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