blob: b33ae7a2a91eece02a30e2df13a9218d5267b414 [file] [log] [blame]
Tamas Banfb6237e2023-06-06 13:41:14 +02001/*
2 * Copyright (c) 2024, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include <qcbor/qcbor_decode.h>
9#include <qcbor/qcbor_encode.h>
10#include <qcbor/qcbor_spiffy_decode.h>
11
12#include <common/debug.h>
13#include <dice.h>
14#include <dice_protection_environment.h>
15#include <psa/client.h>
16#include <psa_manifest/sid.h>
17
18enum dpe_command_id_t {
19 /* Standard commands */
20 DPE_GET_PROFILE = 1,
21 DPE_OPEN_SESSION = 2,
22 DPE_CLOSE_SESSION = 3,
23 DPE_SYNC_SESSION = 4,
24 DPE_EXPORT_SESSION = 5,
25 DPE_IMPORT_SESSION = 6,
26 DPE_INITIALIZE_CONTEXT = 7,
27 DPE_DERIVE_CONTEXT = 8,
28 DPE_CERTIFY_KEY = 9,
29 DPE_SIGN = 10,
30 DPE_SEAL = 11,
31 DPE_UNSEAL = 12,
32 DPE_DERIVE_SEALING_PUBLIC_KEY = 13,
33 DPE_ROTATE_CONTEXT_HANDLE = 14,
34 DPE_DESTROY_CONTEXT = 15,
35};
36
37enum dice_input_labels_t {
38 DICE_CODE_HASH = 1,
39 DICE_CODE_DESCRIPTOR = 2,
40 DICE_CONFIG_TYPE = 3,
41 DICE_CONFIG_VALUE = 4,
42 DICE_CONFIG_DESCRIPTOR = 5,
43 DICE_AUTHORITY_HASH = 6,
44 DICE_AUTHORITY_DESCRIPTOR = 7,
45 DICE_MODE = 8,
46 DICE_HIDDEN = 9,
47};
48
49enum dpe_derive_context_input_labels_t {
50 DPE_DERIVE_CONTEXT_CONTEXT_HANDLE = 1,
51 DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT = 2,
52 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE = 3,
53 DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE = 4,
54 DPE_DERIVE_CONTEXT_NEW_SESSION_INITIATOR_HANDSHAKE = 5,
55 DPE_DERIVE_CONTEXT_INPUT_DATA = 6,
56 DPE_DERIVE_CONTEXT_INTERNAL_INPUTS = 7,
57 DPE_DERIVE_CONTEXT_TARGET_LOCALITY = 8,
58 DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE = 9,
59 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT = 10,
60 DPE_DERIVE_CONTEXT_EXPORT_CDI = 11,
61};
62
63enum dpe_derive_context_output_labels_t {
64 DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE = 1,
65 DPE_DERIVE_CONTEXT_NEW_SESSION_RESPONDER_HANDSHAKE = 2,
66 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE = 3,
67 DPE_DERIVE_CONTEXT_NEW_CERTIFICATE = 4,
68 DPE_DERIVE_CONTEXT_EXPORTED_CDI = 5,
69};
70
71struct derive_context_input_t {
72 int context_handle;
73 bool retain_parent_context;
74 bool allow_new_context_to_derive;
75 bool create_certificate;
76 const DiceInputValues *dice_inputs;
77 int32_t target_locality;
78 bool return_certificate;
79 bool allow_new_context_to_export;
80 bool export_cdi;
81};
82
83struct derive_context_output_t {
84 int new_context_handle;
85 int new_parent_context_handle;
86 const uint8_t *new_certificate;
87 size_t new_certificate_size;
88 const uint8_t *exported_cdi;
89 size_t exported_cdi_size;
90};
91
92static void encode_dice_inputs(QCBOREncodeContext *encode_ctx,
93 const DiceInputValues *input)
94{
95 /* Wrap the DICE inputs into a byte string */
96 QCBOREncode_BstrWrapInMapN(encode_ctx, DPE_DERIVE_CONTEXT_INPUT_DATA);
97
98 /* Inside the byte string the DICE inputs are encoded as a map */
99 QCBOREncode_OpenMap(encode_ctx);
100
101 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CODE_HASH,
102 (UsefulBufC) { input->code_hash,
103 sizeof(input->code_hash) });
104
105 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CODE_DESCRIPTOR,
106 (UsefulBufC) { input->code_descriptor,
107 input->code_descriptor_size });
108
109 QCBOREncode_AddInt64ToMapN(encode_ctx, DICE_CONFIG_TYPE,
110 input->config_type);
111
112 if (input->config_type == kDiceConfigTypeInline) {
113 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CONFIG_VALUE,
114 (UsefulBufC) { input->config_value,
115 sizeof(input->config_value) });
116 } else {
117 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CONFIG_DESCRIPTOR,
118 (UsefulBufC) { input->config_descriptor,
119 input->config_descriptor_size });
120 }
121
122 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_AUTHORITY_HASH,
123 (UsefulBufC) { input->authority_hash,
124 sizeof(input->authority_hash) });
125
126 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_AUTHORITY_DESCRIPTOR,
127 (UsefulBufC) { input->authority_descriptor,
128 input->authority_descriptor_size });
129
130 QCBOREncode_AddInt64ToMapN(encode_ctx, DICE_MODE, input->mode);
131
132 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_HIDDEN,
133 (UsefulBufC) { input->hidden,
134 sizeof(input->hidden) });
135
136 QCBOREncode_CloseMap(encode_ctx);
137 QCBOREncode_CloseBstrWrap2(encode_ctx, true, NULL);
138}
139
140static QCBORError encode_derive_context(const struct derive_context_input_t *args,
141 UsefulBuf buf,
142 UsefulBufC *encoded_buf)
143{
144 QCBOREncodeContext encode_ctx;
145
146 QCBOREncode_Init(&encode_ctx, buf);
147
148 QCBOREncode_OpenArray(&encode_ctx);
149 QCBOREncode_AddUInt64(&encode_ctx, DPE_DERIVE_CONTEXT);
150
151 /* Encode DeriveContext command */
152 QCBOREncode_OpenMap(&encode_ctx);
153 QCBOREncode_AddBytesToMapN(&encode_ctx,
154 DPE_DERIVE_CONTEXT_CONTEXT_HANDLE,
155 (UsefulBufC) { &args->context_handle,
156 sizeof(args->context_handle) });
157 QCBOREncode_AddBoolToMapN(&encode_ctx,
158 DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT,
159 args->retain_parent_context);
160 QCBOREncode_AddBoolToMapN(&encode_ctx,
161 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE,
162 args->allow_new_context_to_derive);
163 QCBOREncode_AddBoolToMapN(&encode_ctx,
164 DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE,
165 args->create_certificate);
166 encode_dice_inputs(&encode_ctx, args->dice_inputs);
167 QCBOREncode_AddBytesToMapN(&encode_ctx,
168 DPE_DERIVE_CONTEXT_TARGET_LOCALITY,
169 (UsefulBufC) { &args->target_locality,
170 sizeof(args->target_locality) });
171 QCBOREncode_AddBoolToMapN(&encode_ctx,
172 DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE,
173 args->return_certificate);
174 QCBOREncode_AddBoolToMapN(&encode_ctx,
175 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT,
176 args->allow_new_context_to_export);
177 QCBOREncode_AddBoolToMapN(&encode_ctx,
178 DPE_DERIVE_CONTEXT_EXPORT_CDI,
179 args->export_cdi);
180 QCBOREncode_CloseMap(&encode_ctx);
181
182 QCBOREncode_CloseArray(&encode_ctx);
183
184 return QCBOREncode_Finish(&encode_ctx, encoded_buf);
185}
186
187static QCBORError decode_derive_context_response(UsefulBufC encoded_buf,
188 struct derive_context_output_t *args,
189 dpe_error_t *dpe_err)
190{
191 QCBORDecodeContext decode_ctx;
192 UsefulBufC out;
193 int64_t response_dpe_err;
194
195 QCBORDecode_Init(&decode_ctx, encoded_buf, QCBOR_DECODE_MODE_NORMAL);
196
197 QCBORDecode_EnterArray(&decode_ctx, NULL);
198
199 /* Get the error code from the response. DPE returns int32_t */
200 QCBORDecode_GetInt64(&decode_ctx, &response_dpe_err);
201 *dpe_err = (dpe_error_t)response_dpe_err;
202
203 /* Decode DeriveContext response if successful */
204 if (*dpe_err == DPE_NO_ERROR) {
205 QCBORDecode_EnterMap(&decode_ctx, NULL);
206
207 QCBORDecode_GetByteStringInMapN(&decode_ctx,
208 DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE,
209 &out);
210 if (out.len != sizeof(args->new_context_handle)) {
211 return QCBORDecode_Finish(&decode_ctx);
212 }
213 memcpy(&args->new_context_handle, out.ptr, out.len);
214
215 QCBORDecode_GetByteStringInMapN(&decode_ctx,
216 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE,
217 &out);
218 if (out.len != sizeof(args->new_parent_context_handle)) {
219 return QCBORDecode_Finish(&decode_ctx);
220 }
221 memcpy(&args->new_parent_context_handle, out.ptr, out.len);
222
223 QCBORDecode_GetByteStringInMapN(&decode_ctx,
224 DPE_DERIVE_CONTEXT_NEW_CERTIFICATE,
225 &out);
226 args->new_certificate = out.ptr;
227 args->new_certificate_size = out.len;
228
229 QCBORDecode_GetByteStringInMapN(&decode_ctx,
230 DPE_DERIVE_CONTEXT_EXPORTED_CDI,
231 &out);
232 args->exported_cdi = out.ptr;
233 args->exported_cdi_size = out.len;
234
235 QCBORDecode_ExitMap(&decode_ctx);
236 }
237
238 QCBORDecode_ExitArray(&decode_ctx);
239
240 return QCBORDecode_Finish(&decode_ctx);
241}
242
243static int32_t dpe_client_call(const char *cmd_input, size_t cmd_input_size,
244 char *cmd_output, size_t *cmd_output_size)
245{
246 int32_t err;
247
248 psa_invec in_vec[] = {
249 { cmd_input, cmd_input_size },
250 };
251 psa_outvec out_vec[] = {
252 { cmd_output, *cmd_output_size },
253 };
254
255 err = psa_call(RSS_DPE_SERVICE_HANDLE, 0,
256 in_vec, IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
257
258 if (err == PSA_SUCCESS) {
259 *cmd_output_size = out_vec[0].len;
260 }
261
262 return err;
263}
264
265dpe_error_t dpe_derive_context(int context_handle,
266 bool retain_parent_context,
267 bool allow_new_context_to_derive,
268 bool create_certificate,
269 const DiceInputValues *dice_inputs,
270 int32_t target_locality,
271 bool return_certificate,
272 bool allow_new_context_to_export,
273 bool export_cdi,
274 int *new_context_handle,
275 int *new_parent_context_handle,
276 uint8_t *new_certificate_buf,
277 size_t new_certificate_buf_size,
278 size_t *new_certificate_actual_size,
279 uint8_t *exported_cdi_buf,
280 size_t exported_cdi_buf_size,
281 size_t *exported_cdi_actual_size)
282{
283 int32_t service_err;
284 dpe_error_t dpe_err;
285 QCBORError qcbor_err;
286 UsefulBufC encoded_buf;
287 UsefulBuf_MAKE_STACK_UB(cmd_buf, 612);
288
289 const struct derive_context_input_t in_args = {
290 context_handle,
291 retain_parent_context,
292 allow_new_context_to_derive,
293 create_certificate,
294 dice_inputs,
295 target_locality,
296 return_certificate,
297 allow_new_context_to_export,
298 export_cdi,
299 };
300 struct derive_context_output_t out_args;
301
302 /*
303 * Validate the output params here because they are not sent to the
304 * service. Input params are validated by the DPE service.
305 */
306 if ((new_context_handle == NULL) ||
307 (retain_parent_context == true && new_parent_context_handle == NULL) ||
308 (return_certificate == true &&
309 (new_certificate_buf == NULL || new_certificate_actual_size == NULL)) ||
310 (export_cdi == true &&
311 (exported_cdi_buf == NULL || exported_cdi_actual_size == NULL))) {
312 return DPE_INVALID_ARGUMENT;
313 }
314
315 qcbor_err = encode_derive_context(&in_args, cmd_buf, &encoded_buf);
316 if (qcbor_err != QCBOR_SUCCESS) {
317 return DPE_INTERNAL_ERROR;
318 }
319
320 service_err = dpe_client_call(encoded_buf.ptr, encoded_buf.len,
321 cmd_buf.ptr, &cmd_buf.len);
322 if (service_err != 0) {
323 return DPE_INTERNAL_ERROR;
324 }
325
326 qcbor_err = decode_derive_context_response(UsefulBuf_Const(cmd_buf),
327 &out_args, &dpe_err);
328 if (qcbor_err != QCBOR_SUCCESS) {
329 return DPE_INTERNAL_ERROR;
330 } else if (dpe_err != DPE_NO_ERROR) {
331 return dpe_err;
332 }
333
334 /* Copy returned values into caller's memory */
335 *new_context_handle = out_args.new_context_handle;
336
337 if (retain_parent_context == true) {
338 *new_parent_context_handle = out_args.new_parent_context_handle;
339 }
340
341 if (return_certificate == true) {
342 if (out_args.new_certificate_size > new_certificate_buf_size) {
343 return DPE_INVALID_ARGUMENT;
344 }
345
346 memcpy(new_certificate_buf, out_args.new_certificate,
347 out_args.new_certificate_size);
348 *new_certificate_actual_size = out_args.new_certificate_size;
349 }
350
351 if (export_cdi == true) {
352 if (out_args.exported_cdi_size > exported_cdi_buf_size) {
353 return DPE_INVALID_ARGUMENT;
354 }
355
356 memcpy(exported_cdi_buf, out_args.exported_cdi,
357 out_args.exported_cdi_size);
358 *exported_cdi_actual_size = out_args.exported_cdi_size;
359 }
360
361 return DPE_NO_ERROR;
362}