1 /*
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 
18 enum 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 
37 enum 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 
49 enum 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 	/* enum values 256 and onwards are reserved for custom arguments */
62 	DPE_DERIVE_CONTEXT_CERT_ID = 256,
63 };
64 
65 enum 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 
73 struct derive_context_input_t {
74 	int context_handle;
75 	uint32_t cert_id;
76 	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 
86 struct 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 
encode_dice_inputs(QCBOREncodeContext * encode_ctx,const DiceInputValues * input)95 static 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 
encode_derive_context(const struct derive_context_input_t * args,UsefulBuf buf,UsefulBufC * encoded_buf)143 static 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) });
160 	QCBOREncode_AddUInt64ToMapN(&encode_ctx,
161 				    DPE_DERIVE_CONTEXT_CERT_ID,
162 				    args->cert_id);
163 	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 
decode_derive_context_response(UsefulBufC encoded_buf,struct derive_context_output_t * args,dpe_error_t * dpe_err)193 static 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 
dpe_client_call(const char * cmd_input,size_t cmd_input_size,char * cmd_output,size_t * cmd_output_size)249 static 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(RSE_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 
dpe_derive_context(int context_handle,uint32_t cert_id,bool retain_parent_context,bool allow_new_context_to_derive,bool create_certificate,const DiceInputValues * dice_inputs,int32_t target_locality,bool return_certificate,bool allow_new_context_to_export,bool export_cdi,int * new_context_handle,int * new_parent_context_handle,uint8_t * new_certificate_buf,size_t new_certificate_buf_size,size_t * new_certificate_actual_size,uint8_t * exported_cdi_buf,size_t exported_cdi_buf_size,size_t * exported_cdi_actual_size)271 dpe_error_t dpe_derive_context(int context_handle,
272 			       uint32_t cert_id,
273 			       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,
298 		cert_id,
299 		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 }
371