blob: ff2595e24e580e74dffc7542f42443654025cccb [file] [log] [blame]
Jamie Foxab30e712023-03-30 17:48:36 +01001/*
2 * Copyright (c) 2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include "dpe_cmd_decode.h"
9
10#include <string.h>
11
12#include "dpe_client.h"
Maulik Patelad2f3db2023-05-17 15:41:36 +010013#include "dpe_context_mngr.h"
Jamie Foxab30e712023-03-30 17:48:36 +010014#include "dpe_impl.h"
15#include "qcbor/qcbor_encode.h"
16#include "qcbor/qcbor_decode.h"
17#include "qcbor/qcbor_spiffy_decode.h"
18
19static dpe_error_t decode_dice_inputs(QCBORDecodeContext *decode_ctx,
20 DiceInputValues *input)
21{
22 QCBORError qcbor_err;
23 UsefulBufC out = { NULL, 0 };
24 int64_t out_int;
25
26 /* The DICE inputs are encoded as a map wrapped into a byte string */
27 QCBORDecode_EnterBstrWrappedFromMapN(decode_ctx,
28 DPE_DERIVE_CHILD_INPUT_DATA,
29 QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL);
30 QCBORDecode_EnterMap(decode_ctx, NULL);
31
32 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_HASH, &out);
33 if (out.len != sizeof(input->code_hash)) {
34 return DPE_INVALID_COMMAND;
35 }
36 memcpy(input->code_hash, out.ptr, out.len);
37
38 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_DESCRIPTOR, &out);
39 input->code_descriptor = out.ptr;
40 input->code_descriptor_size = out.len;
41
42 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_CONFIG_TYPE, &out_int);
43
44 /* Check error state before interpreting config type */
45 qcbor_err = QCBORDecode_GetError(decode_ctx);
46 if (qcbor_err != QCBOR_SUCCESS) {
47 return DPE_INVALID_COMMAND;
48 }
49
50 if (out_int < kDiceConfigTypeInline ||
51 out_int > kDiceConfigTypeDescriptor) {
52 return DPE_INVALID_COMMAND;
53 }
54 input->config_type = (DiceConfigType)out_int;
55
56 /* Only one of config value or config descriptor needs to be provided */
57 if (input->config_type == kDiceConfigTypeInline) {
58 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_VALUE, &out);
59 if (out.len != sizeof(input->config_value)) {
60 return DPE_INVALID_COMMAND;
61 }
62 memcpy(input->config_value, out.ptr, out.len);
63
64 /* Config descriptor is not provided */
65 input->config_descriptor = NULL;
66 input->config_descriptor_size = 0;
67 } else {
68 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_DESCRIPTOR,
69 &out);
70 input->config_descriptor = out.ptr;
71 input->config_descriptor_size = out.len;
72
73 /* Config value is not provided */
74 memset(input->config_value, 0, sizeof(input->config_value));
75 }
76
77 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_HASH, &out);
78 if (out.len != sizeof(input->authority_hash)) {
79 return DPE_INVALID_COMMAND;
80 }
81 memcpy(input->authority_hash, out.ptr, out.len);
82
83 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_DESCRIPTOR,
84 &out);
85 input->authority_descriptor = out.ptr;
86 input->authority_descriptor_size = out.len;
87
88 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_MODE, &out_int);
89 if (out_int < kDiceModeNotInitialized || out_int > kDiceModeMaintenance) {
90 return DPE_INVALID_COMMAND;
91 }
92 input->mode = (DiceMode)out_int;
93
94 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_HIDDEN, &out);
95 if (out.len != sizeof(input->hidden)) {
96 return DPE_INVALID_COMMAND;
97 }
98 memcpy(input->hidden, out.ptr, out.len);
99
100 QCBORDecode_ExitMap(decode_ctx);
101 QCBORDecode_ExitBstrWrapped(decode_ctx);
102
103 return DPE_NO_ERROR;
104}
105
106static dpe_error_t decode_derive_child(QCBORDecodeContext *decode_ctx,
Maulik Patelad2f3db2023-05-17 15:41:36 +0100107 QCBOREncodeContext *encode_ctx,
108 int32_t client_id)
Jamie Foxab30e712023-03-30 17:48:36 +0100109{
110 dpe_error_t dpe_err;
111 QCBORError qcbor_err;
112 UsefulBufC out;
113 int context_handle;
114 bool retain_parent_context;
115 bool allow_child_to_derive;
116 bool create_certificate;
117 DiceInputValues dice_inputs;
118 int new_child_context_handle;
119 int new_parent_context_handle;
120
121 /* Decode DeriveChild command */
122 QCBORDecode_EnterMap(decode_ctx, NULL);
123
124 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DERIVE_CHILD_CONTEXT_HANDLE,
125 &out);
126 if (out.len != sizeof(context_handle)) {
127 return DPE_INVALID_COMMAND;
128 }
129 memcpy(&context_handle, out.ptr, out.len);
130
131 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CHILD_RETAIN_PARENT_CONTEXT,
132 &retain_parent_context);
133
134 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CHILD_ALLOW_CHILD_TO_DERIVE,
135 &allow_child_to_derive);
136
137 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CHILD_CREATE_CERTIFICATE,
138 &create_certificate);
139
140 dpe_err = decode_dice_inputs(decode_ctx, &dice_inputs);
141 if (dpe_err != DPE_NO_ERROR) {
142 return dpe_err;
143 }
144
145 QCBORDecode_ExitMap(decode_ctx);
146
147 /* Exit top level array */
148 QCBORDecode_ExitArray(decode_ctx);
149
150 /* Finish and check for errors before using decoded values */
151 qcbor_err = QCBORDecode_Finish(decode_ctx);
152 if (qcbor_err != QCBOR_SUCCESS) {
153 return DPE_INVALID_COMMAND;
154 }
155
Maulik Patelad2f3db2023-05-17 15:41:36 +0100156 dpe_err = derive_child_request(context_handle, retain_parent_context,
157 allow_child_to_derive, create_certificate,
158 &dice_inputs, client_id,
159 &new_child_context_handle,
160 &new_parent_context_handle);
Jamie Foxab30e712023-03-30 17:48:36 +0100161 if (dpe_err != DPE_NO_ERROR) {
162 return dpe_err;
163 }
164
165 /* Encode response */
166 QCBOREncode_OpenArray(encode_ctx);
167 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
168
169 QCBOREncode_OpenMap(encode_ctx);
170 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CHILD_NEW_CONTEXT_HANDLE,
171 (UsefulBufC){ &new_child_context_handle,
172 sizeof(new_child_context_handle) });
173 QCBOREncode_AddBytesToMapN(encode_ctx,
174 DPE_DERIVE_CHILD_PARENT_CONTEXT_HANDLE,
175 (UsefulBufC){ &new_parent_context_handle,
176 sizeof(new_parent_context_handle) });
177 QCBOREncode_CloseMap(encode_ctx);
178
179 QCBOREncode_CloseArray(encode_ctx);
180
181 return DPE_NO_ERROR;
182}
183
Maulik Patel54d65f72023-06-28 13:04:36 +0100184static dpe_error_t decode_destroy_context(QCBORDecodeContext *decode_ctx,
185 QCBOREncodeContext *encode_ctx)
186{
187 dpe_error_t dpe_err;
188 QCBORError qcbor_err;
189 UsefulBufC out;
190 int context_handle;
191 bool destroy_recursively;
192
193 /* Decode Destroy context command */
194 QCBORDecode_EnterMap(decode_ctx, NULL);
195
196 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DESTROY_CONTEXT_HANDLE,
197 &out);
198 if (out.len != sizeof(context_handle)) {
199 return DPE_INVALID_COMMAND;
200 }
201 memcpy(&context_handle, out.ptr, out.len);
202
203 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DESTROY_CONTEXT_RECURSIVELY,
204 &destroy_recursively);
205
206 QCBORDecode_ExitMap(decode_ctx);
207
208 /* Exit top level array */
209 QCBORDecode_ExitArray(decode_ctx);
210
211 /* Finish and check for errors before using decoded values */
212 qcbor_err = QCBORDecode_Finish(decode_ctx);
213 if (qcbor_err != QCBOR_SUCCESS) {
214 return DPE_INVALID_COMMAND;
215 }
216
217 dpe_err = destroy_context_request(context_handle, destroy_recursively);
218 if (dpe_err != DPE_NO_ERROR) {
219 return dpe_err;
220 }
221
222 /* Encode response */
223 QCBOREncode_OpenArray(encode_ctx);
224 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
225 QCBOREncode_CloseArray(encode_ctx);
226
227 return DPE_NO_ERROR;
228}
229
Jamie Foxab30e712023-03-30 17:48:36 +0100230static dpe_error_t decode_certify_key(QCBORDecodeContext *decode_ctx,
231 QCBOREncodeContext *encode_ctx)
232{
233 QCBORError qcbor_err;
234 UsefulBufC out;
235 dpe_error_t dpe_err;
236 int context_handle;
237 bool retain_context;
238 const uint8_t *public_key;
239 size_t public_key_size;
240 const uint8_t *label;
241 size_t label_size;
242 uint8_t certificate_chain_buf[DPE_CERTIFICATE_CHAIN_MAX_SIZE];
243 size_t certificate_chain_actual_size;
244 uint8_t derived_public_key_buf[DPE_PUBLIC_KEY_MAX_SIZE];
245 size_t derived_public_key_actual_size;
246 int new_context_handle;
247
248 /* Decode CertifyKey command */
249 QCBORDecode_EnterMap(decode_ctx, NULL);
250
251 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_CONTEXT_HANDLE,
252 &out);
253 if (out.len != sizeof(context_handle)) {
254 return DPE_INVALID_COMMAND;
255 }
256 memcpy(&context_handle, out.ptr, out.len);
257
258 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_CERTIFY_KEY_RETAIN_CONTEXT,
259 &retain_context);
260
261 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_PUBLIC_KEY,
262 &out);
263 public_key = out.ptr;
264 public_key_size = out.len;
265
266 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_LABEL, &out);
267 label = out.ptr;
268 label_size = out.len;
269
270 QCBORDecode_ExitMap(decode_ctx);
271
272 /* Exit top level array */
273 QCBORDecode_ExitArray(decode_ctx);
274
275 /* Finish and check for errors before using decoded values */
276 qcbor_err = QCBORDecode_Finish(decode_ctx);
277 if (qcbor_err != QCBOR_SUCCESS) {
278 return DPE_INVALID_COMMAND;
279 }
280
281 dpe_err = dpe_certify_key_impl(context_handle, retain_context, public_key,
282 public_key_size, label, label_size,
283 certificate_chain_buf,
284 sizeof(certificate_chain_buf),
285 &certificate_chain_actual_size,
286 derived_public_key_buf,
287 sizeof(derived_public_key_buf),
288 &derived_public_key_actual_size,
289 &new_context_handle);
290 if (dpe_err != DPE_NO_ERROR) {
291 return dpe_err;
292 }
293
294 /* Encode response */
295 QCBOREncode_OpenArray(encode_ctx);
296 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
297
298 QCBOREncode_OpenMap(encode_ctx);
299
300 /* The certificate chain is already encoded into a CBOR array by the certify
301 * key implementation. Add it as a byte string so that its decoding can be
302 * skipped and the CBOR returned to the caller.
303 */
304 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_CERTIFICATE_CHAIN,
305 (UsefulBufC){ certificate_chain_buf,
306 certificate_chain_actual_size });
307
308 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_DERIVED_PUBLIC_KEY,
309 (UsefulBufC){ derived_public_key_buf,
310 derived_public_key_actual_size });
311 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_NEW_CONTEXT_HANDLE,
312 (UsefulBufC){ &new_context_handle,
313 sizeof(new_context_handle) });
314
315 QCBOREncode_CloseMap(encode_ctx);
316
317 QCBOREncode_CloseArray(encode_ctx);
318
319 return DPE_NO_ERROR;
320}
321
322static void encode_error_only(QCBOREncodeContext *encode_ctx,
323 dpe_error_t dpe_err)
324{
325 QCBOREncode_OpenArray(encode_ctx);
326 QCBOREncode_AddInt64(encode_ctx, dpe_err);
327 QCBOREncode_CloseArray(encode_ctx);
328}
329
330int32_t dpe_command_decode(int32_t client_id,
331 const char *cmd_input, size_t cmd_input_size,
332 char *cmd_output, size_t *cmd_output_size)
333{
334 dpe_error_t dpe_err;
335 QCBORError qcbor_err;
336 QCBORDecodeContext decode_ctx;
337 QCBOREncodeContext encode_ctx;
338 UsefulBufC out;
339 uint64_t command_id;
340
341 QCBORDecode_Init(&decode_ctx, (UsefulBufC){ cmd_input, cmd_input_size },
342 QCBOR_DECODE_MODE_NORMAL);
343 QCBOREncode_Init(&encode_ctx, (UsefulBuf){ cmd_output, *cmd_output_size });
344
345 /* Enter top level array */
346 QCBORDecode_EnterArray(&decode_ctx, NULL);
347
348 /* Get the command ID */
349 QCBORDecode_GetUInt64(&decode_ctx, &command_id);
350
351 /* Check for errors before interpreting the decoded command ID */
352 qcbor_err = QCBORDecode_GetError(&decode_ctx);
353
354 if (qcbor_err == QCBOR_SUCCESS) {
355 switch (command_id) {
356 case DPE_DERIVE_CHILD:
Maulik Patelad2f3db2023-05-17 15:41:36 +0100357 dpe_err = decode_derive_child(&decode_ctx, &encode_ctx, client_id);
Jamie Foxab30e712023-03-30 17:48:36 +0100358 break;
359 case DPE_CERTIFY_KEY:
360 dpe_err = decode_certify_key(&decode_ctx, &encode_ctx);
361 break;
Maulik Patel54d65f72023-06-28 13:04:36 +0100362 case DPE_DESTROY_CONTEXT:
363 dpe_err = decode_destroy_context(&decode_ctx, &encode_ctx);
364 break;
Jamie Foxab30e712023-03-30 17:48:36 +0100365 default:
366 dpe_err = DPE_INVALID_COMMAND;
367 break;
368 }
369 } else {
370 dpe_err = DPE_INVALID_COMMAND;
371 }
372
373 /* If an unhandled DPE error was returned, then encode it into a response */
374 if (dpe_err != DPE_NO_ERROR) {
375 encode_error_only(&encode_ctx, dpe_err);
376 }
377
378 qcbor_err = QCBOREncode_Finish(&encode_ctx, &out);
379 if (qcbor_err != QCBOR_SUCCESS) {
380 return -1;
381 }
382
383 *cmd_output_size = out.len;
384
385 return 0;
386}