blob: f941be8f59f2f951f782e3b31efc77a5a3d6239b [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;
Maulik Patelf4230182024-04-15 13:56:02 +010074 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
75 QCBORItem item;
Jamie Foxab30e712023-03-30 17:48:36 +010076
77 /* The DICE inputs are encoded as a map wrapped into a byte string */
78 QCBORDecode_EnterBstrWrappedFromMapN(decode_ctx,
Maulik Patela81605b2023-10-24 12:17:03 +010079 DPE_DERIVE_CONTEXT_INPUT_DATA,
Jamie Foxab30e712023-03-30 17:48:36 +010080 QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL);
Maulik Patelf4230182024-04-15 13:56:02 +010081 QCBORDecode_EnterMap(decode_ctx, &item);
82 qcbor_err = QCBORDecode_GetError(decode_ctx);
83 if ((qcbor_err != QCBOR_SUCCESS) ||
84 (item.uDataType != QCBOR_TYPE_MAP)) {
85 /* We expect a map of Dice inputs here */
86 return DPE_INVALID_ARGUMENT;
87 }
88 /* Save the number of items found in the map */
89 num_of_input_arguments = item.val.uCount;
Jamie Foxab30e712023-03-30 17:48:36 +010090
91 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_HASH, &out);
Maulik Patelf4230182024-04-15 13:56:02 +010092 qcbor_err = QCBORDecode_GetError(decode_ctx);
93 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(input->code_hash))) {
Maulik Patel6f892252024-03-05 16:39:38 +000094 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +010095 }
96 memcpy(input->code_hash, out.ptr, out.len);
Maulik Patelf4230182024-04-15 13:56:02 +010097 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +010098
99 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_DESCRIPTOR, &out);
Maulik Patelf4230182024-04-15 13:56:02 +0100100 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
101 if (qcbor_err == QCBOR_SUCCESS) {
102 /* Valid argument was found */
103 input->code_descriptor = out.ptr;
104 input->code_descriptor_size = out.len;
105 }
Jamie Foxab30e712023-03-30 17:48:36 +0100106
107 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_CONFIG_TYPE, &out_int);
108
109 /* Check error state before interpreting config type */
110 qcbor_err = QCBORDecode_GetError(decode_ctx);
111 if (qcbor_err != QCBOR_SUCCESS) {
Maulik Patel6f892252024-03-05 16:39:38 +0000112 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100113 }
114
115 if (out_int < kDiceConfigTypeInline ||
116 out_int > kDiceConfigTypeDescriptor) {
Maulik Patel6f892252024-03-05 16:39:38 +0000117 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100118 }
Maulik Patelf4230182024-04-15 13:56:02 +0100119 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100120 input->config_type = (DiceConfigType)out_int;
121
122 /* Only one of config value or config descriptor needs to be provided */
123 if (input->config_type == kDiceConfigTypeInline) {
124 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_VALUE, &out);
Maulik Patelf4230182024-04-15 13:56:02 +0100125 qcbor_err = QCBORDecode_GetError(decode_ctx);
126 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(input->config_value))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000127 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100128 }
Maulik Patelf4230182024-04-15 13:56:02 +0100129 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100130 memcpy(input->config_value, out.ptr, out.len);
131
132 /* Config descriptor is not provided */
133 input->config_descriptor = NULL;
134 input->config_descriptor_size = 0;
135 } else {
136 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_DESCRIPTOR,
137 &out);
Maulik Patelf4230182024-04-15 13:56:02 +0100138 qcbor_err = QCBORDecode_GetError(decode_ctx);
139 if (qcbor_err != QCBOR_SUCCESS) {
140 return DPE_INVALID_ARGUMENT;
141 }
142 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100143 input->config_descriptor = out.ptr;
144 input->config_descriptor_size = out.len;
145
146 /* Config value is not provided */
147 memset(input->config_value, 0, sizeof(input->config_value));
148 }
149
150 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_HASH, &out);
Maulik Patelf4230182024-04-15 13:56:02 +0100151 qcbor_err = QCBORDecode_GetError(decode_ctx);
152 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(input->authority_hash))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000153 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100154 }
Maulik Patelf4230182024-04-15 13:56:02 +0100155 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100156 memcpy(input->authority_hash, out.ptr, out.len);
157
158 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_DESCRIPTOR,
159 &out);
Maulik Patelf4230182024-04-15 13:56:02 +0100160 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
161 if (qcbor_err == QCBOR_SUCCESS) {
162 /* Valid argument was found */
163 input->authority_descriptor = out.ptr;
164 input->authority_descriptor_size = out.len;
165 }
Jamie Foxab30e712023-03-30 17:48:36 +0100166
167 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_MODE, &out_int);
168 if (out_int < kDiceModeNotInitialized || out_int > kDiceModeMaintenance) {
Maulik Patel6f892252024-03-05 16:39:38 +0000169 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100170 }
Maulik Patelf4230182024-04-15 13:56:02 +0100171 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100172 input->mode = (DiceMode)out_int;
173
174 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_HIDDEN, &out);
175 if (out.len != sizeof(input->hidden)) {
Maulik Patel6f892252024-03-05 16:39:38 +0000176 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100177 }
Maulik Patelf4230182024-04-15 13:56:02 +0100178 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100179 memcpy(input->hidden, out.ptr, out.len);
180
181 QCBORDecode_ExitMap(decode_ctx);
182 QCBORDecode_ExitBstrWrapped(decode_ctx);
183
Maulik Pateld936d742024-01-08 14:16:46 +0000184 qcbor_err = QCBORDecode_GetError(decode_ctx);
185 if (qcbor_err != QCBOR_SUCCESS) {
Maulik Patel6f892252024-03-05 16:39:38 +0000186 return DPE_INVALID_ARGUMENT;
Maulik Pateld936d742024-01-08 14:16:46 +0000187 }
188
Maulik Patelf4230182024-04-15 13:56:02 +0100189 if (num_of_input_arguments > num_of_valid_arguments) {
190 /* Extra unsupported arguments encoded in command map */
191 return DPE_INVALID_ARGUMENT;
192 }
193
Jamie Foxab30e712023-03-30 17:48:36 +0100194 return DPE_NO_ERROR;
195}
196
Maulik Patela81605b2023-10-24 12:17:03 +0100197static dpe_error_t decode_derive_context(QCBORDecodeContext *decode_ctx,
198 QCBOREncodeContext *encode_ctx,
199 int32_t client_id)
Jamie Foxab30e712023-03-30 17:48:36 +0100200{
201 dpe_error_t dpe_err;
202 QCBORError qcbor_err;
203 UsefulBufC out;
204 int context_handle;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000205 int32_t target_locality;
Jamie Foxab30e712023-03-30 17:48:36 +0100206 bool retain_parent_context;
Maulik Patela81605b2023-10-24 12:17:03 +0100207 bool allow_new_context_to_derive;
Jamie Foxab30e712023-03-30 17:48:36 +0100208 bool create_certificate;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000209 bool return_certificate;
210 bool allow_new_context_to_export;
211 bool export_cdi;
Maulik Patelf4230182024-04-15 13:56:02 +0100212 DiceInputValues dice_inputs = {0};
Maulik Patela81605b2023-10-24 12:17:03 +0100213 int new_context_handle;
Jamie Foxab30e712023-03-30 17:48:36 +0100214 int new_parent_context_handle;
Tamas Banfcc06e32024-03-25 13:47:33 +0100215 uint8_t *new_certificate_buf = ALLOC_TEMP_BUF;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000216 uint8_t exported_cdi_buf[DICE_MAX_ENCODED_CDI_SIZE];
Maulik Patelcb14cde2024-01-23 12:39:53 +0000217 uint32_t cert_id;
Antonio de Angelis00a5e072025-01-07 12:15:11 +0000218 uint64_t cert_id64;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000219 size_t new_certificate_actual_size = 0;
220 size_t exported_cdi_actual_size = 0;
Maulik Patel8a969fd2024-03-01 14:43:03 +0000221 QCBORItem item;
222 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
Jamie Foxab30e712023-03-30 17:48:36 +0100223
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000224 /* Initialise optional parameters with their default value in case
225 * they are not encoded in the input command
226 */
227 cert_id = DPE_CERT_ID_INVALID;
228 retain_parent_context = false;
229 allow_new_context_to_derive = true;
230 create_certificate = true;
231 return_certificate = false;
232 allow_new_context_to_export = false;
233 export_cdi = false;
Maulik Patelacc3f4a2024-03-25 18:34:05 +0000234 target_locality = DEFAULT_TARGET_LOCALITY;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000235
Maulik Patela81605b2023-10-24 12:17:03 +0100236 /* Decode DeriveContext command */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000237 QCBORDecode_EnterMap(decode_ctx, &item);
238 qcbor_err = QCBORDecode_GetError(decode_ctx);
239 if ((qcbor_err != QCBOR_SUCCESS) ||
240 (item.uDataType != QCBOR_TYPE_MAP)) {
241 /* We expect a map of Derive Context command arguments here */
242 return DPE_INVALID_COMMAND;
243 }
244 /* Save the number of items found in the map */
245 num_of_input_arguments = item.val.uCount;
Jamie Foxab30e712023-03-30 17:48:36 +0100246
Maulik Patela81605b2023-10-24 12:17:03 +0100247 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DERIVE_CONTEXT_CONTEXT_HANDLE,
Jamie Foxab30e712023-03-30 17:48:36 +0100248 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000249 qcbor_err = QCBORDecode_GetError(decode_ctx);
Maulik Patelcb14cde2024-01-23 12:39:53 +0000250 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000251 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100252 }
253 memcpy(&context_handle, out.ptr, out.len);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000254 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100255
Antonio de Angelis00a5e072025-01-07 12:15:11 +0000256 QCBORDecode_GetUInt64InMapN(decode_ctx, DPE_DERIVE_CONTEXT_CERT_ID, &cert_id64);
Maulik Patelcb14cde2024-01-23 12:39:53 +0000257 /* Check if cert_id was encoded in the received command buffer */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000258 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patelcb14cde2024-01-23 12:39:53 +0000259
Maulik Patela81605b2023-10-24 12:17:03 +0100260 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT,
Jamie Foxab30e712023-03-30 17:48:36 +0100261 &retain_parent_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000262 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100263
Maulik Patela81605b2023-10-24 12:17:03 +0100264 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE,
265 &allow_new_context_to_derive);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000266 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100267
Maulik Patela81605b2023-10-24 12:17:03 +0100268 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE,
Jamie Foxab30e712023-03-30 17:48:36 +0100269 &create_certificate);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000270 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100271
272 dpe_err = decode_dice_inputs(decode_ctx, &dice_inputs);
273 if (dpe_err != DPE_NO_ERROR) {
274 return dpe_err;
275 }
Maulik Patel8a969fd2024-03-01 14:43:03 +0000276 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100277
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000278 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DERIVE_CONTEXT_TARGET_LOCALITY,
279 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000280 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
281 if (qcbor_err == QCBOR_SUCCESS) {
282 /* Valid argument was found */
283 if (out.len != sizeof(target_locality)) {
284 return DPE_INVALID_ARGUMENT;
285 }
286 memcpy(&target_locality, out.ptr, out.len);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000287 }
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000288
289 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE,
290 &return_certificate);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000291 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000292
293 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT,
294 &allow_new_context_to_export);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000295 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000296
297 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_EXPORT_CDI,
298 &export_cdi);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000299 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000300
Jamie Foxab30e712023-03-30 17:48:36 +0100301 QCBORDecode_ExitMap(decode_ctx);
302
303 /* Exit top level array */
304 QCBORDecode_ExitArray(decode_ctx);
305
306 /* Finish and check for errors before using decoded values */
307 qcbor_err = QCBORDecode_Finish(decode_ctx);
308 if (qcbor_err != QCBOR_SUCCESS) {
309 return DPE_INVALID_COMMAND;
310 }
311
Maulik Patel8a969fd2024-03-01 14:43:03 +0000312 if (num_of_input_arguments > num_of_valid_arguments) {
313 /* Extra unsupported arguments encoded in command map */
314 return DPE_INVALID_ARGUMENT;
315 }
316
Antonio de Angelis00a5e072025-01-07 12:15:11 +0000317 /* The QCBOR function uses a 64-bit pointer, but the context info is on 32 bit */
318 if (cert_id64 > UINT32_MAX) {
319 return DPE_INVALID_ARGUMENT;
320 }
321
322 cert_id = (uint32_t)cert_id64;
323
Maulik Patelcb14cde2024-01-23 12:39:53 +0000324 dpe_err = derive_context_request(context_handle, cert_id, retain_parent_context,
Maulik Patela81605b2023-10-24 12:17:03 +0100325 allow_new_context_to_derive, create_certificate,
326 &dice_inputs, client_id,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000327 target_locality,
328 return_certificate,
329 allow_new_context_to_export,
330 export_cdi,
Maulik Patela81605b2023-10-24 12:17:03 +0100331 &new_context_handle,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000332 &new_parent_context_handle,
333 new_certificate_buf,
Tamas Banfcc06e32024-03-25 13:47:33 +0100334 SIZEOF_TEMP_BUF,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000335 &new_certificate_actual_size,
336 exported_cdi_buf,
337 sizeof(exported_cdi_buf),
338 &exported_cdi_actual_size);
Jamie Foxab30e712023-03-30 17:48:36 +0100339 if (dpe_err != DPE_NO_ERROR) {
340 return dpe_err;
341 }
342
343 /* Encode response */
344 QCBOREncode_OpenArray(encode_ctx);
345 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
346
347 QCBOREncode_OpenMap(encode_ctx);
Maulik Patela81605b2023-10-24 12:17:03 +0100348 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE,
349 (UsefulBufC){ &new_context_handle,
350 sizeof(new_context_handle) });
Jamie Foxab30e712023-03-30 17:48:36 +0100351 QCBOREncode_AddBytesToMapN(encode_ctx,
Maulik Patela81605b2023-10-24 12:17:03 +0100352 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE,
Jamie Foxab30e712023-03-30 17:48:36 +0100353 (UsefulBufC){ &new_parent_context_handle,
354 sizeof(new_parent_context_handle) });
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000355
356 /* The certificate is already encoded into a CBOR array by the function
Maulik Patel97a61fe2024-07-01 15:55:04 +0100357 * encode_certificate(). Add it as a byte string so that its
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000358 * decoding can be skipped and the CBOR returned to the caller.
359 */
Tamas Banfcc06e32024-03-25 13:47:33 +0100360 CHECK_OVERFLOW_TO_TEMP_BUF;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000361 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_NEW_CERTIFICATE,
362 (UsefulBufC){ new_certificate_buf,
363 new_certificate_actual_size });
364
365 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_EXPORTED_CDI,
366 (UsefulBufC){ exported_cdi_buf,
367 exported_cdi_actual_size });
368
Jamie Foxab30e712023-03-30 17:48:36 +0100369 QCBOREncode_CloseMap(encode_ctx);
370
371 QCBOREncode_CloseArray(encode_ctx);
372
373 return DPE_NO_ERROR;
374}
375
Maulik Patel54d65f72023-06-28 13:04:36 +0100376static dpe_error_t decode_destroy_context(QCBORDecodeContext *decode_ctx,
377 QCBOREncodeContext *encode_ctx)
378{
379 dpe_error_t dpe_err;
380 QCBORError qcbor_err;
381 UsefulBufC out;
382 int context_handle;
383 bool destroy_recursively;
Maulik Pateldc446492024-03-18 14:52:15 +0000384 QCBORItem item;
385 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
386
387 /* Initialise optional parameters with their default value in case
388 * they are not encoded in the input command
389 */
390 destroy_recursively = false;
Maulik Patel54d65f72023-06-28 13:04:36 +0100391
392 /* Decode Destroy context command */
Maulik Pateldc446492024-03-18 14:52:15 +0000393 QCBORDecode_EnterMap(decode_ctx, &item);
394 qcbor_err = QCBORDecode_GetError(decode_ctx);
395 if ((qcbor_err != QCBOR_SUCCESS) ||
396 (item.uDataType != QCBOR_TYPE_MAP)) {
397 /* We expect a map of Derive Context command arguments here */
398 return DPE_INVALID_COMMAND;
399 }
400 /* Save the number of items found in the map */
401 num_of_input_arguments = item.val.uCount;
Maulik Patel54d65f72023-06-28 13:04:36 +0100402
403 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DESTROY_CONTEXT_HANDLE,
404 &out);
Maulik Pateldc446492024-03-18 14:52:15 +0000405 qcbor_err = QCBORDecode_GetError(decode_ctx);
406 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000407 return DPE_INVALID_ARGUMENT;
Maulik Patel54d65f72023-06-28 13:04:36 +0100408 }
409 memcpy(&context_handle, out.ptr, out.len);
Maulik Pateldc446492024-03-18 14:52:15 +0000410 COUNT_ARGS(num_of_valid_arguments);
Maulik Patel54d65f72023-06-28 13:04:36 +0100411
412 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DESTROY_CONTEXT_RECURSIVELY,
413 &destroy_recursively);
Maulik Pateldc446492024-03-18 14:52:15 +0000414 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel54d65f72023-06-28 13:04:36 +0100415
416 QCBORDecode_ExitMap(decode_ctx);
417
418 /* Exit top level array */
419 QCBORDecode_ExitArray(decode_ctx);
420
421 /* Finish and check for errors before using decoded values */
422 qcbor_err = QCBORDecode_Finish(decode_ctx);
423 if (qcbor_err != QCBOR_SUCCESS) {
424 return DPE_INVALID_COMMAND;
425 }
426
Maulik Pateldc446492024-03-18 14:52:15 +0000427 if (num_of_input_arguments > num_of_valid_arguments) {
428 /* Extra unsupported arguments encoded in command map */
429 return DPE_INVALID_ARGUMENT;
430 }
431
Maulik Patel54d65f72023-06-28 13:04:36 +0100432 dpe_err = destroy_context_request(context_handle, destroy_recursively);
433 if (dpe_err != DPE_NO_ERROR) {
434 return dpe_err;
435 }
436
437 /* Encode response */
438 QCBOREncode_OpenArray(encode_ctx);
439 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
440 QCBOREncode_CloseArray(encode_ctx);
441
442 return DPE_NO_ERROR;
443}
444
Jamie Foxab30e712023-03-30 17:48:36 +0100445static dpe_error_t decode_certify_key(QCBORDecodeContext *decode_ctx,
446 QCBOREncodeContext *encode_ctx)
447{
448 QCBORError qcbor_err;
449 UsefulBufC out;
450 dpe_error_t dpe_err;
451 int context_handle;
452 bool retain_context;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000453 const uint8_t *public_key = NULL;
Jamie Foxab30e712023-03-30 17:48:36 +0100454 size_t public_key_size;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000455 const uint8_t *label = NULL;
Jamie Foxab30e712023-03-30 17:48:36 +0100456 size_t label_size;
Tamas Banfcc06e32024-03-25 13:47:33 +0100457 uint8_t *certificate_buf = ALLOC_TEMP_BUF;
Maulik Patelcbded682023-12-07 11:50:16 +0000458 size_t certificate_actual_size;
Maulik Patele6adc112023-08-18 14:21:51 +0100459 uint8_t derived_public_key_buf[DPE_ATTEST_PUB_KEY_SIZE];
Jamie Foxab30e712023-03-30 17:48:36 +0100460 size_t derived_public_key_actual_size;
461 int new_context_handle;
Maulik Patel8a969fd2024-03-01 14:43:03 +0000462 QCBORItem item;
463 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
Jamie Foxab30e712023-03-30 17:48:36 +0100464
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000465 /* Initialise optional parameters with their default value in case
466 * they are not encoded in the input command
467 */
468 retain_context = false;
469 public_key_size = 0;
470 label_size = 0;
471
Jamie Foxab30e712023-03-30 17:48:36 +0100472 /* Decode CertifyKey command */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000473 QCBORDecode_EnterMap(decode_ctx, &item);
474 qcbor_err = QCBORDecode_GetError(decode_ctx);
475 if ((qcbor_err != QCBOR_SUCCESS) ||
476 (item.uDataType != QCBOR_TYPE_MAP)) {
477 /* We expect a map of Certify Key command arguments here */
478 return DPE_INVALID_COMMAND;
479 }
480 /* Save the number of items found in the map */
481 num_of_input_arguments = item.val.uCount;
Jamie Foxab30e712023-03-30 17:48:36 +0100482
483 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_CONTEXT_HANDLE,
484 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000485 qcbor_err = QCBORDecode_GetError(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000486 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000487 return DPE_INVALID_ARGUMENT;
Jamie Foxab30e712023-03-30 17:48:36 +0100488 }
489 memcpy(&context_handle, out.ptr, out.len);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000490 COUNT_ARGS(num_of_valid_arguments);
Jamie Foxab30e712023-03-30 17:48:36 +0100491
492 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_CERTIFY_KEY_RETAIN_CONTEXT,
493 &retain_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000494 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Jamie Foxab30e712023-03-30 17:48:36 +0100495
496 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_PUBLIC_KEY,
497 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000498 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000499 if (qcbor_err == QCBOR_SUCCESS) {
Maulik Patel8a969fd2024-03-01 14:43:03 +0000500 /* Valid argument was found */
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000501 public_key = out.ptr;
502 public_key_size = out.len;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000503 }
Jamie Foxab30e712023-03-30 17:48:36 +0100504
505 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_LABEL, &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000506 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000507 if (qcbor_err == QCBOR_SUCCESS) {
Maulik Patel8a969fd2024-03-01 14:43:03 +0000508 /* Valid argument was found */
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000509 label = out.ptr;
510 label_size = out.len;
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000511 }
Jamie Foxab30e712023-03-30 17:48:36 +0100512
513 QCBORDecode_ExitMap(decode_ctx);
514
515 /* Exit top level array */
516 QCBORDecode_ExitArray(decode_ctx);
517
518 /* Finish and check for errors before using decoded values */
519 qcbor_err = QCBORDecode_Finish(decode_ctx);
520 if (qcbor_err != QCBOR_SUCCESS) {
521 return DPE_INVALID_COMMAND;
522 }
523
Maulik Patel8a969fd2024-03-01 14:43:03 +0000524 if (num_of_input_arguments > num_of_valid_arguments) {
525 /* Extra unsupported arguments encoded in command map */
526 return DPE_INVALID_ARGUMENT;
527 }
528
Maulik Patele6adc112023-08-18 14:21:51 +0100529 dpe_err = certify_key_request(context_handle, retain_context, public_key,
530 public_key_size, label, label_size,
Maulik Patelcbded682023-12-07 11:50:16 +0000531 certificate_buf,
Tamas Banfcc06e32024-03-25 13:47:33 +0100532 SIZEOF_TEMP_BUF,
Maulik Patelcbded682023-12-07 11:50:16 +0000533 &certificate_actual_size,
Maulik Patele6adc112023-08-18 14:21:51 +0100534 derived_public_key_buf,
535 sizeof(derived_public_key_buf),
536 &derived_public_key_actual_size,
537 &new_context_handle);
Jamie Foxab30e712023-03-30 17:48:36 +0100538 if (dpe_err != DPE_NO_ERROR) {
539 return dpe_err;
540 }
541
542 /* Encode response */
543 QCBOREncode_OpenArray(encode_ctx);
544 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
545
546 QCBOREncode_OpenMap(encode_ctx);
547
548 /* The certificate chain is already encoded into a CBOR array by the certify
549 * key implementation. Add it as a byte string so that its decoding can be
550 * skipped and the CBOR returned to the caller.
551 */
Tamas Banfcc06e32024-03-25 13:47:33 +0100552 CHECK_OVERFLOW_TO_TEMP_BUF;
Maulik Patelcbded682023-12-07 11:50:16 +0000553 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_CERTIFICATE,
554 (UsefulBufC){ certificate_buf,
555 certificate_actual_size });
Jamie Foxab30e712023-03-30 17:48:36 +0100556
557 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_DERIVED_PUBLIC_KEY,
558 (UsefulBufC){ derived_public_key_buf,
559 derived_public_key_actual_size });
560 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_NEW_CONTEXT_HANDLE,
561 (UsefulBufC){ &new_context_handle,
562 sizeof(new_context_handle) });
563
564 QCBOREncode_CloseMap(encode_ctx);
565
566 QCBOREncode_CloseArray(encode_ctx);
567
568 return DPE_NO_ERROR;
569}
570
Maulik Patel83a6b592023-12-05 15:20:30 +0000571static dpe_error_t decode_get_certificate_chain(QCBORDecodeContext *decode_ctx,
572 QCBOREncodeContext *encode_ctx)
573{
574 QCBORError qcbor_err;
575 UsefulBufC out;
576 dpe_error_t dpe_err;
577 int context_handle;
578 bool retain_context;
579 bool clear_from_context;
Tamas Banfcc06e32024-03-25 13:47:33 +0100580 uint8_t *certificate_chain_buf = ALLOC_TEMP_BUF;
Maulik Patel83a6b592023-12-05 15:20:30 +0000581 size_t certificate_chain_actual_size;
582 int new_context_handle;
Maulik Patel8a969fd2024-03-01 14:43:03 +0000583 QCBORItem item;
584 uint16_t num_of_input_arguments, num_of_valid_arguments = 0;
Maulik Patel83a6b592023-12-05 15:20:30 +0000585
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000586 /* Initialise optional parameters with their default value in case
587 * they are not encoded in the input command
588 */
589 retain_context = false;
590 clear_from_context = false;
591
Maulik Patel83a6b592023-12-05 15:20:30 +0000592 /* Decode GetCertificateChain command */
Maulik Patel8a969fd2024-03-01 14:43:03 +0000593 QCBORDecode_EnterMap(decode_ctx, &item);
594 qcbor_err = QCBORDecode_GetError(decode_ctx);
595 if ((qcbor_err != QCBOR_SUCCESS) ||
596 (item.uDataType != QCBOR_TYPE_MAP)) {
597 /* We expect a map of Get Certificate Chain command arguments here */
598 return DPE_INVALID_COMMAND;
599 }
600 /* Save the number of items found in the map */
601 num_of_input_arguments = item.val.uCount;
Maulik Patel83a6b592023-12-05 15:20:30 +0000602
603 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_CONTEXT_HANDLE,
604 &out);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000605 qcbor_err = QCBORDecode_GetError(decode_ctx);
Maulik Patelfbe9bff2024-02-09 14:05:25 +0000606 if ((qcbor_err != QCBOR_SUCCESS) || (out.len != sizeof(context_handle))) {
Maulik Patel6f892252024-03-05 16:39:38 +0000607 return DPE_INVALID_ARGUMENT;
Maulik Patel83a6b592023-12-05 15:20:30 +0000608 }
609 memcpy(&context_handle, out.ptr, out.len);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000610 COUNT_ARGS(num_of_valid_arguments);
Maulik Patel83a6b592023-12-05 15:20:30 +0000611
612 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_RETAIN_CONTEXT,
613 &retain_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000614 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel83a6b592023-12-05 15:20:30 +0000615
616 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_CLEAR_FROM_CONTEXT,
617 &clear_from_context);
Maulik Patel8a969fd2024-03-01 14:43:03 +0000618 CHECK_AND_COUNT_OPTIONAL_ARGUMENT(decode_ctx);
Maulik Patel83a6b592023-12-05 15:20:30 +0000619
620 QCBORDecode_ExitMap(decode_ctx);
621
622 /* Exit top level array */
623 QCBORDecode_ExitArray(decode_ctx);
624
625 /* Finish and check for errors before using decoded values */
626 qcbor_err = QCBORDecode_Finish(decode_ctx);
627 if (qcbor_err != QCBOR_SUCCESS) {
628 return DPE_INVALID_COMMAND;
629 }
630
Maulik Patel8a969fd2024-03-01 14:43:03 +0000631 if (num_of_input_arguments > num_of_valid_arguments) {
632 /* Extra unsupported arguments encoded in command map */
633 return DPE_INVALID_ARGUMENT;
634 }
635
Maulik Patel83a6b592023-12-05 15:20:30 +0000636 dpe_err = get_certificate_chain_request(context_handle,
637 retain_context,
638 clear_from_context,
639 certificate_chain_buf,
Tamas Banfcc06e32024-03-25 13:47:33 +0100640 SIZEOF_TEMP_BUF,
Maulik Patel83a6b592023-12-05 15:20:30 +0000641 &certificate_chain_actual_size,
642 &new_context_handle);
643 if (dpe_err != DPE_NO_ERROR) {
644 return dpe_err;
645 }
646
647 /* Encode response */
648 QCBOREncode_OpenArray(encode_ctx);
649 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
650
651 QCBOREncode_OpenMap(encode_ctx);
652
653 /* The certificate chain is already encoded into a CBOR array by the get certificate
654 * chain implementation. Add it as a byte string so that its decoding can be
655 * skipped and the CBOR returned to the caller.
656 */
Tamas Banfcc06e32024-03-25 13:47:33 +0100657 CHECK_OVERFLOW_TO_TEMP_BUF;
Maulik Patel83a6b592023-12-05 15:20:30 +0000658 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_GET_CERTIFICATE_CHAIN_CERTIFICATE_CHAIN,
659 (UsefulBufC){ certificate_chain_buf,
660 certificate_chain_actual_size });
661
662 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_GET_CERTIFICATE_CHAIN_NEW_CONTEXT_HANDLE,
663 (UsefulBufC){ &new_context_handle,
664 sizeof(new_context_handle) });
665
666 QCBOREncode_CloseMap(encode_ctx);
667
668 QCBOREncode_CloseArray(encode_ctx);
669
670 return DPE_NO_ERROR;
671}
672
Jamie Foxab30e712023-03-30 17:48:36 +0100673static void encode_error_only(QCBOREncodeContext *encode_ctx,
674 dpe_error_t dpe_err)
675{
676 QCBOREncode_OpenArray(encode_ctx);
677 QCBOREncode_AddInt64(encode_ctx, dpe_err);
678 QCBOREncode_CloseArray(encode_ctx);
679}
680
681int32_t dpe_command_decode(int32_t client_id,
682 const char *cmd_input, size_t cmd_input_size,
683 char *cmd_output, size_t *cmd_output_size)
684{
685 dpe_error_t dpe_err;
686 QCBORError qcbor_err;
687 QCBORDecodeContext decode_ctx;
688 QCBOREncodeContext encode_ctx;
689 UsefulBufC out;
690 uint64_t command_id;
691
692 QCBORDecode_Init(&decode_ctx, (UsefulBufC){ cmd_input, cmd_input_size },
693 QCBOR_DECODE_MODE_NORMAL);
694 QCBOREncode_Init(&encode_ctx, (UsefulBuf){ cmd_output, *cmd_output_size });
695
696 /* Enter top level array */
697 QCBORDecode_EnterArray(&decode_ctx, NULL);
698
699 /* Get the command ID */
700 QCBORDecode_GetUInt64(&decode_ctx, &command_id);
701
702 /* Check for errors before interpreting the decoded command ID */
703 qcbor_err = QCBORDecode_GetError(&decode_ctx);
704
705 if (qcbor_err == QCBOR_SUCCESS) {
706 switch (command_id) {
Maulik Patela81605b2023-10-24 12:17:03 +0100707 case DPE_DERIVE_CONTEXT:
708 dpe_err = decode_derive_context(&decode_ctx, &encode_ctx, client_id);
Jamie Foxab30e712023-03-30 17:48:36 +0100709 break;
710 case DPE_CERTIFY_KEY:
711 dpe_err = decode_certify_key(&decode_ctx, &encode_ctx);
712 break;
Maulik Patel83a6b592023-12-05 15:20:30 +0000713 case DPE_GET_CERTIFICATE_CHAIN:
714 dpe_err = decode_get_certificate_chain(&decode_ctx, &encode_ctx);
715 break;
Maulik Patel54d65f72023-06-28 13:04:36 +0100716 case DPE_DESTROY_CONTEXT:
717 dpe_err = decode_destroy_context(&decode_ctx, &encode_ctx);
718 break;
Jamie Foxab30e712023-03-30 17:48:36 +0100719 default:
720 dpe_err = DPE_INVALID_COMMAND;
721 break;
722 }
723 } else {
724 dpe_err = DPE_INVALID_COMMAND;
725 }
726
727 /* If an unhandled DPE error was returned, then encode it into a response */
728 if (dpe_err != DPE_NO_ERROR) {
729 encode_error_only(&encode_ctx, dpe_err);
730 }
731
732 qcbor_err = QCBOREncode_Finish(&encode_ctx, &out);
733 if (qcbor_err != QCBOR_SUCCESS) {
734 return -1;
735 }
736
737 *cmd_output_size = out.len;
738
739 return 0;
740}