blob: 9fb50bbf8977785e8d8e1fb43a4fa2a154103562 [file] [log] [blame]
Jamie Foxab30e712023-03-30 17:48:36 +01001/*
Tamas Band0983e92024-01-25 16:32:51 +01002 * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
Jamie Foxab30e712023-03-30 17:48:36 +01003 *
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"
Maulik Patele6adc112023-08-18 14:21:51 +010014#include "dpe_crypto_config.h"
Jamie Foxab30e712023-03-30 17:48:36 +010015#include "qcbor/qcbor_encode.h"
16#include "qcbor/qcbor_decode.h"
17#include "qcbor/qcbor_spiffy_decode.h"
18
Maulik Patel8a969fd2024-03-01 14:43:03 +000019#define COUNT_ARGS(arg) (arg)++
20
21#define CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx) \
22 qcbor_err = QCBORDecode_GetAndResetError(decode_ctx); \
23 if (qcbor_err == QCBOR_SUCCESS) { \
24 /* Valid label found - optional argument present */ \
25 COUNT_ARGS(num_of_valid_arguments); \
26 } else if (qcbor_err != QCBOR_ERR_LABEL_NOT_FOUND) { \
Maulik Patel6f892252024-03-05 16:39:38 +000027 return DPE_INVALID_ARGUMENT; \
Maulik Patel8a969fd2024-03-01 14:43:03 +000028 } else { \
29 /* We have NOT found the optional argument, do not update the count */ \
Maulik Patelfbe9bff2024-02-09 14:05:25 +000030 }
31
Tamas Band0983e92024-01-25 16:32:51 +010032/*
33 * The goal to reuse the cmd_buf allocated in dpe_req_mngr.c to create the
34 * big objects (certificate, certificate_chain) in place rather then allocate
35 * a separate buffer on the stack and later copy them to cmd_buf.
36 *
37 * The temporary buffer is allocated from the end of the cmd_buf. When the
38 * reply is encoded then the content of the temp buf is moved to its final
39 * place in the cmd_buf.
40 *
41 * Overlapping copy is not an issue because QCBOR relies on memmove under the
42 * hood which handles this scenario.
43 *
44 * Note:
45 * Make sure that the beginning of the encoded reply does not overwrite the
46 * data in the temp buf. That is why the temp buff is allocated at the end of
47 * cmd_buf.
48 */
49#define REUSE_CMD_BUF(size) (uint8_t *)encode_ctx->OutBuf.UB.ptr + \
50 encode_ctx->OutBuf.UB.len - \
51 (size)
52
Jamie Foxab30e712023-03-30 17:48:36 +010053static dpe_error_t decode_dice_inputs(QCBORDecodeContext *decode_ctx,
54 DiceInputValues *input)
55{
56 QCBORError qcbor_err;
57 UsefulBufC out = { NULL, 0 };
58 int64_t out_int;
59
60 /* The DICE inputs are encoded as a map wrapped into a byte string */
61 QCBORDecode_EnterBstrWrappedFromMapN(decode_ctx,
Maulik Patela81605b2023-10-24 12:17:03 +010062 DPE_DERIVE_CONTEXT_INPUT_DATA,
Jamie Foxab30e712023-03-30 17:48:36 +010063 QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL);
64 QCBORDecode_EnterMap(decode_ctx, NULL);
65
66 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_HASH, &out);
67 if (out.len != sizeof(input->code_hash)) {
Maulik Patel6f892252024-03-05 16:39:38 +000068 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +010069 }
70 memcpy(input->code_hash, out.ptr, out.len);
71
72 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_DESCRIPTOR, &out);
73 input->code_descriptor = out.ptr;
74 input->code_descriptor_size = out.len;
75
76 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_CONFIG_TYPE, &out_int);
77
78 /* Check error state before interpreting config type */
79 qcbor_err = QCBORDecode_GetError(decode_ctx);
80 if (qcbor_err != QCBOR_SUCCESS) {
Maulik Patel6f892252024-03-05 16:39:38 +000081 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +010082 }
83
84 if (out_int < kDiceConfigTypeInline ||
85 out_int > kDiceConfigTypeDescriptor) {
Maulik Patel6f892252024-03-05 16:39:38 +000086 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +010087 }
88 input->config_type = (DiceConfigType)out_int;
89
90 /* Only one of config value or config descriptor needs to be provided */
91 if (input->config_type == kDiceConfigTypeInline) {
92 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_VALUE, &out);
93 if (out.len != sizeof(input->config_value)) {
Maulik Patel6f892252024-03-05 16:39:38 +000094 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +010095 }
96 memcpy(input->config_value, out.ptr, out.len);
97
98 /* Config descriptor is not provided */
99 input->config_descriptor = NULL;
100 input->config_descriptor_size = 0;
101 } else {
102 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_DESCRIPTOR,
103 &out);
104 input->config_descriptor = out.ptr;
105 input->config_descriptor_size = out.len;
106
107 /* Config value is not provided */
108 memset(input->config_value, 0, sizeof(input->config_value));
109 }
110
111 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_HASH, &out);
112 if (out.len != sizeof(input->authority_hash)) {
Maulik Patel6f892252024-03-05 16:39:38 +0000113 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100114 }
115 memcpy(input->authority_hash, out.ptr, out.len);
116
117 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_DESCRIPTOR,
118 &out);
119 input->authority_descriptor = out.ptr;
120 input->authority_descriptor_size = out.len;
121
122 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_MODE, &out_int);
123 if (out_int < kDiceModeNotInitialized || out_int > kDiceModeMaintenance) {
Maulik Patel6f892252024-03-05 16:39:38 +0000124 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100125 }
126 input->mode = (DiceMode)out_int;
127
128 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_HIDDEN, &out);
129 if (out.len != sizeof(input->hidden)) {
Maulik Patel6f892252024-03-05 16:39:38 +0000130 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100131 }
132 memcpy(input->hidden, out.ptr, out.len);
133
134 QCBORDecode_ExitMap(decode_ctx);
135 QCBORDecode_ExitBstrWrapped(decode_ctx);
136
Maulik Pateld936d742024-01-08 14:16:46 +0000137 qcbor_err = QCBORDecode_GetError(decode_ctx);
138 if (qcbor_err != QCBOR_SUCCESS) {
Maulik Patel6f892252024-03-05 16:39:38 +0000139 return DPE_INVALID_ARGUMENT;
Maulik Pateld936d742024-01-08 14:16:46 +0000140 }
141
Jamie Foxab30e712023-03-30 17:48:36 +0100142 return DPE_NO_ERROR;
143}
144
Maulik Patela81605b2023-10-24 12:17:03 +0100145static dpe_error_t decode_derive_context(QCBORDecodeContext *decode_ctx,
146 QCBOREncodeContext *encode_ctx,
147 int32_t client_id)
Jamie Foxab30e712023-03-30 17:48:36 +0100148{
149 dpe_error_t dpe_err;
150 QCBORError qcbor_err;
151 UsefulBufC out;
152 int context_handle;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000153 int32_t target_locality;
Jamie Foxab30e712023-03-30 17:48:36 +0100154 bool retain_parent_context;
Maulik Patela81605b2023-10-24 12:17:03 +0100155 bool allow_new_context_to_derive;
Jamie Foxab30e712023-03-30 17:48:36 +0100156 bool create_certificate;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000157 bool return_certificate;
158 bool allow_new_context_to_export;
159 bool export_cdi;
Jamie Foxab30e712023-03-30 17:48:36 +0100160 DiceInputValues dice_inputs;
Maulik Patela81605b2023-10-24 12:17:03 +0100161 int new_context_handle;
Jamie Foxab30e712023-03-30 17:48:36 +0100162 int new_parent_context_handle;
Tamas Band0983e92024-01-25 16:32:51 +0100163 uint8_t *new_certificate_buf = REUSE_CMD_BUF(DICE_CERT_SIZE);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000164 uint8_t exported_cdi_buf[DICE_MAX_ENCODED_CDI_SIZE];
Maulik Patelcb14cde2024-01-23 12:39:53 +0000165 uint32_t cert_id;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000166 size_t new_certificate_actual_size = 0;
167 size_t exported_cdi_actual_size = 0;
Maulik Patel8a969fd2024-03-01 14:43:03 +0000168 QCBORItem item;
169 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
Jamie Foxab30e712023-03-30 17:48:36 +0100170
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000171 /* Initialise optional parameters with their default value in case
172 * they are not encoded in the input command
173 */
174 cert_id = DPE_CERT_ID_INVALID;
175 retain_parent_context = false;
176 allow_new_context_to_derive = true;
177 create_certificate = true;
178 return_certificate = false;
179 allow_new_context_to_export = false;
180 export_cdi = false;
181
Maulik Patela81605b2023-10-24 12:17:03 +0100182 /* Decode DeriveContext command */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000183 QCBORDecode_EnterMap(decode_ctx, &item);
184 qcbor_err = QCBORDecode_GetError(decode_ctx);
185 if ((qcbor_err != QCBOR_SUCCESS) ||
186 (item.uDataType != QCBOR_TYPE_MAP)) {
187 /* We expect a map of Derive Context command arguments here */
188 return DPE_INVALID_COMMAND;
189 }
190 /* Save the number of items found in the map */
191 num_of_input_arguments = item.val.uCount;
Jamie Foxab30e712023-03-30 17:48:36 +0100192
Maulik Patela81605b2023-10-24 12:17:03 +0100193 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DERIVE_CONTEXT_CONTEXT_HANDLE,
Jamie Foxab30e712023-03-30 17:48:36 +0100194 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000195 qcbor_err = QCBORDecode_GetError(decode_ctx);
Maulik Patelcb14cde2024-01-23 12:39:53 +0000196 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000197 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100198 }
199 memcpy(&context_handle, out.ptr, out.len);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000200 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100201
Maulik Patelcb14cde2024-01-23 12:39:53 +0000202 QCBORDecode_GetUInt64InMapN(decode_ctx, DPE_DERIVE_CONTEXT_CERT_ID, &cert_id);
203 /* Check if cert_id was encoded in the received command buffer */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000204 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patelcb14cde2024-01-23 12:39:53 +0000205
Maulik Patela81605b2023-10-24 12:17:03 +0100206 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT,
Jamie Foxab30e712023-03-30 17:48:36 +0100207 &retain_parent_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000208 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100209
Maulik Patela81605b2023-10-24 12:17:03 +0100210 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE,
211 &allow_new_context_to_derive);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000212 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100213
Maulik Patela81605b2023-10-24 12:17:03 +0100214 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE,
Jamie Foxab30e712023-03-30 17:48:36 +0100215 &create_certificate);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000216 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100217
218 dpe_err = decode_dice_inputs(decode_ctx, &dice_inputs);
219 if (dpe_err != DPE_NO_ERROR) {
220 return dpe_err;
221 }
Maulik Patel8a969fd2024-03-01 14:43:03 +0000222 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100223
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000224 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DERIVE_CONTEXT_TARGET_LOCALITY,
225 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000226 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
227 if (qcbor_err == QCBOR_SUCCESS) {
228 /* Valid argument was found */
229 if (out.len != sizeof(target_locality)) {
230 return DPE_INVALID_ARGUMENT;
231 }
232 memcpy(&target_locality, out.ptr, out.len);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000233 }
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000234
235 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE,
236 &return_certificate);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000237 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000238
239 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT,
240 &allow_new_context_to_export);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000241 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000242
243 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_EXPORT_CDI,
244 &export_cdi);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000245 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000246
Jamie Foxab30e712023-03-30 17:48:36 +0100247 QCBORDecode_ExitMap(decode_ctx);
248
249 /* Exit top level array */
250 QCBORDecode_ExitArray(decode_ctx);
251
252 /* Finish and check for errors before using decoded values */
253 qcbor_err = QCBORDecode_Finish(decode_ctx);
254 if (qcbor_err != QCBOR_SUCCESS) {
255 return DPE_INVALID_COMMAND;
256 }
257
Maulik Patel8a969fd2024-03-01 14:43:03 +0000258 if (num_of_input_arguments > num_of_valid_arguments) {
259 /* Extra unsupported arguments encoded in command map */
260 return DPE_INVALID_ARGUMENT;
261 }
262
Maulik Patelcb14cde2024-01-23 12:39:53 +0000263 dpe_err = derive_context_request(context_handle, cert_id, retain_parent_context,
Maulik Patela81605b2023-10-24 12:17:03 +0100264 allow_new_context_to_derive, create_certificate,
265 &dice_inputs, client_id,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000266 target_locality,
267 return_certificate,
268 allow_new_context_to_export,
269 export_cdi,
Maulik Patela81605b2023-10-24 12:17:03 +0100270 &new_context_handle,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000271 &new_parent_context_handle,
272 new_certificate_buf,
Tamas Band0983e92024-01-25 16:32:51 +0100273 DICE_CERT_SIZE,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000274 &new_certificate_actual_size,
275 exported_cdi_buf,
276 sizeof(exported_cdi_buf),
277 &exported_cdi_actual_size);
Jamie Foxab30e712023-03-30 17:48:36 +0100278 if (dpe_err != DPE_NO_ERROR) {
279 return dpe_err;
280 }
281
282 /* Encode response */
283 QCBOREncode_OpenArray(encode_ctx);
284 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
285
286 QCBOREncode_OpenMap(encode_ctx);
Maulik Patela81605b2023-10-24 12:17:03 +0100287 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE,
288 (UsefulBufC){ &new_context_handle,
289 sizeof(new_context_handle) });
Jamie Foxab30e712023-03-30 17:48:36 +0100290 QCBOREncode_AddBytesToMapN(encode_ctx,
Maulik Patela81605b2023-10-24 12:17:03 +0100291 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE,
Jamie Foxab30e712023-03-30 17:48:36 +0100292 (UsefulBufC){ &new_parent_context_handle,
293 sizeof(new_parent_context_handle) });
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000294
295 /* The certificate is already encoded into a CBOR array by the function
296 * add_encoded_layer_certificate. Add it as a byte string so that its
297 * decoding can be skipped and the CBOR returned to the caller.
298 */
299 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_NEW_CERTIFICATE,
300 (UsefulBufC){ new_certificate_buf,
301 new_certificate_actual_size });
302
303 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_EXPORTED_CDI,
304 (UsefulBufC){ exported_cdi_buf,
305 exported_cdi_actual_size });
306
Jamie Foxab30e712023-03-30 17:48:36 +0100307 QCBOREncode_CloseMap(encode_ctx);
308
309 QCBOREncode_CloseArray(encode_ctx);
310
311 return DPE_NO_ERROR;
312}
313
Maulik Patel54d65f72023-06-28 13:04:36 +0100314static dpe_error_t decode_destroy_context(QCBORDecodeContext *decode_ctx,
315 QCBOREncodeContext *encode_ctx)
316{
317 dpe_error_t dpe_err;
318 QCBORError qcbor_err;
319 UsefulBufC out;
320 int context_handle;
321 bool destroy_recursively;
Maulik Pateldc446492024-03-18 14:52:15 +0000322 QCBORItem item;
323 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
324
325 /* Initialise optional parameters with their default value in case
326 * they are not encoded in the input command
327 */
328 destroy_recursively = false;
Maulik Patel54d65f72023-06-28 13:04:36 +0100329
330 /* Decode Destroy context command */
Maulik Pateldc446492024-03-18 14:52:15 +0000331 QCBORDecode_EnterMap(decode_ctx, &item);
332 qcbor_err = QCBORDecode_GetError(decode_ctx);
333 if ((qcbor_err != QCBOR_SUCCESS) ||
334 (item.uDataType != QCBOR_TYPE_MAP)) {
335 /* We expect a map of Derive Context command arguments here */
336 return DPE_INVALID_COMMAND;
337 }
338 /* Save the number of items found in the map */
339 num_of_input_arguments = item.val.uCount;
Maulik Patel54d65f72023-06-28 13:04:36 +0100340
341 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DESTROY_CONTEXT_HANDLE,
342 &out);
Maulik Pateldc446492024-03-18 14:52:15 +0000343 qcbor_err = QCBORDecode_GetError(decode_ctx);
344 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000345 return DPE_INVALID_ARGUMENT;
Maulik Patel54d65f72023-06-28 13:04:36 +0100346 }
347 memcpy(&context_handle, out.ptr, out.len);
Maulik Pateldc446492024-03-18 14:52:15 +0000348 COUNT_ARGS(num_of_valid_arguments);
Maulik Patel54d65f72023-06-28 13:04:36 +0100349
350 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DESTROY_CONTEXT_RECURSIVELY,
351 &destroy_recursively);
Maulik Pateldc446492024-03-18 14:52:15 +0000352 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel54d65f72023-06-28 13:04:36 +0100353
354 QCBORDecode_ExitMap(decode_ctx);
355
356 /* Exit top level array */
357 QCBORDecode_ExitArray(decode_ctx);
358
359 /* Finish and check for errors before using decoded values */
360 qcbor_err = QCBORDecode_Finish(decode_ctx);
361 if (qcbor_err != QCBOR_SUCCESS) {
362 return DPE_INVALID_COMMAND;
363 }
364
Maulik Pateldc446492024-03-18 14:52:15 +0000365 if (num_of_input_arguments > num_of_valid_arguments) {
366 /* Extra unsupported arguments encoded in command map */
367 return DPE_INVALID_ARGUMENT;
368 }
369
Maulik Patel54d65f72023-06-28 13:04:36 +0100370 dpe_err = destroy_context_request(context_handle, destroy_recursively);
371 if (dpe_err != DPE_NO_ERROR) {
372 return dpe_err;
373 }
374
375 /* Encode response */
376 QCBOREncode_OpenArray(encode_ctx);
377 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
378 QCBOREncode_CloseArray(encode_ctx);
379
380 return DPE_NO_ERROR;
381}
382
Jamie Foxab30e712023-03-30 17:48:36 +0100383static dpe_error_t decode_certify_key(QCBORDecodeContext *decode_ctx,
384 QCBOREncodeContext *encode_ctx)
385{
386 QCBORError qcbor_err;
387 UsefulBufC out;
388 dpe_error_t dpe_err;
389 int context_handle;
390 bool retain_context;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000391 const uint8_t *public_key = NULL;
Jamie Foxab30e712023-03-30 17:48:36 +0100392 size_t public_key_size;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000393 const uint8_t *label = NULL;
Jamie Foxab30e712023-03-30 17:48:36 +0100394 size_t label_size;
Tamas Band0983e92024-01-25 16:32:51 +0100395 uint8_t *certificate_buf = REUSE_CMD_BUF(DICE_CERT_SIZE);
Maulik Patelcbded682023-12-07 11:50:16 +0000396 size_t certificate_actual_size;
Maulik Patele6adc112023-08-18 14:21:51 +0100397 uint8_t derived_public_key_buf[DPE_ATTEST_PUB_KEY_SIZE];
Jamie Foxab30e712023-03-30 17:48:36 +0100398 size_t derived_public_key_actual_size;
399 int new_context_handle;
Maulik Patel8a969fd2024-03-01 14:43:03 +0000400 QCBORItem item;
401 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
Jamie Foxab30e712023-03-30 17:48:36 +0100402
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000403 /* Initialise optional parameters with their default value in case
404 * they are not encoded in the input command
405 */
406 retain_context = false;
407 public_key_size = 0;
408 label_size = 0;
409
Jamie Foxab30e712023-03-30 17:48:36 +0100410 /* Decode CertifyKey command */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000411 QCBORDecode_EnterMap(decode_ctx, &item);
412 qcbor_err = QCBORDecode_GetError(decode_ctx);
413 if ((qcbor_err != QCBOR_SUCCESS) ||
414 (item.uDataType != QCBOR_TYPE_MAP)) {
415 /* We expect a map of Certify Key command arguments here */
416 return DPE_INVALID_COMMAND;
417 }
418 /* Save the number of items found in the map */
419 num_of_input_arguments = item.val.uCount;
Jamie Foxab30e712023-03-30 17:48:36 +0100420
421 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_CONTEXT_HANDLE,
422 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000423 qcbor_err = QCBORDecode_GetError(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000424 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000425 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100426 }
427 memcpy(&context_handle, out.ptr, out.len);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000428 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100429
430 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_CERTIFY_KEY_RETAIN_CONTEXT,
431 &retain_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000432 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100433
434 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_PUBLIC_KEY,
435 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000436 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000437 if (qcbor_err == QCBOR_SUCCESS) {
Maulik Patel8a969fd2024-03-01 14:43:03 +0000438 /* Valid argument was found */
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000439 public_key = out.ptr;
440 public_key_size = out.len;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000441 }
Jamie Foxab30e712023-03-30 17:48:36 +0100442
443 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_LABEL, &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000444 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000445 if (qcbor_err == QCBOR_SUCCESS) {
Maulik Patel8a969fd2024-03-01 14:43:03 +0000446 /* Valid argument was found */
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000447 label = out.ptr;
448 label_size = out.len;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000449 }
Jamie Foxab30e712023-03-30 17:48:36 +0100450
451 QCBORDecode_ExitMap(decode_ctx);
452
453 /* Exit top level array */
454 QCBORDecode_ExitArray(decode_ctx);
455
456 /* Finish and check for errors before using decoded values */
457 qcbor_err = QCBORDecode_Finish(decode_ctx);
458 if (qcbor_err != QCBOR_SUCCESS) {
459 return DPE_INVALID_COMMAND;
460 }
461
Maulik Patel8a969fd2024-03-01 14:43:03 +0000462 if (num_of_input_arguments > num_of_valid_arguments) {
463 /* Extra unsupported arguments encoded in command map */
464 return DPE_INVALID_ARGUMENT;
465 }
466
Maulik Patele6adc112023-08-18 14:21:51 +0100467 dpe_err = certify_key_request(context_handle, retain_context, public_key,
468 public_key_size, label, label_size,
Maulik Patelcbded682023-12-07 11:50:16 +0000469 certificate_buf,
Tamas Band0983e92024-01-25 16:32:51 +0100470 DICE_CERT_SIZE,
Maulik Patelcbded682023-12-07 11:50:16 +0000471 &certificate_actual_size,
Maulik Patele6adc112023-08-18 14:21:51 +0100472 derived_public_key_buf,
473 sizeof(derived_public_key_buf),
474 &derived_public_key_actual_size,
475 &new_context_handle);
Jamie Foxab30e712023-03-30 17:48:36 +0100476 if (dpe_err != DPE_NO_ERROR) {
477 return dpe_err;
478 }
479
480 /* Encode response */
481 QCBOREncode_OpenArray(encode_ctx);
482 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
483
484 QCBOREncode_OpenMap(encode_ctx);
485
486 /* The certificate chain is already encoded into a CBOR array by the certify
487 * key implementation. Add it as a byte string so that its decoding can be
488 * skipped and the CBOR returned to the caller.
489 */
Maulik Patelcbded682023-12-07 11:50:16 +0000490 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_CERTIFICATE,
491 (UsefulBufC){ certificate_buf,
492 certificate_actual_size });
Jamie Foxab30e712023-03-30 17:48:36 +0100493
494 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_DERIVED_PUBLIC_KEY,
495 (UsefulBufC){ derived_public_key_buf,
496 derived_public_key_actual_size });
497 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_NEW_CONTEXT_HANDLE,
498 (UsefulBufC){ &new_context_handle,
499 sizeof(new_context_handle) });
500
501 QCBOREncode_CloseMap(encode_ctx);
502
503 QCBOREncode_CloseArray(encode_ctx);
504
505 return DPE_NO_ERROR;
506}
507
Maulik Patel83a6b592023-12-05 15:20:30 +0000508static dpe_error_t decode_get_certificate_chain(QCBORDecodeContext *decode_ctx,
509 QCBOREncodeContext *encode_ctx)
510{
511 QCBORError qcbor_err;
512 UsefulBufC out;
513 dpe_error_t dpe_err;
514 int context_handle;
515 bool retain_context;
516 bool clear_from_context;
Tamas Band0983e92024-01-25 16:32:51 +0100517 uint8_t *certificate_chain_buf = REUSE_CMD_BUF(DICE_CERT_CHAIN_SIZE);
Maulik Patel83a6b592023-12-05 15:20:30 +0000518 size_t certificate_chain_actual_size;
519 int new_context_handle;
Maulik Patel8a969fd2024-03-01 14:43:03 +0000520 QCBORItem item;
521 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
Maulik Patel83a6b592023-12-05 15:20:30 +0000522
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000523 /* Initialise optional parameters with their default value in case
524 * they are not encoded in the input command
525 */
526 retain_context = false;
527 clear_from_context = false;
528
Maulik Patel83a6b592023-12-05 15:20:30 +0000529 /* Decode GetCertificateChain command */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000530 QCBORDecode_EnterMap(decode_ctx, &item);
531 qcbor_err = QCBORDecode_GetError(decode_ctx);
532 if ((qcbor_err != QCBOR_SUCCESS) ||
533 (item.uDataType != QCBOR_TYPE_MAP)) {
534 /* We expect a map of Get Certificate Chain command arguments here */
535 return DPE_INVALID_COMMAND;
536 }
537 /* Save the number of items found in the map */
538 num_of_input_arguments = item.val.uCount;
Maulik Patel83a6b592023-12-05 15:20:30 +0000539
540 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_CONTEXT_HANDLE,
541 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000542 qcbor_err = QCBORDecode_GetError(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000543 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000544 return DPE_INVALID_ARGUMENT;
Maulik Patel83a6b592023-12-05 15:20:30 +0000545 }
546 memcpy(&context_handle, out.ptr, out.len);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000547 COUNT_ARGS(num_of_valid_arguments);
Maulik Patel83a6b592023-12-05 15:20:30 +0000548
549 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_RETAIN_CONTEXT,
550 &retain_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000551 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel83a6b592023-12-05 15:20:30 +0000552
553 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_CLEAR_FROM_CONTEXT,
554 &clear_from_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000555 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel83a6b592023-12-05 15:20:30 +0000556
557 QCBORDecode_ExitMap(decode_ctx);
558
559 /* Exit top level array */
560 QCBORDecode_ExitArray(decode_ctx);
561
562 /* Finish and check for errors before using decoded values */
563 qcbor_err = QCBORDecode_Finish(decode_ctx);
564 if (qcbor_err != QCBOR_SUCCESS) {
565 return DPE_INVALID_COMMAND;
566 }
567
Maulik Patel8a969fd2024-03-01 14:43:03 +0000568 if (num_of_input_arguments > num_of_valid_arguments) {
569 /* Extra unsupported arguments encoded in command map */
570 return DPE_INVALID_ARGUMENT;
571 }
572
Maulik Patel83a6b592023-12-05 15:20:30 +0000573 dpe_err = get_certificate_chain_request(context_handle,
574 retain_context,
575 clear_from_context,
576 certificate_chain_buf,
Tamas Band0983e92024-01-25 16:32:51 +0100577 DICE_CERT_CHAIN_SIZE,
Maulik Patel83a6b592023-12-05 15:20:30 +0000578 &certificate_chain_actual_size,
579 &new_context_handle);
580 if (dpe_err != DPE_NO_ERROR) {
581 return dpe_err;
582 }
583
584 /* Encode response */
585 QCBOREncode_OpenArray(encode_ctx);
586 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
587
588 QCBOREncode_OpenMap(encode_ctx);
589
590 /* The certificate chain is already encoded into a CBOR array by the get certificate
591 * chain implementation. Add it as a byte string so that its decoding can be
592 * skipped and the CBOR returned to the caller.
593 */
594 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_GET_CERTIFICATE_CHAIN_CERTIFICATE_CHAIN,
595 (UsefulBufC){ certificate_chain_buf,
596 certificate_chain_actual_size });
597
598 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_GET_CERTIFICATE_CHAIN_NEW_CONTEXT_HANDLE,
599 (UsefulBufC){ &new_context_handle,
600 sizeof(new_context_handle) });
601
602 QCBOREncode_CloseMap(encode_ctx);
603
604 QCBOREncode_CloseArray(encode_ctx);
605
606 return DPE_NO_ERROR;
607}
608
Jamie Foxab30e712023-03-30 17:48:36 +0100609static void encode_error_only(QCBOREncodeContext *encode_ctx,
610 dpe_error_t dpe_err)
611{
612 QCBOREncode_OpenArray(encode_ctx);
613 QCBOREncode_AddInt64(encode_ctx, dpe_err);
614 QCBOREncode_CloseArray(encode_ctx);
615}
616
617int32_t dpe_command_decode(int32_t client_id,
618 const char *cmd_input, size_t cmd_input_size,
619 char *cmd_output, size_t *cmd_output_size)
620{
621 dpe_error_t dpe_err;
622 QCBORError qcbor_err;
623 QCBORDecodeContext decode_ctx;
624 QCBOREncodeContext encode_ctx;
625 UsefulBufC out;
626 uint64_t command_id;
627
628 QCBORDecode_Init(&decode_ctx, (UsefulBufC){ cmd_input, cmd_input_size },
629 QCBOR_DECODE_MODE_NORMAL);
630 QCBOREncode_Init(&encode_ctx, (UsefulBuf){ cmd_output, *cmd_output_size });
631
632 /* Enter top level array */
633 QCBORDecode_EnterArray(&decode_ctx, NULL);
634
635 /* Get the command ID */
636 QCBORDecode_GetUInt64(&decode_ctx, &command_id);
637
638 /* Check for errors before interpreting the decoded command ID */
639 qcbor_err = QCBORDecode_GetError(&decode_ctx);
640
641 if (qcbor_err == QCBOR_SUCCESS) {
642 switch (command_id) {
Maulik Patela81605b2023-10-24 12:17:03 +0100643 case DPE_DERIVE_CONTEXT:
644 dpe_err = decode_derive_context(&decode_ctx, &encode_ctx, client_id);
Jamie Foxab30e712023-03-30 17:48:36 +0100645 break;
646 case DPE_CERTIFY_KEY:
647 dpe_err = decode_certify_key(&decode_ctx, &encode_ctx);
648 break;
Maulik Patel83a6b592023-12-05 15:20:30 +0000649 case DPE_GET_CERTIFICATE_CHAIN:
650 dpe_err = decode_get_certificate_chain(&decode_ctx, &encode_ctx);
651 break;
Maulik Patel54d65f72023-06-28 13:04:36 +0100652 case DPE_DESTROY_CONTEXT:
653 dpe_err = decode_destroy_context(&decode_ctx, &encode_ctx);
654 break;
Jamie Foxab30e712023-03-30 17:48:36 +0100655 default:
656 dpe_err = DPE_INVALID_COMMAND;
657 break;
658 }
659 } else {
660 dpe_err = DPE_INVALID_COMMAND;
661 }
662
663 /* If an unhandled DPE error was returned, then encode it into a response */
664 if (dpe_err != DPE_NO_ERROR) {
665 encode_error_only(&encode_ctx, dpe_err);
666 }
667
668 qcbor_err = QCBOREncode_Finish(&encode_ctx, &out);
669 if (qcbor_err != QCBOR_SUCCESS) {
670 return -1;
671 }
672
673 *cmd_output_size = out.len;
674
675 return 0;
676}