xref: /optee_os/core/pta/veraison_attestation/cbor.c (revision 900bf7c6b0b2a2dc120a1286c5efa414974078f9)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2024, Institute of Information Security (IISEC)
4  */
5 
6 #include <compiler.h>
7 #include <kernel/pseudo_ta.h>
8 #include <mempool.h>
9 
10 #include "cbor.h"
11 #include "sign.h"
12 
13 struct cbor_evidence_args {
14 	UsefulBufC ubc_eat_profile;
15 	int psa_client_id;
16 	int psa_security_lifecycle;
17 	UsefulBufC ubc_psa_implementation_id;
18 	UsefulBufC ubc_measurement_type;
19 	UsefulBufC ubc_signer_id;
20 	UsefulBufC ubc_psa_instance_id;
21 	UsefulBufC ubc_psa_nonce;
22 	UsefulBufC ubc_measurement_value;
23 };
24 
25 struct cose_evidence_args {
26 	UsefulBufC ubc_cbor_evidence;
27 };
28 
29 struct tbs_structure_args {
30 	UsefulBufC protected_header;
31 	UsefulBufC aad;
32 	UsefulBufC payload;
33 };
34 
35 static void
encode_cbor_evidence(QCBOREncodeContext * context,UsefulBufC ubc_eat_profile,const int psa_client_id,const int psa_security_lifecycle,UsefulBufC ubc_psa_implementation_id,UsefulBufC ubc_measurement_type,UsefulBufC ubc_signer_id,UsefulBufC ubc_psa_instance_id,UsefulBufC ubc_psa_nonce,UsefulBufC ubc_measurement_value)36 encode_cbor_evidence(QCBOREncodeContext *context, UsefulBufC ubc_eat_profile,
37 		     const int psa_client_id, const int psa_security_lifecycle,
38 		     UsefulBufC ubc_psa_implementation_id,
39 		     UsefulBufC ubc_measurement_type, UsefulBufC ubc_signer_id,
40 		     UsefulBufC ubc_psa_instance_id, UsefulBufC ubc_psa_nonce,
41 		     UsefulBufC ubc_measurement_value)
42 {
43 	QCBOREncode_OpenMap(context);
44 
45 	/* Profile Definition */
46 	QCBOREncode_AddTextToMapN(context, PSA_PROFILE_DEFINITION,
47 				  ubc_eat_profile);
48 
49 	/* Client ID */
50 	QCBOREncode_AddInt64ToMapN(context, PSA_CLIENT_ID, psa_client_id);
51 
52 	/* Security Lifecycle */
53 	QCBOREncode_AddInt64ToMapN(context, PSA_SECURITY_LIFECYCLE,
54 				   psa_security_lifecycle);
55 
56 	/* Implementation ID */
57 	QCBOREncode_AddBytesToMapN(context, PSA_IMPLEMENTATION_ID,
58 				   ubc_psa_implementation_id);
59 
60 	/* Software Components */
61 	QCBOREncode_OpenArrayInMapN(context, PSA_SW_COMPONENTS); /* [ */
62 	QCBOREncode_OpenMap(context); /* { */
63 	QCBOREncode_AddTextToMapN(context, PSA_SW_COMPONENT_MEASUREMENT_TYPE,
64 				  ubc_measurement_type);
65 	QCBOREncode_AddBytesToMapN(context, PSA_SW_COMPONENT_MEASUREMENT_VALUE,
66 				   ubc_measurement_value);
67 	QCBOREncode_AddBytesToMapN(context, PSA_SW_COMPONENT_SIGNER_ID,
68 				   ubc_signer_id);
69 	QCBOREncode_CloseMap(context); /* } */
70 	QCBOREncode_CloseArray(context); /* ] */
71 
72 	/* Nonce */
73 	QCBOREncode_AddBytesToMapN(context, PSA_NONCE, ubc_psa_nonce);
74 
75 	/* Instance ID */
76 	QCBOREncode_AddBytesToMapN(context, PSA_INSTANCE_ID,
77 				   ubc_psa_instance_id);
78 
79 	QCBOREncode_CloseMap(context);
80 }
81 
82 /* Generic function for encoding and buffer allocation */
build_encoded_buffer(void (* encode_func)(QCBOREncodeContext *,void *),void * encode_args)83 static UsefulBufC build_encoded_buffer(void (*encode_func)(QCBOREncodeContext *,
84 							   void *),
85 				       void *encode_args)
86 {
87 	QCBOREncodeContext context = { };
88 	uint8_t *buffer = NULL;
89 	size_t required_size = 0;
90 	UsefulBufC encoded_data = { NULL, 0 };
91 
92 	/* First encode: calculate the required length */
93 	QCBOREncode_Init(&context, (UsefulBuf){ NULL, INT32_MAX });
94 	encode_func(&context, encode_args);
95 	if (QCBOREncode_FinishGetSize(&context, &required_size) !=
96 	    QCBOR_SUCCESS) {
97 		return NULLUsefulBufC;
98 	}
99 
100 	/* Allocate buffer for encoded data */
101 	buffer = mempool_alloc(mempool_default, required_size);
102 	if (!buffer) {
103 		DMSG("Failed to allocate buffer");
104 		return NULLUsefulBufC;
105 	}
106 
107 	/* Second encode: encode data */
108 	QCBOREncode_Init(&context, (UsefulBuf){ buffer, required_size });
109 	encode_func(&context, encode_args);
110 	if (QCBOREncode_Finish(&context, &encoded_data) != QCBOR_SUCCESS) {
111 		mempool_free(mempool_default, buffer);
112 		return NULLUsefulBufC;
113 	}
114 
115 	/* Verify the length of the encoded data */
116 	if (encoded_data.len != required_size) {
117 		DMSG("Unexpected length of encoded data");
118 		mempool_free(mempool_default, buffer);
119 		return NULLUsefulBufC;
120 	}
121 
122 	return encoded_data;
123 }
124 
encode_protected_header(QCBOREncodeContext * context)125 static void encode_protected_header(QCBOREncodeContext *context)
126 {
127 	QCBOREncode_OpenMap(context);
128 	QCBOREncode_AddInt64ToMapN(context, COSE_HEADER_PARAM_ALG,
129 				   COSE_ALGORITHM_ES256);
130 	QCBOREncode_CloseMap(context);
131 }
132 
encode_protected_header_wrapper(QCBOREncodeContext * context,void * args __unused)133 static void encode_protected_header_wrapper(QCBOREncodeContext *context,
134 					    void *args __unused)
135 {
136 	encode_protected_header(context);
137 }
138 
139 /*
140  * Format of to-be-signed bytes. This is defined in COSE (RFC 8152)
141  * section 4.4. It is the input to the hash.
142  *
143  * Sig_structure = [
144  *    context : "Signature1",
145  *    body_protected : empty_or_serialized_map,
146  *    external_aad : bstr,
147  *    payload : bstr
148  * ]
149  *
150  * body_protected refers to the protected parameters from the main
151  * COSE_Sign1 structure.
152  */
encode_tbs_structure(QCBOREncodeContext * context,UsefulBufC protected_header,UsefulBufC aad,UsefulBufC payload)153 static void encode_tbs_structure(QCBOREncodeContext *context,
154 				 UsefulBufC protected_header, UsefulBufC aad,
155 				 UsefulBufC payload)
156 {
157 	QCBOREncode_OpenArray(context);
158 	QCBOREncode_AddSZString(context, COSE_SIG_CONTEXT_STRING_SIGNATURE1);
159 	QCBOREncode_AddBytes(context, protected_header);
160 	QCBOREncode_AddBytes(context, aad);
161 	QCBOREncode_AddBytes(context, payload);
162 	QCBOREncode_CloseArray(context);
163 }
164 
encode_tbs_structure_wrapper(QCBOREncodeContext * context,void * args)165 static void encode_tbs_structure_wrapper(QCBOREncodeContext *context,
166 					 void *args)
167 {
168 	struct tbs_structure_args *tbs_args =
169 		(struct tbs_structure_args *)args;
170 
171 	encode_tbs_structure(context, tbs_args->protected_header, tbs_args->aad,
172 			     tbs_args->payload);
173 }
174 
build_protected_header(void)175 static UsefulBufC build_protected_header(void)
176 {
177 	return build_encoded_buffer(encode_protected_header_wrapper, NULL);
178 }
179 
build_tbs_structure(UsefulBufC protected_header,UsefulBufC aad,UsefulBufC payload)180 static UsefulBufC build_tbs_structure(UsefulBufC protected_header,
181 				      UsefulBufC aad, UsefulBufC payload)
182 {
183 	struct tbs_structure_args args = {
184 		.protected_header = protected_header,
185 		.aad = aad,
186 		.payload = payload,
187 	};
188 
189 	return build_encoded_buffer(encode_tbs_structure_wrapper, &args);
190 }
191 
encode_cose_evidence(QCBOREncodeContext * context,UsefulBufC ubc_cbor_evidence)192 static void encode_cose_evidence(QCBOREncodeContext *context,
193 				 UsefulBufC ubc_cbor_evidence)
194 {
195 	UsefulBufC protected_header = { NULL, 0 };
196 	UsefulBufC tbs_payload = { NULL, 0 };
197 	uint8_t signature[64] = { };
198 	size_t signature_len = 64;
199 	UsefulBufC signature_payload = { signature, signature_len };
200 
201 	/* Add top level array for COSE_Sign1 */
202 	QCBOREncode_AddTag(context, CBOR_TAG_COSE_SIGN1);
203 	QCBOREncode_OpenArray(context);
204 
205 	/* Encode protected header */
206 	protected_header = build_protected_header();
207 	if (UsefulBuf_IsNULLC(protected_header)) {
208 		DMSG("Failed to encode protected header payload");
209 		return;
210 	}
211 
212 	/* Add protected header */
213 	QCBOREncode_AddBytes(context, protected_header);
214 
215 	/* Add unprotected header (empty map) */
216 	QCBOREncode_OpenMap(context);
217 	QCBOREncode_CloseMap(context);
218 
219 	/* Add the payload (evidence CBOR) */
220 	QCBOREncode_AddBytes(context, ubc_cbor_evidence);
221 
222 	/* Encode "To Be Signed" payload */
223 	tbs_payload = build_tbs_structure(protected_header, NULLUsefulBufC,
224 					  ubc_cbor_evidence);
225 	if (UsefulBuf_IsNULLC(tbs_payload)) {
226 		DMSG("Failed to encode to-be-signed payload");
227 		mempool_free(mempool_default, (void *)protected_header.ptr);
228 		return;
229 	}
230 
231 	/* Calculate a signature and add the signature to payload */
232 	if (sign_ecdsa_sha256(tbs_payload.ptr, tbs_payload.len, signature,
233 			      &signature_len) != TEE_SUCCESS) {
234 		DMSG("Failed to sign payload");
235 		mempool_free(mempool_default, (void *)protected_header.ptr);
236 		mempool_free(mempool_default, (void *)tbs_payload.ptr);
237 		return;
238 	}
239 
240 	/* Add the signature */
241 	QCBOREncode_AddBytes(context, signature_payload);
242 
243 	/* Close top level array for COSE_Sign1 */
244 	QCBOREncode_CloseArray(context);
245 }
246 
encode_cbor_evidence_wrapper(QCBOREncodeContext * context,void * args)247 static void encode_cbor_evidence_wrapper(QCBOREncodeContext *context,
248 					 void *args)
249 {
250 	struct cbor_evidence_args *evidence_args =
251 		(struct cbor_evidence_args *)args;
252 
253 	encode_cbor_evidence(context, evidence_args->ubc_eat_profile,
254 			     evidence_args->psa_client_id,
255 			     evidence_args->psa_security_lifecycle,
256 			     evidence_args->ubc_psa_implementation_id,
257 			     evidence_args->ubc_measurement_type,
258 			     evidence_args->ubc_signer_id,
259 			     evidence_args->ubc_psa_instance_id,
260 			     evidence_args->ubc_psa_nonce,
261 			     evidence_args->ubc_measurement_value);
262 }
263 
encode_cose_evidence_wrapper(QCBOREncodeContext * context,void * args)264 static void encode_cose_evidence_wrapper(QCBOREncodeContext *context,
265 					 void *args)
266 {
267 	struct cose_evidence_args *cose_args =
268 		(struct cose_evidence_args *)args;
269 
270 	encode_cose_evidence(context, cose_args->ubc_cbor_evidence);
271 }
272 
273 static UsefulBufC
build_cbor_evidence(UsefulBufC ubc_eat_profile,int psa_client_id,int psa_security_lifecycle,UsefulBufC ubc_psa_implementation_id,UsefulBufC ubc_measurement_type,UsefulBufC ubc_signer_id,UsefulBufC ubc_psa_instance_id,UsefulBufC ubc_psa_nonce,UsefulBufC ubc_measurement_value)274 build_cbor_evidence(UsefulBufC ubc_eat_profile, int psa_client_id,
275 		    int psa_security_lifecycle,
276 		    UsefulBufC ubc_psa_implementation_id,
277 		    UsefulBufC ubc_measurement_type, UsefulBufC ubc_signer_id,
278 		    UsefulBufC ubc_psa_instance_id, UsefulBufC ubc_psa_nonce,
279 		    UsefulBufC ubc_measurement_value)
280 {
281 	struct cbor_evidence_args args = {
282 		.ubc_eat_profile = ubc_eat_profile,
283 		.psa_client_id = psa_client_id,
284 		.psa_security_lifecycle = psa_security_lifecycle,
285 		.ubc_psa_implementation_id = ubc_psa_implementation_id,
286 		.ubc_measurement_type = ubc_measurement_type,
287 		.ubc_signer_id = ubc_signer_id,
288 		.ubc_psa_instance_id = ubc_psa_instance_id,
289 		.ubc_psa_nonce = ubc_psa_nonce,
290 		.ubc_measurement_value = ubc_measurement_value,
291 	};
292 
293 	return build_encoded_buffer(encode_cbor_evidence_wrapper, &args);
294 }
295 
build_cose_evidence(UsefulBufC ubc_cbor_evidence)296 static UsefulBufC build_cose_evidence(UsefulBufC ubc_cbor_evidence)
297 {
298 	struct cose_evidence_args args = {
299 		.ubc_cbor_evidence = ubc_cbor_evidence,
300 	};
301 
302 	return build_encoded_buffer(encode_cose_evidence_wrapper, &args);
303 }
304 
generate_cbor_evidence(const char * eat_profile,int psa_client_id,int psa_security_lifecycle,const uint8_t * psa_implementation_id,size_t psa_implementation_id_len,const char * measurement_type,const uint8_t * signer_id,size_t signer_id_len,const uint8_t * psa_instance_id,size_t psa_instance_id_len,const uint8_t * psa_nonce,size_t psa_nonce_len,const uint8_t * measurement_value,size_t measurement_value_len)305 UsefulBufC generate_cbor_evidence(const char *eat_profile,
306 				  int psa_client_id,
307 				  int psa_security_lifecycle,
308 				  const uint8_t *psa_implementation_id,
309 				  size_t psa_implementation_id_len,
310 				  const char *measurement_type,
311 				  const uint8_t *signer_id,
312 				  size_t signer_id_len,
313 				  const uint8_t *psa_instance_id,
314 				  size_t psa_instance_id_len,
315 				  const uint8_t *psa_nonce,
316 				  size_t psa_nonce_len,
317 				  const uint8_t *measurement_value,
318 				  size_t measurement_value_len)
319 {
320 	/* prepare usefulbufs because qcbor only accepts them */
321 	UsefulBufC ubc_eat_profile = UsefulBuf_FromSZ(eat_profile);
322 	UsefulBufC ubc_psa_implementation_id = { psa_implementation_id,
323 						 psa_implementation_id_len };
324 	UsefulBufC ubc_measurement_type = UsefulBuf_FromSZ(measurement_type);
325 	UsefulBufC ubc_signer_id = { signer_id, signer_id_len };
326 	UsefulBufC ubc_psa_instance_id = { psa_instance_id,
327 					   psa_instance_id_len };
328 	UsefulBufC ubc_psa_nonce = { psa_nonce, psa_nonce_len };
329 	UsefulBufC ubc_measurement_value = { measurement_value,
330 					     measurement_value_len };
331 
332 	return build_cbor_evidence(ubc_eat_profile,
333 				   psa_client_id,
334 				   psa_security_lifecycle,
335 				   ubc_psa_implementation_id,
336 				   ubc_measurement_type,
337 				   ubc_signer_id,
338 				   ubc_psa_instance_id,
339 				   ubc_psa_nonce,
340 				   ubc_measurement_value);
341 }
342 
generate_cose_evidence(UsefulBufC ubc_cbor_evidence)343 UsefulBufC generate_cose_evidence(UsefulBufC ubc_cbor_evidence)
344 {
345 	return build_cose_evidence(ubc_cbor_evidence);
346 }
347