blob: 44a58482c6d07add052cb808b14009d9045569c5 [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,
Tamas Band571d6e2024-01-30 10:22:29 +010061 /* enum values 256 and onwards are reserved for custom arguments */
62 DPE_DERIVE_CONTEXT_CERT_ID = 256,
Tamas Banfb6237e2023-06-06 13:41:14 +020063};
64
65enum dpe_derive_context_output_labels_t {
66 DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE = 1,
67 DPE_DERIVE_CONTEXT_NEW_SESSION_RESPONDER_HANDSHAKE = 2,
68 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE = 3,
69 DPE_DERIVE_CONTEXT_NEW_CERTIFICATE = 4,
70 DPE_DERIVE_CONTEXT_EXPORTED_CDI = 5,
71};
72
73struct derive_context_input_t {
74 int context_handle;
Tamas Band571d6e2024-01-30 10:22:29 +010075 uint32_t cert_id;
Tamas Banfb6237e2023-06-06 13:41:14 +020076 bool retain_parent_context;
77 bool allow_new_context_to_derive;
78 bool create_certificate;
79 const DiceInputValues *dice_inputs;
80 int32_t target_locality;
81 bool return_certificate;
82 bool allow_new_context_to_export;
83 bool export_cdi;
84};
85
86struct derive_context_output_t {
87 int new_context_handle;
88 int new_parent_context_handle;
89 const uint8_t *new_certificate;
90 size_t new_certificate_size;
91 const uint8_t *exported_cdi;
92 size_t exported_cdi_size;
93};
94
95static void encode_dice_inputs(QCBOREncodeContext *encode_ctx,
96 const DiceInputValues *input)
97{
98 /* Wrap the DICE inputs into a byte string */
99 QCBOREncode_BstrWrapInMapN(encode_ctx, DPE_DERIVE_CONTEXT_INPUT_DATA);
100
101 /* Inside the byte string the DICE inputs are encoded as a map */
102 QCBOREncode_OpenMap(encode_ctx);
103
104 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CODE_HASH,
105 (UsefulBufC) { input->code_hash,
106 sizeof(input->code_hash) });
107
108 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CODE_DESCRIPTOR,
109 (UsefulBufC) { input->code_descriptor,
110 input->code_descriptor_size });
111
112 QCBOREncode_AddInt64ToMapN(encode_ctx, DICE_CONFIG_TYPE,
113 input->config_type);
114
115 if (input->config_type == kDiceConfigTypeInline) {
116 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CONFIG_VALUE,
117 (UsefulBufC) { input->config_value,
118 sizeof(input->config_value) });
119 } else {
120 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CONFIG_DESCRIPTOR,
121 (UsefulBufC) { input->config_descriptor,
122 input->config_descriptor_size });
123 }
124
125 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_AUTHORITY_HASH,
126 (UsefulBufC) { input->authority_hash,
127 sizeof(input->authority_hash) });
128
129 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_AUTHORITY_DESCRIPTOR,
130 (UsefulBufC) { input->authority_descriptor,
131 input->authority_descriptor_size });
132
133 QCBOREncode_AddInt64ToMapN(encode_ctx, DICE_MODE, input->mode);
134
135 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_HIDDEN,
136 (UsefulBufC) { input->hidden,
137 sizeof(input->hidden) });
138
139 QCBOREncode_CloseMap(encode_ctx);
140 QCBOREncode_CloseBstrWrap2(encode_ctx, true, NULL);
141}
142
143static QCBORError encode_derive_context(const struct derive_context_input_t *args,
144 UsefulBuf buf,
145 UsefulBufC *encoded_buf)
146{
147 QCBOREncodeContext encode_ctx;
148
149 QCBOREncode_Init(&encode_ctx, buf);
150
151 QCBOREncode_OpenArray(&encode_ctx);
152 QCBOREncode_AddUInt64(&encode_ctx, DPE_DERIVE_CONTEXT);
153
154 /* Encode DeriveContext command */
155 QCBOREncode_OpenMap(&encode_ctx);
156 QCBOREncode_AddBytesToMapN(&encode_ctx,
157 DPE_DERIVE_CONTEXT_CONTEXT_HANDLE,
158 (UsefulBufC) { &args->context_handle,
159 sizeof(args->context_handle) });
Tamas Band571d6e2024-01-30 10:22:29 +0100160 QCBOREncode_AddUInt64ToMapN(&encode_ctx,
161 DPE_DERIVE_CONTEXT_CERT_ID,
162 args->cert_id);
Tamas Banfb6237e2023-06-06 13:41:14 +0200163 QCBOREncode_AddBoolToMapN(&encode_ctx,
164 DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT,
165 args->retain_parent_context);
166 QCBOREncode_AddBoolToMapN(&encode_ctx,
167 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE,
168 args->allow_new_context_to_derive);
169 QCBOREncode_AddBoolToMapN(&encode_ctx,
170 DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE,
171 args->create_certificate);
172 encode_dice_inputs(&encode_ctx, args->dice_inputs);
173 QCBOREncode_AddBytesToMapN(&encode_ctx,
174 DPE_DERIVE_CONTEXT_TARGET_LOCALITY,
175 (UsefulBufC) { &args->target_locality,
176 sizeof(args->target_locality) });
177 QCBOREncode_AddBoolToMapN(&encode_ctx,
178 DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE,
179 args->return_certificate);
180 QCBOREncode_AddBoolToMapN(&encode_ctx,
181 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT,
182 args->allow_new_context_to_export);
183 QCBOREncode_AddBoolToMapN(&encode_ctx,
184 DPE_DERIVE_CONTEXT_EXPORT_CDI,
185 args->export_cdi);
186 QCBOREncode_CloseMap(&encode_ctx);
187
188 QCBOREncode_CloseArray(&encode_ctx);
189
190 return QCBOREncode_Finish(&encode_ctx, encoded_buf);
191}
192
193static QCBORError decode_derive_context_response(UsefulBufC encoded_buf,
194 struct derive_context_output_t *args,
195 dpe_error_t *dpe_err)
196{
197 QCBORDecodeContext decode_ctx;
198 UsefulBufC out;
199 int64_t response_dpe_err;
200
201 QCBORDecode_Init(&decode_ctx, encoded_buf, QCBOR_DECODE_MODE_NORMAL);
202
203 QCBORDecode_EnterArray(&decode_ctx, NULL);
204
205 /* Get the error code from the response. DPE returns int32_t */
206 QCBORDecode_GetInt64(&decode_ctx, &response_dpe_err);
207 *dpe_err = (dpe_error_t)response_dpe_err;
208
209 /* Decode DeriveContext response if successful */
210 if (*dpe_err == DPE_NO_ERROR) {
211 QCBORDecode_EnterMap(&decode_ctx, NULL);
212
213 QCBORDecode_GetByteStringInMapN(&decode_ctx,
214 DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE,
215 &out);
216 if (out.len != sizeof(args->new_context_handle)) {
217 return QCBORDecode_Finish(&decode_ctx);
218 }
219 memcpy(&args->new_context_handle, out.ptr, out.len);
220
221 QCBORDecode_GetByteStringInMapN(&decode_ctx,
222 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE,
223 &out);
224 if (out.len != sizeof(args->new_parent_context_handle)) {
225 return QCBORDecode_Finish(&decode_ctx);
226 }
227 memcpy(&args->new_parent_context_handle, out.ptr, out.len);
228
229 QCBORDecode_GetByteStringInMapN(&decode_ctx,
230 DPE_DERIVE_CONTEXT_NEW_CERTIFICATE,
231 &out);
232 args->new_certificate = out.ptr;
233 args->new_certificate_size = out.len;
234
235 QCBORDecode_GetByteStringInMapN(&decode_ctx,
236 DPE_DERIVE_CONTEXT_EXPORTED_CDI,
237 &out);
238 args->exported_cdi = out.ptr;
239 args->exported_cdi_size = out.len;
240
241 QCBORDecode_ExitMap(&decode_ctx);
242 }
243
244 QCBORDecode_ExitArray(&decode_ctx);
245
246 return QCBORDecode_Finish(&decode_ctx);
247}
248
249static int32_t dpe_client_call(const char *cmd_input, size_t cmd_input_size,
250 char *cmd_output, size_t *cmd_output_size)
251{
252 int32_t err;
253
254 psa_invec in_vec[] = {
255 { cmd_input, cmd_input_size },
256 };
257 psa_outvec out_vec[] = {
258 { cmd_output, *cmd_output_size },
259 };
260
261 err = psa_call(RSS_DPE_SERVICE_HANDLE, 0,
262 in_vec, IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
263
264 if (err == PSA_SUCCESS) {
265 *cmd_output_size = out_vec[0].len;
266 }
267
268 return err;
269}
270
271dpe_error_t dpe_derive_context(int context_handle,
Tamas Band571d6e2024-01-30 10:22:29 +0100272 uint32_t cert_id,
Tamas Banfb6237e2023-06-06 13:41:14 +0200273 bool retain_parent_context,
274 bool allow_new_context_to_derive,
275 bool create_certificate,
276 const DiceInputValues *dice_inputs,
277 int32_t target_locality,
278 bool return_certificate,
279 bool allow_new_context_to_export,
280 bool export_cdi,
281 int *new_context_handle,
282 int *new_parent_context_handle,
283 uint8_t *new_certificate_buf,
284 size_t new_certificate_buf_size,
285 size_t *new_certificate_actual_size,
286 uint8_t *exported_cdi_buf,
287 size_t exported_cdi_buf_size,
288 size_t *exported_cdi_actual_size)
289{
290 int32_t service_err;
291 dpe_error_t dpe_err;
292 QCBORError qcbor_err;
293 UsefulBufC encoded_buf;
294 UsefulBuf_MAKE_STACK_UB(cmd_buf, 612);
295
296 const struct derive_context_input_t in_args = {
297 context_handle,
Tamas Band571d6e2024-01-30 10:22:29 +0100298 cert_id,
Tamas Banfb6237e2023-06-06 13:41:14 +0200299 retain_parent_context,
300 allow_new_context_to_derive,
301 create_certificate,
302 dice_inputs,
303 target_locality,
304 return_certificate,
305 allow_new_context_to_export,
306 export_cdi,
307 };
308 struct derive_context_output_t out_args;
309
310 /*
311 * Validate the output params here because they are not sent to the
312 * service. Input params are validated by the DPE service.
313 */
314 if ((new_context_handle == NULL) ||
315 (retain_parent_context == true && new_parent_context_handle == NULL) ||
316 (return_certificate == true &&
317 (new_certificate_buf == NULL || new_certificate_actual_size == NULL)) ||
318 (export_cdi == true &&
319 (exported_cdi_buf == NULL || exported_cdi_actual_size == NULL))) {
320 return DPE_INVALID_ARGUMENT;
321 }
322
323 qcbor_err = encode_derive_context(&in_args, cmd_buf, &encoded_buf);
324 if (qcbor_err != QCBOR_SUCCESS) {
325 return DPE_INTERNAL_ERROR;
326 }
327
328 service_err = dpe_client_call(encoded_buf.ptr, encoded_buf.len,
329 cmd_buf.ptr, &cmd_buf.len);
330 if (service_err != 0) {
331 return DPE_INTERNAL_ERROR;
332 }
333
334 qcbor_err = decode_derive_context_response(UsefulBuf_Const(cmd_buf),
335 &out_args, &dpe_err);
336 if (qcbor_err != QCBOR_SUCCESS) {
337 return DPE_INTERNAL_ERROR;
338 } else if (dpe_err != DPE_NO_ERROR) {
339 return dpe_err;
340 }
341
342 /* Copy returned values into caller's memory */
343 *new_context_handle = out_args.new_context_handle;
344
345 if (retain_parent_context == true) {
346 *new_parent_context_handle = out_args.new_parent_context_handle;
347 }
348
349 if (return_certificate == true) {
350 if (out_args.new_certificate_size > new_certificate_buf_size) {
351 return DPE_INVALID_ARGUMENT;
352 }
353
354 memcpy(new_certificate_buf, out_args.new_certificate,
355 out_args.new_certificate_size);
356 *new_certificate_actual_size = out_args.new_certificate_size;
357 }
358
359 if (export_cdi == true) {
360 if (out_args.exported_cdi_size > exported_cdi_buf_size) {
361 return DPE_INVALID_ARGUMENT;
362 }
363
364 memcpy(exported_cdi_buf, out_args.exported_cdi,
365 out_args.exported_cdi_size);
366 *exported_cdi_actual_size = out_args.exported_cdi_size;
367 }
368
369 return DPE_NO_ERROR;
370}