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