blob: ad5f8114b432e0ffad9c12b5003ae2ba9df2a83a [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
Tamas Banfcc06e32024-03-25 13:47:33 +010010#include <assert.h>
Jamie Foxab30e712023-03-30 17:48:36 +010011#include <string.h>
12
13#include "dpe_client.h"
Maulik Patelad2f3db2023-05-17 15:41:36 +010014#include "dpe_context_mngr.h"
Maulik Patele6adc112023-08-18 14:21:51 +010015#include "dpe_crypto_config.h"
Jamie Foxab30e712023-03-30 17:48:36 +010016#include "qcbor/qcbor_encode.h"
17#include "qcbor/qcbor_decode.h"
18#include "qcbor/qcbor_spiffy_decode.h"
19
Tamas Banfcc06e32024-03-25 13:47:33 +010020/*
21 * The goal to reuse the cmd_buf allocated in dpe_req_mngr.c to create the
22 * big objects (certificate, certificate_chain) in place rather then allocate
23 * a separate buffer on the stack and later copy them to cmd_buf.
24 *
25 * The temporary buffer is allocated from the beginning + some offset of the
26 * cmd_buf. The offset is a placeholder for the first few bytes of the
27 * response. The size of temp buf is till the end of the cmd_buf. Usually not
28 * the entire size is necessary it is just convenient to allocate as much. When
29 * the response is encoded then the content of the temp buf is moved to its
30 * final location within the cmd_buf.
31 *
32 * Overlapping copy is not an issue because QCBOR relies on memmove under the
33 * hood which handles this scenario.
34 *
35 * Note:
36 * Only a single temp buffer can be allocated with this trick per DPE command.
37 */
38#define DPE_RESPONSE_HEADER_SIZE 20
39#define ALLOC_TEMP_BUF (uint8_t *)encode_ctx->OutBuf.UB.ptr + \
40 DPE_RESPONSE_HEADER_SIZE
41
42#define SIZEOF_TEMP_BUF encode_ctx->OutBuf.UB.len - \
43 DPE_RESPONSE_HEADER_SIZE
44
45/* Decreasing the placeholder size a bit because UsefulOutBuf_GetEndPosition()
46 * cannot determine the exact number of bytes to encode array and map objects
47 * until they are closed. Allocating 1 byte for both allows encoding up to
48 * 23 elements per type (map or array) in a single byte, so at the end it
49 * consumes 2 bytes. It is very unlikely to have more elements in a map or array
50 * than 23 in a DPE response.
51 */
52#define CHECK_OVERFLOW_TO_TEMP_BUF assert((DPE_RESPONSE_HEADER_SIZE - 2) > \
53 UsefulOutBuf_GetEndPosition(&encode_ctx->OutBuf))
54
Maulik Patel8a969fd2024-03-01 14:43:03 +000055#define COUNT_ARGS(arg) (arg)++
56
57#define CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx) \
58 qcbor_err = QCBORDecode_GetAndResetError(decode_ctx); \
59 if (qcbor_err == QCBOR_SUCCESS) { \
60 /* Valid label found - optional argument present */ \
61 COUNT_ARGS(num_of_valid_arguments); \
62 } else if (qcbor_err != QCBOR_ERR_LABEL_NOT_FOUND) { \
Maulik Patel6f892252024-03-05 16:39:38 +000063 return DPE_INVALID_ARGUMENT; \
Maulik Patel8a969fd2024-03-01 14:43:03 +000064 } else { \
65 /* We have NOT found the optional argument, do not update the count */ \
Maulik Patelfbe9bff2024-02-09 14:05:25 +000066 }
67
Jamie Foxab30e712023-03-30 17:48:36 +010068static dpe_error_t decode_dice_inputs(QCBORDecodeContext *decode_ctx,
69 DiceInputValues *input)
70{
71 QCBORError qcbor_err;
72 UsefulBufC out = { NULL, 0 };
73 int64_t out_int;
74
75 /* The DICE inputs are encoded as a map wrapped into a byte string */
76 QCBORDecode_EnterBstrWrappedFromMapN(decode_ctx,
Maulik Patela81605b2023-10-24 12:17:03 +010077 DPE_DERIVE_CONTEXT_INPUT_DATA,
Jamie Foxab30e712023-03-30 17:48:36 +010078 QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL);
79 QCBORDecode_EnterMap(decode_ctx, NULL);
80
81 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_HASH, &out);
82 if (out.len != sizeof(input->code_hash)) {
Maulik Patel6f892252024-03-05 16:39:38 +000083 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +010084 }
85 memcpy(input->code_hash, out.ptr, out.len);
86
87 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_DESCRIPTOR, &out);
88 input->code_descriptor = out.ptr;
89 input->code_descriptor_size = out.len;
90
91 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_CONFIG_TYPE, &out_int);
92
93 /* Check error state before interpreting config type */
94 qcbor_err = QCBORDecode_GetError(decode_ctx);
95 if (qcbor_err != QCBOR_SUCCESS) {
Maulik Patel6f892252024-03-05 16:39:38 +000096 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +010097 }
98
99 if (out_int < kDiceConfigTypeInline ||
100 out_int > kDiceConfigTypeDescriptor) {
Maulik Patel6f892252024-03-05 16:39:38 +0000101 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100102 }
103 input->config_type = (DiceConfigType)out_int;
104
105 /* Only one of config value or config descriptor needs to be provided */
106 if (input->config_type == kDiceConfigTypeInline) {
107 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_VALUE, &out);
108 if (out.len != sizeof(input->config_value)) {
Maulik Patel6f892252024-03-05 16:39:38 +0000109 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100110 }
111 memcpy(input->config_value, out.ptr, out.len);
112
113 /* Config descriptor is not provided */
114 input->config_descriptor = NULL;
115 input->config_descriptor_size = 0;
116 } else {
117 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_DESCRIPTOR,
118 &out);
119 input->config_descriptor = out.ptr;
120 input->config_descriptor_size = out.len;
121
122 /* Config value is not provided */
123 memset(input->config_value, 0, sizeof(input->config_value));
124 }
125
126 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_HASH, &out);
127 if (out.len != sizeof(input->authority_hash)) {
Maulik Patel6f892252024-03-05 16:39:38 +0000128 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100129 }
130 memcpy(input->authority_hash, out.ptr, out.len);
131
132 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_DESCRIPTOR,
133 &out);
134 input->authority_descriptor = out.ptr;
135 input->authority_descriptor_size = out.len;
136
137 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_MODE, &out_int);
138 if (out_int < kDiceModeNotInitialized || out_int > kDiceModeMaintenance) {
Maulik Patel6f892252024-03-05 16:39:38 +0000139 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100140 }
141 input->mode = (DiceMode)out_int;
142
143 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_HIDDEN, &out);
144 if (out.len != sizeof(input->hidden)) {
Maulik Patel6f892252024-03-05 16:39:38 +0000145 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100146 }
147 memcpy(input->hidden, out.ptr, out.len);
148
149 QCBORDecode_ExitMap(decode_ctx);
150 QCBORDecode_ExitBstrWrapped(decode_ctx);
151
Maulik Pateld936d742024-01-08 14:16:46 +0000152 qcbor_err = QCBORDecode_GetError(decode_ctx);
153 if (qcbor_err != QCBOR_SUCCESS) {
Maulik Patel6f892252024-03-05 16:39:38 +0000154 return DPE_INVALID_ARGUMENT;
Maulik Pateld936d742024-01-08 14:16:46 +0000155 }
156
Jamie Foxab30e712023-03-30 17:48:36 +0100157 return DPE_NO_ERROR;
158}
159
Maulik Patela81605b2023-10-24 12:17:03 +0100160static dpe_error_t decode_derive_context(QCBORDecodeContext *decode_ctx,
161 QCBOREncodeContext *encode_ctx,
162 int32_t client_id)
Jamie Foxab30e712023-03-30 17:48:36 +0100163{
164 dpe_error_t dpe_err;
165 QCBORError qcbor_err;
166 UsefulBufC out;
167 int context_handle;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000168 int32_t target_locality;
Jamie Foxab30e712023-03-30 17:48:36 +0100169 bool retain_parent_context;
Maulik Patela81605b2023-10-24 12:17:03 +0100170 bool allow_new_context_to_derive;
Jamie Foxab30e712023-03-30 17:48:36 +0100171 bool create_certificate;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000172 bool return_certificate;
173 bool allow_new_context_to_export;
174 bool export_cdi;
Jamie Foxab30e712023-03-30 17:48:36 +0100175 DiceInputValues dice_inputs;
Maulik Patela81605b2023-10-24 12:17:03 +0100176 int new_context_handle;
Jamie Foxab30e712023-03-30 17:48:36 +0100177 int new_parent_context_handle;
Tamas Banfcc06e32024-03-25 13:47:33 +0100178 uint8_t *new_certificate_buf = ALLOC_TEMP_BUF;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000179 uint8_t exported_cdi_buf[DICE_MAX_ENCODED_CDI_SIZE];
Maulik Patelcb14cde2024-01-23 12:39:53 +0000180 uint32_t cert_id;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000181 size_t new_certificate_actual_size = 0;
182 size_t exported_cdi_actual_size = 0;
Maulik Patel8a969fd2024-03-01 14:43:03 +0000183 QCBORItem item;
184 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
Jamie Foxab30e712023-03-30 17:48:36 +0100185
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000186 /* Initialise optional parameters with their default value in case
187 * they are not encoded in the input command
188 */
189 cert_id = DPE_CERT_ID_INVALID;
190 retain_parent_context = false;
191 allow_new_context_to_derive = true;
192 create_certificate = true;
193 return_certificate = false;
194 allow_new_context_to_export = false;
195 export_cdi = false;
196
Maulik Patela81605b2023-10-24 12:17:03 +0100197 /* Decode DeriveContext command */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000198 QCBORDecode_EnterMap(decode_ctx, &item);
199 qcbor_err = QCBORDecode_GetError(decode_ctx);
200 if ((qcbor_err != QCBOR_SUCCESS) ||
201 (item.uDataType != QCBOR_TYPE_MAP)) {
202 /* We expect a map of Derive Context command arguments here */
203 return DPE_INVALID_COMMAND;
204 }
205 /* Save the number of items found in the map */
206 num_of_input_arguments = item.val.uCount;
Jamie Foxab30e712023-03-30 17:48:36 +0100207
Maulik Patela81605b2023-10-24 12:17:03 +0100208 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DERIVE_CONTEXT_CONTEXT_HANDLE,
Jamie Foxab30e712023-03-30 17:48:36 +0100209 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000210 qcbor_err = QCBORDecode_GetError(decode_ctx);
Maulik Patelcb14cde2024-01-23 12:39:53 +0000211 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000212 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100213 }
214 memcpy(&context_handle, out.ptr, out.len);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000215 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100216
Maulik Patelcb14cde2024-01-23 12:39:53 +0000217 QCBORDecode_GetUInt64InMapN(decode_ctx, DPE_DERIVE_CONTEXT_CERT_ID, &cert_id);
218 /* Check if cert_id was encoded in the received command buffer */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000219 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patelcb14cde2024-01-23 12:39:53 +0000220
Maulik Patela81605b2023-10-24 12:17:03 +0100221 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT,
Jamie Foxab30e712023-03-30 17:48:36 +0100222 &retain_parent_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000223 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100224
Maulik Patela81605b2023-10-24 12:17:03 +0100225 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE,
226 &allow_new_context_to_derive);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000227 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100228
Maulik Patela81605b2023-10-24 12:17:03 +0100229 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE,
Jamie Foxab30e712023-03-30 17:48:36 +0100230 &create_certificate);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000231 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100232
233 dpe_err = decode_dice_inputs(decode_ctx, &dice_inputs);
234 if (dpe_err != DPE_NO_ERROR) {
235 return dpe_err;
236 }
Maulik Patel8a969fd2024-03-01 14:43:03 +0000237 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100238
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000239 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DERIVE_CONTEXT_TARGET_LOCALITY,
240 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000241 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
242 if (qcbor_err == QCBOR_SUCCESS) {
243 /* Valid argument was found */
244 if (out.len != sizeof(target_locality)) {
245 return DPE_INVALID_ARGUMENT;
246 }
247 memcpy(&target_locality, out.ptr, out.len);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000248 }
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000249
250 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE,
251 &return_certificate);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000252 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000253
254 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT,
255 &allow_new_context_to_export);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000256 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000257
258 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_EXPORT_CDI,
259 &export_cdi);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000260 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000261
Jamie Foxab30e712023-03-30 17:48:36 +0100262 QCBORDecode_ExitMap(decode_ctx);
263
264 /* Exit top level array */
265 QCBORDecode_ExitArray(decode_ctx);
266
267 /* Finish and check for errors before using decoded values */
268 qcbor_err = QCBORDecode_Finish(decode_ctx);
269 if (qcbor_err != QCBOR_SUCCESS) {
270 return DPE_INVALID_COMMAND;
271 }
272
Maulik Patel8a969fd2024-03-01 14:43:03 +0000273 if (num_of_input_arguments > num_of_valid_arguments) {
274 /* Extra unsupported arguments encoded in command map */
275 return DPE_INVALID_ARGUMENT;
276 }
277
Maulik Patelcb14cde2024-01-23 12:39:53 +0000278 dpe_err = derive_context_request(context_handle, cert_id, retain_parent_context,
Maulik Patela81605b2023-10-24 12:17:03 +0100279 allow_new_context_to_derive, create_certificate,
280 &dice_inputs, client_id,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000281 target_locality,
282 return_certificate,
283 allow_new_context_to_export,
284 export_cdi,
Maulik Patela81605b2023-10-24 12:17:03 +0100285 &new_context_handle,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000286 &new_parent_context_handle,
287 new_certificate_buf,
Tamas Banfcc06e32024-03-25 13:47:33 +0100288 SIZEOF_TEMP_BUF,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000289 &new_certificate_actual_size,
290 exported_cdi_buf,
291 sizeof(exported_cdi_buf),
292 &exported_cdi_actual_size);
Jamie Foxab30e712023-03-30 17:48:36 +0100293 if (dpe_err != DPE_NO_ERROR) {
294 return dpe_err;
295 }
296
297 /* Encode response */
298 QCBOREncode_OpenArray(encode_ctx);
299 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
300
301 QCBOREncode_OpenMap(encode_ctx);
Maulik Patela81605b2023-10-24 12:17:03 +0100302 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE,
303 (UsefulBufC){ &new_context_handle,
304 sizeof(new_context_handle) });
Jamie Foxab30e712023-03-30 17:48:36 +0100305 QCBOREncode_AddBytesToMapN(encode_ctx,
Maulik Patela81605b2023-10-24 12:17:03 +0100306 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE,
Jamie Foxab30e712023-03-30 17:48:36 +0100307 (UsefulBufC){ &new_parent_context_handle,
308 sizeof(new_parent_context_handle) });
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000309
310 /* The certificate is already encoded into a CBOR array by the function
Tamas Ban257471b2024-03-25 13:49:53 +0100311 * encode_layer_certificate(). Add it as a byte string so that its
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000312 * decoding can be skipped and the CBOR returned to the caller.
313 */
Tamas Banfcc06e32024-03-25 13:47:33 +0100314 CHECK_OVERFLOW_TO_TEMP_BUF;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000315 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_NEW_CERTIFICATE,
316 (UsefulBufC){ new_certificate_buf,
317 new_certificate_actual_size });
318
319 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_EXPORTED_CDI,
320 (UsefulBufC){ exported_cdi_buf,
321 exported_cdi_actual_size });
322
Jamie Foxab30e712023-03-30 17:48:36 +0100323 QCBOREncode_CloseMap(encode_ctx);
324
325 QCBOREncode_CloseArray(encode_ctx);
326
327 return DPE_NO_ERROR;
328}
329
Maulik Patel54d65f72023-06-28 13:04:36 +0100330static dpe_error_t decode_destroy_context(QCBORDecodeContext *decode_ctx,
331 QCBOREncodeContext *encode_ctx)
332{
333 dpe_error_t dpe_err;
334 QCBORError qcbor_err;
335 UsefulBufC out;
336 int context_handle;
337 bool destroy_recursively;
Maulik Pateldc446492024-03-18 14:52:15 +0000338 QCBORItem item;
339 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
340
341 /* Initialise optional parameters with their default value in case
342 * they are not encoded in the input command
343 */
344 destroy_recursively = false;
Maulik Patel54d65f72023-06-28 13:04:36 +0100345
346 /* Decode Destroy context command */
Maulik Pateldc446492024-03-18 14:52:15 +0000347 QCBORDecode_EnterMap(decode_ctx, &item);
348 qcbor_err = QCBORDecode_GetError(decode_ctx);
349 if ((qcbor_err != QCBOR_SUCCESS) ||
350 (item.uDataType != QCBOR_TYPE_MAP)) {
351 /* We expect a map of Derive Context command arguments here */
352 return DPE_INVALID_COMMAND;
353 }
354 /* Save the number of items found in the map */
355 num_of_input_arguments = item.val.uCount;
Maulik Patel54d65f72023-06-28 13:04:36 +0100356
357 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DESTROY_CONTEXT_HANDLE,
358 &out);
Maulik Pateldc446492024-03-18 14:52:15 +0000359 qcbor_err = QCBORDecode_GetError(decode_ctx);
360 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000361 return DPE_INVALID_ARGUMENT;
Maulik Patel54d65f72023-06-28 13:04:36 +0100362 }
363 memcpy(&context_handle, out.ptr, out.len);
Maulik Pateldc446492024-03-18 14:52:15 +0000364 COUNT_ARGS(num_of_valid_arguments);
Maulik Patel54d65f72023-06-28 13:04:36 +0100365
366 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DESTROY_CONTEXT_RECURSIVELY,
367 &destroy_recursively);
Maulik Pateldc446492024-03-18 14:52:15 +0000368 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel54d65f72023-06-28 13:04:36 +0100369
370 QCBORDecode_ExitMap(decode_ctx);
371
372 /* Exit top level array */
373 QCBORDecode_ExitArray(decode_ctx);
374
375 /* Finish and check for errors before using decoded values */
376 qcbor_err = QCBORDecode_Finish(decode_ctx);
377 if (qcbor_err != QCBOR_SUCCESS) {
378 return DPE_INVALID_COMMAND;
379 }
380
Maulik Pateldc446492024-03-18 14:52:15 +0000381 if (num_of_input_arguments > num_of_valid_arguments) {
382 /* Extra unsupported arguments encoded in command map */
383 return DPE_INVALID_ARGUMENT;
384 }
385
Maulik Patel54d65f72023-06-28 13:04:36 +0100386 dpe_err = destroy_context_request(context_handle, destroy_recursively);
387 if (dpe_err != DPE_NO_ERROR) {
388 return dpe_err;
389 }
390
391 /* Encode response */
392 QCBOREncode_OpenArray(encode_ctx);
393 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
394 QCBOREncode_CloseArray(encode_ctx);
395
396 return DPE_NO_ERROR;
397}
398
Jamie Foxab30e712023-03-30 17:48:36 +0100399static dpe_error_t decode_certify_key(QCBORDecodeContext *decode_ctx,
400 QCBOREncodeContext *encode_ctx)
401{
402 QCBORError qcbor_err;
403 UsefulBufC out;
404 dpe_error_t dpe_err;
405 int context_handle;
406 bool retain_context;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000407 const uint8_t *public_key = NULL;
Jamie Foxab30e712023-03-30 17:48:36 +0100408 size_t public_key_size;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000409 const uint8_t *label = NULL;
Jamie Foxab30e712023-03-30 17:48:36 +0100410 size_t label_size;
Tamas Banfcc06e32024-03-25 13:47:33 +0100411 uint8_t *certificate_buf = ALLOC_TEMP_BUF;
Maulik Patelcbded682023-12-07 11:50:16 +0000412 size_t certificate_actual_size;
Maulik Patele6adc112023-08-18 14:21:51 +0100413 uint8_t derived_public_key_buf[DPE_ATTEST_PUB_KEY_SIZE];
Jamie Foxab30e712023-03-30 17:48:36 +0100414 size_t derived_public_key_actual_size;
415 int new_context_handle;
Maulik Patel8a969fd2024-03-01 14:43:03 +0000416 QCBORItem item;
417 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
Jamie Foxab30e712023-03-30 17:48:36 +0100418
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000419 /* Initialise optional parameters with their default value in case
420 * they are not encoded in the input command
421 */
422 retain_context = false;
423 public_key_size = 0;
424 label_size = 0;
425
Jamie Foxab30e712023-03-30 17:48:36 +0100426 /* Decode CertifyKey command */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000427 QCBORDecode_EnterMap(decode_ctx, &item);
428 qcbor_err = QCBORDecode_GetError(decode_ctx);
429 if ((qcbor_err != QCBOR_SUCCESS) ||
430 (item.uDataType != QCBOR_TYPE_MAP)) {
431 /* We expect a map of Certify Key command arguments here */
432 return DPE_INVALID_COMMAND;
433 }
434 /* Save the number of items found in the map */
435 num_of_input_arguments = item.val.uCount;
Jamie Foxab30e712023-03-30 17:48:36 +0100436
437 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_CONTEXT_HANDLE,
438 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000439 qcbor_err = QCBORDecode_GetError(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000440 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000441 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100442 }
443 memcpy(&context_handle, out.ptr, out.len);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000444 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100445
446 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_CERTIFY_KEY_RETAIN_CONTEXT,
447 &retain_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000448 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100449
450 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_PUBLIC_KEY,
451 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000452 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000453 if (qcbor_err == QCBOR_SUCCESS) {
Maulik Patel8a969fd2024-03-01 14:43:03 +0000454 /* Valid argument was found */
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000455 public_key = out.ptr;
456 public_key_size = out.len;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000457 }
Jamie Foxab30e712023-03-30 17:48:36 +0100458
459 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_LABEL, &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000460 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000461 if (qcbor_err == QCBOR_SUCCESS) {
Maulik Patel8a969fd2024-03-01 14:43:03 +0000462 /* Valid argument was found */
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000463 label = out.ptr;
464 label_size = out.len;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000465 }
Jamie Foxab30e712023-03-30 17:48:36 +0100466
467 QCBORDecode_ExitMap(decode_ctx);
468
469 /* Exit top level array */
470 QCBORDecode_ExitArray(decode_ctx);
471
472 /* Finish and check for errors before using decoded values */
473 qcbor_err = QCBORDecode_Finish(decode_ctx);
474 if (qcbor_err != QCBOR_SUCCESS) {
475 return DPE_INVALID_COMMAND;
476 }
477
Maulik Patel8a969fd2024-03-01 14:43:03 +0000478 if (num_of_input_arguments > num_of_valid_arguments) {
479 /* Extra unsupported arguments encoded in command map */
480 return DPE_INVALID_ARGUMENT;
481 }
482
Maulik Patele6adc112023-08-18 14:21:51 +0100483 dpe_err = certify_key_request(context_handle, retain_context, public_key,
484 public_key_size, label, label_size,
Maulik Patelcbded682023-12-07 11:50:16 +0000485 certificate_buf,
Tamas Banfcc06e32024-03-25 13:47:33 +0100486 SIZEOF_TEMP_BUF,
Maulik Patelcbded682023-12-07 11:50:16 +0000487 &certificate_actual_size,
Maulik Patele6adc112023-08-18 14:21:51 +0100488 derived_public_key_buf,
489 sizeof(derived_public_key_buf),
490 &derived_public_key_actual_size,
491 &new_context_handle);
Jamie Foxab30e712023-03-30 17:48:36 +0100492 if (dpe_err != DPE_NO_ERROR) {
493 return dpe_err;
494 }
495
496 /* Encode response */
497 QCBOREncode_OpenArray(encode_ctx);
498 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
499
500 QCBOREncode_OpenMap(encode_ctx);
501
502 /* The certificate chain is already encoded into a CBOR array by the certify
503 * key implementation. Add it as a byte string so that its decoding can be
504 * skipped and the CBOR returned to the caller.
505 */
Tamas Banfcc06e32024-03-25 13:47:33 +0100506 CHECK_OVERFLOW_TO_TEMP_BUF;
Maulik Patelcbded682023-12-07 11:50:16 +0000507 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_CERTIFICATE,
508 (UsefulBufC){ certificate_buf,
509 certificate_actual_size });
Jamie Foxab30e712023-03-30 17:48:36 +0100510
511 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_DERIVED_PUBLIC_KEY,
512 (UsefulBufC){ derived_public_key_buf,
513 derived_public_key_actual_size });
514 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_NEW_CONTEXT_HANDLE,
515 (UsefulBufC){ &new_context_handle,
516 sizeof(new_context_handle) });
517
518 QCBOREncode_CloseMap(encode_ctx);
519
520 QCBOREncode_CloseArray(encode_ctx);
521
522 return DPE_NO_ERROR;
523}
524
Maulik Patel83a6b592023-12-05 15:20:30 +0000525static dpe_error_t decode_get_certificate_chain(QCBORDecodeContext *decode_ctx,
526 QCBOREncodeContext *encode_ctx)
527{
528 QCBORError qcbor_err;
529 UsefulBufC out;
530 dpe_error_t dpe_err;
531 int context_handle;
532 bool retain_context;
533 bool clear_from_context;
Tamas Banfcc06e32024-03-25 13:47:33 +0100534 uint8_t *certificate_chain_buf = ALLOC_TEMP_BUF;
Maulik Patel83a6b592023-12-05 15:20:30 +0000535 size_t certificate_chain_actual_size;
536 int new_context_handle;
Maulik Patel8a969fd2024-03-01 14:43:03 +0000537 QCBORItem item;
538 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
Maulik Patel83a6b592023-12-05 15:20:30 +0000539
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000540 /* Initialise optional parameters with their default value in case
541 * they are not encoded in the input command
542 */
543 retain_context = false;
544 clear_from_context = false;
545
Maulik Patel83a6b592023-12-05 15:20:30 +0000546 /* Decode GetCertificateChain command */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000547 QCBORDecode_EnterMap(decode_ctx, &item);
548 qcbor_err = QCBORDecode_GetError(decode_ctx);
549 if ((qcbor_err != QCBOR_SUCCESS) ||
550 (item.uDataType != QCBOR_TYPE_MAP)) {
551 /* We expect a map of Get Certificate Chain command arguments here */
552 return DPE_INVALID_COMMAND;
553 }
554 /* Save the number of items found in the map */
555 num_of_input_arguments = item.val.uCount;
Maulik Patel83a6b592023-12-05 15:20:30 +0000556
557 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_CONTEXT_HANDLE,
558 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000559 qcbor_err = QCBORDecode_GetError(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000560 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000561 return DPE_INVALID_ARGUMENT;
Maulik Patel83a6b592023-12-05 15:20:30 +0000562 }
563 memcpy(&context_handle, out.ptr, out.len);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000564 COUNT_ARGS(num_of_valid_arguments);
Maulik Patel83a6b592023-12-05 15:20:30 +0000565
566 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_RETAIN_CONTEXT,
567 &retain_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000568 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel83a6b592023-12-05 15:20:30 +0000569
570 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_CLEAR_FROM_CONTEXT,
571 &clear_from_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000572 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel83a6b592023-12-05 15:20:30 +0000573
574 QCBORDecode_ExitMap(decode_ctx);
575
576 /* Exit top level array */
577 QCBORDecode_ExitArray(decode_ctx);
578
579 /* Finish and check for errors before using decoded values */
580 qcbor_err = QCBORDecode_Finish(decode_ctx);
581 if (qcbor_err != QCBOR_SUCCESS) {
582 return DPE_INVALID_COMMAND;
583 }
584
Maulik Patel8a969fd2024-03-01 14:43:03 +0000585 if (num_of_input_arguments > num_of_valid_arguments) {
586 /* Extra unsupported arguments encoded in command map */
587 return DPE_INVALID_ARGUMENT;
588 }
589
Maulik Patel83a6b592023-12-05 15:20:30 +0000590 dpe_err = get_certificate_chain_request(context_handle,
591 retain_context,
592 clear_from_context,
593 certificate_chain_buf,
Tamas Banfcc06e32024-03-25 13:47:33 +0100594 SIZEOF_TEMP_BUF,
Maulik Patel83a6b592023-12-05 15:20:30 +0000595 &certificate_chain_actual_size,
596 &new_context_handle);
597 if (dpe_err != DPE_NO_ERROR) {
598 return dpe_err;
599 }
600
601 /* Encode response */
602 QCBOREncode_OpenArray(encode_ctx);
603 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
604
605 QCBOREncode_OpenMap(encode_ctx);
606
607 /* The certificate chain is already encoded into a CBOR array by the get certificate
608 * chain implementation. Add it as a byte string so that its decoding can be
609 * skipped and the CBOR returned to the caller.
610 */
Tamas Banfcc06e32024-03-25 13:47:33 +0100611 CHECK_OVERFLOW_TO_TEMP_BUF;
Maulik Patel83a6b592023-12-05 15:20:30 +0000612 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_GET_CERTIFICATE_CHAIN_CERTIFICATE_CHAIN,
613 (UsefulBufC){ certificate_chain_buf,
614 certificate_chain_actual_size });
615
616 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_GET_CERTIFICATE_CHAIN_NEW_CONTEXT_HANDLE,
617 (UsefulBufC){ &new_context_handle,
618 sizeof(new_context_handle) });
619
620 QCBOREncode_CloseMap(encode_ctx);
621
622 QCBOREncode_CloseArray(encode_ctx);
623
624 return DPE_NO_ERROR;
625}
626
Jamie Foxab30e712023-03-30 17:48:36 +0100627static void encode_error_only(QCBOREncodeContext *encode_ctx,
628 dpe_error_t dpe_err)
629{
630 QCBOREncode_OpenArray(encode_ctx);
631 QCBOREncode_AddInt64(encode_ctx, dpe_err);
632 QCBOREncode_CloseArray(encode_ctx);
633}
634
635int32_t dpe_command_decode(int32_t client_id,
636 const char *cmd_input, size_t cmd_input_size,
637 char *cmd_output, size_t *cmd_output_size)
638{
639 dpe_error_t dpe_err;
640 QCBORError qcbor_err;
641 QCBORDecodeContext decode_ctx;
642 QCBOREncodeContext encode_ctx;
643 UsefulBufC out;
644 uint64_t command_id;
645
646 QCBORDecode_Init(&decode_ctx, (UsefulBufC){ cmd_input, cmd_input_size },
647 QCBOR_DECODE_MODE_NORMAL);
648 QCBOREncode_Init(&encode_ctx, (UsefulBuf){ cmd_output, *cmd_output_size });
649
650 /* Enter top level array */
651 QCBORDecode_EnterArray(&decode_ctx, NULL);
652
653 /* Get the command ID */
654 QCBORDecode_GetUInt64(&decode_ctx, &command_id);
655
656 /* Check for errors before interpreting the decoded command ID */
657 qcbor_err = QCBORDecode_GetError(&decode_ctx);
658
659 if (qcbor_err == QCBOR_SUCCESS) {
660 switch (command_id) {
Maulik Patela81605b2023-10-24 12:17:03 +0100661 case DPE_DERIVE_CONTEXT:
662 dpe_err = decode_derive_context(&decode_ctx, &encode_ctx, client_id);
Jamie Foxab30e712023-03-30 17:48:36 +0100663 break;
664 case DPE_CERTIFY_KEY:
665 dpe_err = decode_certify_key(&decode_ctx, &encode_ctx);
666 break;
Maulik Patel83a6b592023-12-05 15:20:30 +0000667 case DPE_GET_CERTIFICATE_CHAIN:
668 dpe_err = decode_get_certificate_chain(&decode_ctx, &encode_ctx);
669 break;
Maulik Patel54d65f72023-06-28 13:04:36 +0100670 case DPE_DESTROY_CONTEXT:
671 dpe_err = decode_destroy_context(&decode_ctx, &encode_ctx);
672 break;
Jamie Foxab30e712023-03-30 17:48:36 +0100673 default:
674 dpe_err = DPE_INVALID_COMMAND;
675 break;
676 }
677 } else {
678 dpe_err = DPE_INVALID_COMMAND;
679 }
680
681 /* If an unhandled DPE error was returned, then encode it into a response */
682 if (dpe_err != DPE_NO_ERROR) {
683 encode_error_only(&encode_ctx, dpe_err);
684 }
685
686 qcbor_err = QCBOREncode_Finish(&encode_ctx, &out);
687 if (qcbor_err != QCBOR_SUCCESS) {
688 return -1;
689 }
690
691 *cmd_output_size = out.len;
692
693 return 0;
694}