blob: 511206356ea08fc60d0f711c68c7129da2f0ae5d [file] [log] [blame]
Jamie Foxab30e712023-03-30 17:48:36 +01001/*
2 * Copyright (c) 2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include "dpe_cmd_decode.h"
9
10#include <string.h>
11
12#include "dpe_client.h"
Maulik Patelad2f3db2023-05-17 15:41:36 +010013#include "dpe_context_mngr.h"
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
19static dpe_error_t decode_dice_inputs(QCBORDecodeContext *decode_ctx,
20 DiceInputValues *input)
21{
22 QCBORError qcbor_err;
23 UsefulBufC out = { NULL, 0 };
24 int64_t out_int;
25
26 /* The DICE inputs are encoded as a map wrapped into a byte string */
27 QCBORDecode_EnterBstrWrappedFromMapN(decode_ctx,
Maulik Patela81605b2023-10-24 12:17:03 +010028 DPE_DERIVE_CONTEXT_INPUT_DATA,
Jamie Foxab30e712023-03-30 17:48:36 +010029 QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL);
30 QCBORDecode_EnterMap(decode_ctx, NULL);
31
32 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_HASH, &out);
33 if (out.len != sizeof(input->code_hash)) {
34 return DPE_INVALID_COMMAND;
35 }
36 memcpy(input->code_hash, out.ptr, out.len);
37
38 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CODE_DESCRIPTOR, &out);
39 input->code_descriptor = out.ptr;
40 input->code_descriptor_size = out.len;
41
42 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_CONFIG_TYPE, &out_int);
43
44 /* Check error state before interpreting config type */
45 qcbor_err = QCBORDecode_GetError(decode_ctx);
46 if (qcbor_err != QCBOR_SUCCESS) {
47 return DPE_INVALID_COMMAND;
48 }
49
50 if (out_int < kDiceConfigTypeInline ||
51 out_int > kDiceConfigTypeDescriptor) {
52 return DPE_INVALID_COMMAND;
53 }
54 input->config_type = (DiceConfigType)out_int;
55
56 /* Only one of config value or config descriptor needs to be provided */
57 if (input->config_type == kDiceConfigTypeInline) {
58 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_VALUE, &out);
59 if (out.len != sizeof(input->config_value)) {
60 return DPE_INVALID_COMMAND;
61 }
62 memcpy(input->config_value, out.ptr, out.len);
63
64 /* Config descriptor is not provided */
65 input->config_descriptor = NULL;
66 input->config_descriptor_size = 0;
67 } else {
68 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_CONFIG_DESCRIPTOR,
69 &out);
70 input->config_descriptor = out.ptr;
71 input->config_descriptor_size = out.len;
72
73 /* Config value is not provided */
74 memset(input->config_value, 0, sizeof(input->config_value));
75 }
76
77 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_HASH, &out);
78 if (out.len != sizeof(input->authority_hash)) {
79 return DPE_INVALID_COMMAND;
80 }
81 memcpy(input->authority_hash, out.ptr, out.len);
82
83 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_AUTHORITY_DESCRIPTOR,
84 &out);
85 input->authority_descriptor = out.ptr;
86 input->authority_descriptor_size = out.len;
87
88 QCBORDecode_GetInt64InMapN(decode_ctx, DICE_MODE, &out_int);
89 if (out_int < kDiceModeNotInitialized || out_int > kDiceModeMaintenance) {
90 return DPE_INVALID_COMMAND;
91 }
92 input->mode = (DiceMode)out_int;
93
94 QCBORDecode_GetByteStringInMapN(decode_ctx, DICE_HIDDEN, &out);
95 if (out.len != sizeof(input->hidden)) {
96 return DPE_INVALID_COMMAND;
97 }
98 memcpy(input->hidden, out.ptr, out.len);
99
100 QCBORDecode_ExitMap(decode_ctx);
101 QCBORDecode_ExitBstrWrapped(decode_ctx);
102
103 return DPE_NO_ERROR;
104}
105
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000106//TODO: Handle the omission of parameters from DPE commands.
Maulik Patela81605b2023-10-24 12:17:03 +0100107static dpe_error_t decode_derive_context(QCBORDecodeContext *decode_ctx,
108 QCBOREncodeContext *encode_ctx,
109 int32_t client_id)
Jamie Foxab30e712023-03-30 17:48:36 +0100110{
111 dpe_error_t dpe_err;
112 QCBORError qcbor_err;
113 UsefulBufC out;
114 int context_handle;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000115 int32_t target_locality;
Jamie Foxab30e712023-03-30 17:48:36 +0100116 bool retain_parent_context;
Maulik Patela81605b2023-10-24 12:17:03 +0100117 bool allow_new_context_to_derive;
Jamie Foxab30e712023-03-30 17:48:36 +0100118 bool create_certificate;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000119 bool return_certificate;
120 bool allow_new_context_to_export;
121 bool export_cdi;
Jamie Foxab30e712023-03-30 17:48:36 +0100122 DiceInputValues dice_inputs;
Maulik Patela81605b2023-10-24 12:17:03 +0100123 int new_context_handle;
Jamie Foxab30e712023-03-30 17:48:36 +0100124 int new_parent_context_handle;
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000125 uint8_t new_certificate_buf[DICE_CERT_SIZE];
126 uint8_t exported_cdi_buf[DICE_MAX_ENCODED_CDI_SIZE];
127 size_t new_certificate_actual_size = 0;
128 size_t exported_cdi_actual_size = 0;
Jamie Foxab30e712023-03-30 17:48:36 +0100129
Maulik Patela81605b2023-10-24 12:17:03 +0100130 /* Decode DeriveContext command */
Jamie Foxab30e712023-03-30 17:48:36 +0100131 QCBORDecode_EnterMap(decode_ctx, NULL);
132
Maulik Patela81605b2023-10-24 12:17:03 +0100133 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DERIVE_CONTEXT_CONTEXT_HANDLE,
Jamie Foxab30e712023-03-30 17:48:36 +0100134 &out);
135 if (out.len != sizeof(context_handle)) {
136 return DPE_INVALID_COMMAND;
137 }
138 memcpy(&context_handle, out.ptr, out.len);
139
Maulik Patela81605b2023-10-24 12:17:03 +0100140 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT,
Jamie Foxab30e712023-03-30 17:48:36 +0100141 &retain_parent_context);
142
Maulik Patela81605b2023-10-24 12:17:03 +0100143 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE,
144 &allow_new_context_to_derive);
Jamie Foxab30e712023-03-30 17:48:36 +0100145
Maulik Patela81605b2023-10-24 12:17:03 +0100146 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE,
Jamie Foxab30e712023-03-30 17:48:36 +0100147 &create_certificate);
148
149 dpe_err = decode_dice_inputs(decode_ctx, &dice_inputs);
150 if (dpe_err != DPE_NO_ERROR) {
151 return dpe_err;
152 }
153
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000154 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DERIVE_CONTEXT_TARGET_LOCALITY,
155 &out);
156 if (out.len != sizeof(target_locality)) {
157 return DPE_INVALID_COMMAND;
158 }
159 memcpy(&target_locality, out.ptr, out.len);
160
161 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE,
162 &return_certificate);
163
164 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT,
165 &allow_new_context_to_export);
166
167 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DERIVE_CONTEXT_EXPORT_CDI,
168 &export_cdi);
169
Jamie Foxab30e712023-03-30 17:48:36 +0100170 QCBORDecode_ExitMap(decode_ctx);
171
172 /* Exit top level array */
173 QCBORDecode_ExitArray(decode_ctx);
174
175 /* Finish and check for errors before using decoded values */
176 qcbor_err = QCBORDecode_Finish(decode_ctx);
177 if (qcbor_err != QCBOR_SUCCESS) {
178 return DPE_INVALID_COMMAND;
179 }
180
Maulik Patela81605b2023-10-24 12:17:03 +0100181 dpe_err = derive_context_request(context_handle, retain_parent_context,
182 allow_new_context_to_derive, create_certificate,
183 &dice_inputs, client_id,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000184 target_locality,
185 return_certificate,
186 allow_new_context_to_export,
187 export_cdi,
Maulik Patela81605b2023-10-24 12:17:03 +0100188 &new_context_handle,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000189 &new_parent_context_handle,
190 new_certificate_buf,
191 sizeof(new_certificate_buf),
192 &new_certificate_actual_size,
193 exported_cdi_buf,
194 sizeof(exported_cdi_buf),
195 &exported_cdi_actual_size);
Jamie Foxab30e712023-03-30 17:48:36 +0100196 if (dpe_err != DPE_NO_ERROR) {
197 return dpe_err;
198 }
199
200 /* Encode response */
201 QCBOREncode_OpenArray(encode_ctx);
202 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
203
204 QCBOREncode_OpenMap(encode_ctx);
Maulik Patela81605b2023-10-24 12:17:03 +0100205 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE,
206 (UsefulBufC){ &new_context_handle,
207 sizeof(new_context_handle) });
Jamie Foxab30e712023-03-30 17:48:36 +0100208 QCBOREncode_AddBytesToMapN(encode_ctx,
Maulik Patela81605b2023-10-24 12:17:03 +0100209 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE,
Jamie Foxab30e712023-03-30 17:48:36 +0100210 (UsefulBufC){ &new_parent_context_handle,
211 sizeof(new_parent_context_handle) });
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000212
213 /* The certificate is already encoded into a CBOR array by the function
214 * add_encoded_layer_certificate. Add it as a byte string so that its
215 * decoding can be skipped and the CBOR returned to the caller.
216 */
217 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_NEW_CERTIFICATE,
218 (UsefulBufC){ new_certificate_buf,
219 new_certificate_actual_size });
220
221 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_DERIVE_CONTEXT_EXPORTED_CDI,
222 (UsefulBufC){ exported_cdi_buf,
223 exported_cdi_actual_size });
224
Jamie Foxab30e712023-03-30 17:48:36 +0100225 QCBOREncode_CloseMap(encode_ctx);
226
227 QCBOREncode_CloseArray(encode_ctx);
228
229 return DPE_NO_ERROR;
230}
231
Maulik Patel54d65f72023-06-28 13:04:36 +0100232static dpe_error_t decode_destroy_context(QCBORDecodeContext *decode_ctx,
233 QCBOREncodeContext *encode_ctx)
234{
235 dpe_error_t dpe_err;
236 QCBORError qcbor_err;
237 UsefulBufC out;
238 int context_handle;
239 bool destroy_recursively;
240
241 /* Decode Destroy context command */
242 QCBORDecode_EnterMap(decode_ctx, NULL);
243
244 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DESTROY_CONTEXT_HANDLE,
245 &out);
246 if (out.len != sizeof(context_handle)) {
247 return DPE_INVALID_COMMAND;
248 }
249 memcpy(&context_handle, out.ptr, out.len);
250
251 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DESTROY_CONTEXT_RECURSIVELY,
252 &destroy_recursively);
253
254 QCBORDecode_ExitMap(decode_ctx);
255
256 /* Exit top level array */
257 QCBORDecode_ExitArray(decode_ctx);
258
259 /* Finish and check for errors before using decoded values */
260 qcbor_err = QCBORDecode_Finish(decode_ctx);
261 if (qcbor_err != QCBOR_SUCCESS) {
262 return DPE_INVALID_COMMAND;
263 }
264
265 dpe_err = destroy_context_request(context_handle, destroy_recursively);
266 if (dpe_err != DPE_NO_ERROR) {
267 return dpe_err;
268 }
269
270 /* Encode response */
271 QCBOREncode_OpenArray(encode_ctx);
272 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
273 QCBOREncode_CloseArray(encode_ctx);
274
275 return DPE_NO_ERROR;
276}
277
Jamie Foxab30e712023-03-30 17:48:36 +0100278static dpe_error_t decode_certify_key(QCBORDecodeContext *decode_ctx,
279 QCBOREncodeContext *encode_ctx)
280{
281 QCBORError qcbor_err;
282 UsefulBufC out;
283 dpe_error_t dpe_err;
284 int context_handle;
285 bool retain_context;
286 const uint8_t *public_key;
287 size_t public_key_size;
288 const uint8_t *label;
289 size_t label_size;
Maulik Patelcbded682023-12-07 11:50:16 +0000290 uint8_t certificate_buf[DICE_CERT_SIZE];
291 size_t certificate_actual_size;
Maulik Patele6adc112023-08-18 14:21:51 +0100292 uint8_t derived_public_key_buf[DPE_ATTEST_PUB_KEY_SIZE];
Jamie Foxab30e712023-03-30 17:48:36 +0100293 size_t derived_public_key_actual_size;
294 int new_context_handle;
295
296 /* Decode CertifyKey command */
297 QCBORDecode_EnterMap(decode_ctx, NULL);
298
299 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_CONTEXT_HANDLE,
300 &out);
301 if (out.len != sizeof(context_handle)) {
302 return DPE_INVALID_COMMAND;
303 }
304 memcpy(&context_handle, out.ptr, out.len);
305
306 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_CERTIFY_KEY_RETAIN_CONTEXT,
307 &retain_context);
308
309 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_PUBLIC_KEY,
310 &out);
311 public_key = out.ptr;
312 public_key_size = out.len;
313
314 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_CERTIFY_KEY_LABEL, &out);
315 label = out.ptr;
316 label_size = out.len;
317
318 QCBORDecode_ExitMap(decode_ctx);
319
320 /* Exit top level array */
321 QCBORDecode_ExitArray(decode_ctx);
322
323 /* Finish and check for errors before using decoded values */
324 qcbor_err = QCBORDecode_Finish(decode_ctx);
325 if (qcbor_err != QCBOR_SUCCESS) {
326 return DPE_INVALID_COMMAND;
327 }
328
Maulik Patele6adc112023-08-18 14:21:51 +0100329 dpe_err = certify_key_request(context_handle, retain_context, public_key,
330 public_key_size, label, label_size,
Maulik Patelcbded682023-12-07 11:50:16 +0000331 certificate_buf,
332 sizeof(certificate_buf),
333 &certificate_actual_size,
Maulik Patele6adc112023-08-18 14:21:51 +0100334 derived_public_key_buf,
335 sizeof(derived_public_key_buf),
336 &derived_public_key_actual_size,
337 &new_context_handle);
Jamie Foxab30e712023-03-30 17:48:36 +0100338 if (dpe_err != DPE_NO_ERROR) {
339 return dpe_err;
340 }
341
342 /* Encode response */
343 QCBOREncode_OpenArray(encode_ctx);
344 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
345
346 QCBOREncode_OpenMap(encode_ctx);
347
348 /* The certificate chain is already encoded into a CBOR array by the certify
349 * key implementation. Add it as a byte string so that its decoding can be
350 * skipped and the CBOR returned to the caller.
351 */
Maulik Patelcbded682023-12-07 11:50:16 +0000352 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_CERTIFICATE,
353 (UsefulBufC){ certificate_buf,
354 certificate_actual_size });
Jamie Foxab30e712023-03-30 17:48:36 +0100355
356 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_DERIVED_PUBLIC_KEY,
357 (UsefulBufC){ derived_public_key_buf,
358 derived_public_key_actual_size });
359 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_CERTIFY_KEY_NEW_CONTEXT_HANDLE,
360 (UsefulBufC){ &new_context_handle,
361 sizeof(new_context_handle) });
362
363 QCBOREncode_CloseMap(encode_ctx);
364
365 QCBOREncode_CloseArray(encode_ctx);
366
367 return DPE_NO_ERROR;
368}
369
Maulik Patel83a6b592023-12-05 15:20:30 +0000370static dpe_error_t decode_get_certificate_chain(QCBORDecodeContext *decode_ctx,
371 QCBOREncodeContext *encode_ctx)
372{
373 QCBORError qcbor_err;
374 UsefulBufC out;
375 dpe_error_t dpe_err;
376 int context_handle;
377 bool retain_context;
378 bool clear_from_context;
379 uint8_t certificate_chain_buf[DICE_CERT_CHAIN_SIZE];
380 size_t certificate_chain_actual_size;
381 int new_context_handle;
382
383 /* Decode GetCertificateChain command */
384 QCBORDecode_EnterMap(decode_ctx, NULL);
385
386 QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_CONTEXT_HANDLE,
387 &out);
388 if (out.len != sizeof(context_handle)) {
389 return DPE_INVALID_COMMAND;
390 }
391 memcpy(&context_handle, out.ptr, out.len);
392
393 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_RETAIN_CONTEXT,
394 &retain_context);
395
396 QCBORDecode_GetBoolInMapN(decode_ctx, DPE_GET_CERTIFICATE_CHAIN_CLEAR_FROM_CONTEXT,
397 &clear_from_context);
398
399 QCBORDecode_ExitMap(decode_ctx);
400
401 /* Exit top level array */
402 QCBORDecode_ExitArray(decode_ctx);
403
404 /* Finish and check for errors before using decoded values */
405 qcbor_err = QCBORDecode_Finish(decode_ctx);
406 if (qcbor_err != QCBOR_SUCCESS) {
407 return DPE_INVALID_COMMAND;
408 }
409
410 dpe_err = get_certificate_chain_request(context_handle,
411 retain_context,
412 clear_from_context,
413 certificate_chain_buf,
414 sizeof(certificate_chain_buf),
415 &certificate_chain_actual_size,
416 &new_context_handle);
417 if (dpe_err != DPE_NO_ERROR) {
418 return dpe_err;
419 }
420
421 /* Encode response */
422 QCBOREncode_OpenArray(encode_ctx);
423 QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
424
425 QCBOREncode_OpenMap(encode_ctx);
426
427 /* The certificate chain is already encoded into a CBOR array by the get certificate
428 * chain implementation. Add it as a byte string so that its decoding can be
429 * skipped and the CBOR returned to the caller.
430 */
431 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_GET_CERTIFICATE_CHAIN_CERTIFICATE_CHAIN,
432 (UsefulBufC){ certificate_chain_buf,
433 certificate_chain_actual_size });
434
435 QCBOREncode_AddBytesToMapN(encode_ctx, DPE_GET_CERTIFICATE_CHAIN_NEW_CONTEXT_HANDLE,
436 (UsefulBufC){ &new_context_handle,
437 sizeof(new_context_handle) });
438
439 QCBOREncode_CloseMap(encode_ctx);
440
441 QCBOREncode_CloseArray(encode_ctx);
442
443 return DPE_NO_ERROR;
444}
445
Jamie Foxab30e712023-03-30 17:48:36 +0100446static void encode_error_only(QCBOREncodeContext *encode_ctx,
447 dpe_error_t dpe_err)
448{
449 QCBOREncode_OpenArray(encode_ctx);
450 QCBOREncode_AddInt64(encode_ctx, dpe_err);
451 QCBOREncode_CloseArray(encode_ctx);
452}
453
454int32_t dpe_command_decode(int32_t client_id,
455 const char *cmd_input, size_t cmd_input_size,
456 char *cmd_output, size_t *cmd_output_size)
457{
458 dpe_error_t dpe_err;
459 QCBORError qcbor_err;
460 QCBORDecodeContext decode_ctx;
461 QCBOREncodeContext encode_ctx;
462 UsefulBufC out;
463 uint64_t command_id;
464
465 QCBORDecode_Init(&decode_ctx, (UsefulBufC){ cmd_input, cmd_input_size },
466 QCBOR_DECODE_MODE_NORMAL);
467 QCBOREncode_Init(&encode_ctx, (UsefulBuf){ cmd_output, *cmd_output_size });
468
469 /* Enter top level array */
470 QCBORDecode_EnterArray(&decode_ctx, NULL);
471
472 /* Get the command ID */
473 QCBORDecode_GetUInt64(&decode_ctx, &command_id);
474
475 /* Check for errors before interpreting the decoded command ID */
476 qcbor_err = QCBORDecode_GetError(&decode_ctx);
477
478 if (qcbor_err == QCBOR_SUCCESS) {
479 switch (command_id) {
Maulik Patela81605b2023-10-24 12:17:03 +0100480 case DPE_DERIVE_CONTEXT:
481 dpe_err = decode_derive_context(&decode_ctx, &encode_ctx, client_id);
Jamie Foxab30e712023-03-30 17:48:36 +0100482 break;
483 case DPE_CERTIFY_KEY:
484 dpe_err = decode_certify_key(&decode_ctx, &encode_ctx);
485 break;
Maulik Patel83a6b592023-12-05 15:20:30 +0000486 case DPE_GET_CERTIFICATE_CHAIN:
487 dpe_err = decode_get_certificate_chain(&decode_ctx, &encode_ctx);
488 break;
Maulik Patel54d65f72023-06-28 13:04:36 +0100489 case DPE_DESTROY_CONTEXT:
490 dpe_err = decode_destroy_context(&decode_ctx, &encode_ctx);
491 break;
Jamie Foxab30e712023-03-30 17:48:36 +0100492 default:
493 dpe_err = DPE_INVALID_COMMAND;
494 break;
495 }
496 } else {
497 dpe_err = DPE_INVALID_COMMAND;
498 }
499
500 /* If an unhandled DPE error was returned, then encode it into a response */
501 if (dpe_err != DPE_NO_ERROR) {
502 encode_error_only(&encode_ctx, dpe_err);
503 }
504
505 qcbor_err = QCBOREncode_Finish(&encode_ctx, &out);
506 if (qcbor_err != QCBOR_SUCCESS) {
507 return -1;
508 }
509
510 *cmd_output_size = out.len;
511
512 return 0;
513}