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 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 */ 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 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 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 */ 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 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 175 static UsefulBufC build_protected_header(void) 176 { 177 return build_encoded_buffer(encode_protected_header_wrapper, NULL); 178 } 179 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 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 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 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 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 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 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 343 UsefulBufC generate_cose_evidence(UsefulBufC ubc_cbor_evidence) 344 { 345 return build_cose_evidence(ubc_cbor_evidence); 346 } 347