Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 1 | /* |
| 2 | * SPDX-License-Identifier: BSD-3-Clause |
| 3 | * SPDX-FileCopyrightText: Copyright Laurence Lundblade. |
| 4 | * SPDX-FileCopyrightText: Copyright TF-RMM Contributors. |
| 5 | */ |
| 6 | |
| 7 | /* |
| 8 | * This file is derived from: |
| 9 | * trusted-firmware-m/secure_fw/partitions/initial_attestation/attest_token_encode.c |
| 10 | */ |
| 11 | |
| 12 | #include <assert.h> |
| 13 | #include <attestation.h> |
| 14 | #include <attestation_defs_priv.h> |
| 15 | #include <attestation_priv.h> |
| 16 | #include <attestation_token.h> |
| 17 | #include <debug.h> |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 18 | #include <measurement.h> |
| 19 | #include <qcbor/qcbor.h> |
Arunachalam Ganapathy | f649121 | 2023-02-23 16:04:34 +0000 | [diff] [blame] | 20 | #include <simd.h> |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 21 | #include <t_cose/q_useful_buf.h> |
| 22 | #include <t_cose/t_cose_common.h> |
| 23 | #include <t_cose/t_cose_sign1_sign.h> |
| 24 | #include <utils_def.h> |
| 25 | |
| 26 | /* |
| 27 | * According to IANA hash algorithm registry: |
| 28 | * - https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml |
| 29 | */ |
AlexeiFedorov | 56e1a8e | 2023-09-01 17:06:13 +0100 | [diff] [blame] | 30 | static void attest_get_hash_algo_text(enum hash_algo algorithm, |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 31 | struct q_useful_buf_c *algo_text) |
| 32 | { |
| 33 | const char *sha256 = "sha-256"; |
| 34 | const char *sha512 = "sha-512"; |
| 35 | |
AlexeiFedorov | 56e1a8e | 2023-09-01 17:06:13 +0100 | [diff] [blame] | 36 | switch (algorithm) { |
AlexeiFedorov | 4fc3b15 | 2023-06-13 12:08:01 +0100 | [diff] [blame] | 37 | case HASH_SHA_256: |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 38 | *algo_text = UsefulBuf_FromSZ(sha256); |
| 39 | break; |
AlexeiFedorov | 4fc3b15 | 2023-06-13 12:08:01 +0100 | [diff] [blame] | 40 | case HASH_SHA_512: |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 41 | *algo_text = UsefulBuf_FromSZ(sha512); |
| 42 | break; |
| 43 | default: |
| 44 | assert(false); |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | /* |
| 49 | * Outline of token creation. Much of this occurs inside |
| 50 | * t_cose_sign1_encode_parameters() and t_cose_sign1_encode_signature(). |
| 51 | * |
| 52 | * - Create encoder context |
| 53 | * - Open the CBOR array that hold the COSE_Sign1 |
| 54 | * - Write COSE Headers |
| 55 | * - Protected Header |
| 56 | * - Algorithm ID |
| 57 | * - Unprotected Headers |
| 58 | * - Key ID |
| 59 | * - Open payload bstr |
| 60 | * - Write payload data, maybe lots of it |
| 61 | * - Get bstr that is the encoded payload |
| 62 | * - Compute signature |
| 63 | * - Create a separate encoder context for Sig_structure |
| 64 | * - Encode CBOR context identifier |
| 65 | * - Encode protected headers |
| 66 | * - Encode two empty bstr |
| 67 | * - Add one more empty bstr that is a "fake payload" |
| 68 | * - Close off Sig_structure |
| 69 | * - Hash all but "fake payload" of Sig_structure |
| 70 | * - Get payload bstr ptr and length |
| 71 | * - Continue hash of the real encoded payload |
| 72 | * - Run ECDSA |
| 73 | * - Write signature into the CBOR output |
| 74 | * - Close CBOR array holding the COSE_Sign1 |
| 75 | */ |
| 76 | static enum attest_token_err_t |
| 77 | attest_token_encode_start(struct attest_token_encode_ctx *me, |
| 78 | uint32_t opt_flags, |
| 79 | int32_t key_select, |
| 80 | int32_t cose_alg_id, |
| 81 | const struct q_useful_buf *out_buf) |
| 82 | { |
| 83 | enum t_cose_err_t cose_res; |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 84 | struct t_cose_key attest_key; |
Mate Toth-Pal | c69951d | 2023-03-17 17:30:50 +0100 | [diff] [blame] | 85 | psa_key_handle_t key_handle; |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 86 | |
| 87 | assert(me != NULL); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 88 | |
| 89 | /* Remember some of the configuration values */ |
| 90 | me->opt_flags = opt_flags; |
| 91 | me->key_select = key_select; |
| 92 | |
Mate Toth-Pal | fda673a | 2023-06-13 12:25:43 +0200 | [diff] [blame] | 93 | t_cose_signature_sign_restart_init(&me->restartable_signer_ctx, cose_alg_id); |
| 94 | t_cose_signature_sign_restart_set_crypto_context(&me->restartable_signer_ctx, &(me->crypto_ctx)); |
| 95 | t_cose_sign_sign_init(&me->sign_ctx, T_COSE_OPT_MESSAGE_TYPE_SIGN1); |
| 96 | t_cose_sign_add_signer(&me->sign_ctx, t_cose_signature_sign_from_restart(&me->restartable_signer_ctx)); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 97 | |
| 98 | |
| 99 | /* |
| 100 | * Get the reference to `mbedtls_ecp_keypair` and set it to t_cose. |
| 101 | */ |
AlexeiFedorov | f4e37b3 | 2023-08-24 13:20:09 +0100 | [diff] [blame] | 102 | if (attest_get_realm_signing_key(&key_handle) != 0) { |
| 103 | return ATTEST_TOKEN_ERR_SIGNING_KEY; |
| 104 | } |
| 105 | |
Mate Toth-Pal | c69951d | 2023-03-17 17:30:50 +0100 | [diff] [blame] | 106 | attest_key.key.handle = key_handle; |
Mate Toth-Pal | fda673a | 2023-06-13 12:25:43 +0200 | [diff] [blame] | 107 | |
| 108 | t_cose_signature_sign_restart_set_signing_key(&me->restartable_signer_ctx, attest_key); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 109 | |
| 110 | /* Spin up the CBOR encoder */ |
| 111 | QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf); |
| 112 | |
| 113 | /* |
| 114 | * This will cause the cose headers to be encoded and written into |
| 115 | * out_buf using me->cbor_enc_ctx |
| 116 | */ |
Mate Toth-Pal | fda673a | 2023-06-13 12:25:43 +0200 | [diff] [blame] | 117 | cose_res = t_cose_sign_encode_start(&me->sign_ctx, &me->cbor_enc_ctx); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 118 | |
| 119 | if (cose_res != T_COSE_SUCCESS) { |
| 120 | return ATTEST_TOKEN_ERR_COSE_ERROR; |
| 121 | } |
| 122 | |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 123 | return ATTEST_TOKEN_ERR_SUCCESS; |
| 124 | } |
| 125 | |
| 126 | enum attest_token_err_t |
| 127 | attest_realm_token_sign(struct attest_token_encode_ctx *me, |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 128 | size_t *completed_token_len) |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 129 | { |
| 130 | /* The completed and signed encoded cose_sign1 */ |
| 131 | struct q_useful_buf_c completed_token_ub; |
| 132 | enum attest_token_err_t attest_res = ATTEST_TOKEN_ERR_SUCCESS; |
| 133 | QCBORError qcbor_res; |
| 134 | enum t_cose_err_t cose_res; |
| 135 | |
| 136 | assert(me != NULL); |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 137 | assert(completed_token_len != NULL); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 138 | |
| 139 | /* Finish up the COSE_Sign1. This is where the signing happens */ |
Arunachalam Ganapathy | 5111993 | 2023-03-23 12:32:49 +0000 | [diff] [blame] | 140 | SIMD_FPU_ALLOW( |
Mate Toth-Pal | fda673a | 2023-06-13 12:25:43 +0200 | [diff] [blame] | 141 | cose_res = t_cose_sign_encode_finish(&me->sign_ctx, |
| 142 | NULL_Q_USEFUL_BUF_C, |
| 143 | me->signed_payload, |
| 144 | &me->cbor_enc_ctx)); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 145 | |
| 146 | if (cose_res == T_COSE_ERR_SIG_IN_PROGRESS) { |
| 147 | /* Token signing has not yet finished */ |
| 148 | return ATTEST_TOKEN_ERR_COSE_SIGN_IN_PROGRESS; |
| 149 | } |
| 150 | |
| 151 | if (cose_res != T_COSE_SUCCESS) { |
| 152 | /* Main errors are invoking the hash or signature */ |
| 153 | return ATTEST_TOKEN_ERR_COSE_ERROR; |
| 154 | } |
| 155 | |
| 156 | /* |
| 157 | * Finally close off the CBOR formatting and get the pointer and length |
| 158 | * of the resulting COSE_Sign1 |
| 159 | */ |
| 160 | qcbor_res = QCBOREncode_Finish(&(me->cbor_enc_ctx), |
| 161 | &completed_token_ub); |
| 162 | |
| 163 | switch (qcbor_res) { |
| 164 | case QCBOR_ERR_BUFFER_TOO_SMALL: |
| 165 | attest_res = ATTEST_TOKEN_ERR_TOO_SMALL; |
| 166 | break; |
| 167 | case QCBOR_SUCCESS: |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 168 | *completed_token_len = completed_token_ub.len; |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 169 | break; |
| 170 | default: |
| 171 | /* likely from array not closed, too many closes ... */ |
| 172 | attest_res = ATTEST_TOKEN_ERR_CBOR_FORMATTING; |
| 173 | } |
| 174 | |
| 175 | return attest_res; |
| 176 | } |
| 177 | |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 178 | size_t attest_cca_token_create(void *attest_token_buf, |
| 179 | size_t attest_token_buf_size, |
| 180 | const void *realm_token_buf, |
| 181 | size_t realm_token_len) |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 182 | { |
| 183 | struct q_useful_buf_c completed_token; |
| 184 | QCBOREncodeContext cbor_enc_ctx; |
| 185 | QCBORError qcbor_res; |
AlexeiFedorov | f4e37b3 | 2023-08-24 13:20:09 +0100 | [diff] [blame] | 186 | struct q_useful_buf_c platform_token; |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 187 | struct q_useful_buf attest_token_ub = {attest_token_buf, attest_token_buf_size}; |
| 188 | struct q_useful_buf_c realm_token_ub = {realm_token_buf, realm_token_len}; |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 189 | |
| 190 | __unused int ret; |
| 191 | |
| 192 | /* Get the platform token */ |
AlexeiFedorov | f4e37b3 | 2023-08-24 13:20:09 +0100 | [diff] [blame] | 193 | ret = attest_get_platform_token(&platform_token.ptr, |
| 194 | &platform_token.len); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 195 | assert(ret == 0); |
| 196 | |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 197 | QCBOREncode_Init(&cbor_enc_ctx, attest_token_ub); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 198 | |
| 199 | QCBOREncode_AddTag(&cbor_enc_ctx, TAG_CCA_TOKEN); |
| 200 | |
| 201 | QCBOREncode_OpenMap(&cbor_enc_ctx); |
| 202 | |
| 203 | QCBOREncode_AddBytesToMapN(&cbor_enc_ctx, |
| 204 | CCA_PLAT_TOKEN, |
AlexeiFedorov | f4e37b3 | 2023-08-24 13:20:09 +0100 | [diff] [blame] | 205 | platform_token); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 206 | |
| 207 | QCBOREncode_AddBytesToMapN(&cbor_enc_ctx, |
| 208 | CCA_REALM_DELEGATED_TOKEN, |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 209 | realm_token_ub); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 210 | QCBOREncode_CloseMap(&cbor_enc_ctx); |
| 211 | |
| 212 | qcbor_res = QCBOREncode_Finish(&cbor_enc_ctx, &completed_token); |
| 213 | |
| 214 | if (qcbor_res == QCBOR_ERR_BUFFER_TOO_SMALL) { |
| 215 | ERROR("CCA output token buffer too small\n"); |
| 216 | return 0; |
| 217 | } else if (qcbor_res != QCBOR_SUCCESS) { |
| 218 | /* likely from array not closed, too many closes, ... */ |
| 219 | assert(false); |
| 220 | } else { |
| 221 | return completed_token.len; |
| 222 | } |
| 223 | return 0; |
| 224 | } |
| 225 | |
| 226 | /* |
| 227 | * Assemble the Realm Attestation Token in the buffer provided in |
| 228 | * realm_token_buf, except the signature. |
| 229 | * |
| 230 | * As per section A7.2.3.1 of RMM specfication, Realm Attestation token is |
| 231 | * composed of: |
| 232 | * - Realm Challenge |
| 233 | * - Realm Personalization Value |
| 234 | * - Realm Hash Algorithm Id |
| 235 | * - Realm Public Key |
| 236 | * - Realm Public Key Hash Algorithm Id |
| 237 | * - Realm Initial Measurement |
| 238 | * - Realm Extensible Measurements |
| 239 | */ |
| 240 | int attest_realm_token_create(enum hash_algo algorithm, |
| 241 | unsigned char measurements[][MAX_MEASUREMENT_SIZE], |
| 242 | unsigned int num_measurements, |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 243 | const void *rpv_buf, |
| 244 | size_t rpv_len, |
AlexeiFedorov | 56e1a8e | 2023-09-01 17:06:13 +0100 | [diff] [blame] | 245 | struct token_sign_cntxt *ctx, |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 246 | void *realm_token_buf, |
| 247 | size_t realm_token_buf_size) |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 248 | { |
| 249 | struct q_useful_buf_c buf; |
| 250 | size_t measurement_size; |
| 251 | enum attest_token_err_t token_ret; |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 252 | struct q_useful_buf realm_token_ub = {realm_token_buf, realm_token_buf_size}; |
| 253 | struct q_useful_buf_c rpv_ub = {rpv_buf, rpv_len}; |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 254 | int ret; |
| 255 | |
| 256 | /* Can only be called in the init state */ |
| 257 | assert(ctx->state == ATTEST_SIGN_NOT_STARTED); |
| 258 | |
| 259 | assert(num_measurements == MEASUREMENT_SLOT_NR); |
| 260 | |
| 261 | /* |
| 262 | * Get started creating the token. This sets up the CBOR and COSE |
| 263 | * contexts which causes the COSE headers to be constructed. |
| 264 | */ |
| 265 | token_ret = attest_token_encode_start(&(ctx->ctx), |
| 266 | 0, /* option_flags */ |
| 267 | 0, /* key_select */ |
| 268 | T_COSE_ALGORITHM_ES384, |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 269 | &realm_token_ub); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 270 | if (token_ret != ATTEST_TOKEN_ERR_SUCCESS) { |
AlexeiFedorov | f4e37b3 | 2023-08-24 13:20:09 +0100 | [diff] [blame] | 271 | return (int)token_ret; |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 272 | } |
| 273 | |
Mate Toth-Pal | fda673a | 2023-06-13 12:25:43 +0200 | [diff] [blame] | 274 | QCBOREncode_BstrWrap(&(ctx->ctx.cbor_enc_ctx)); |
| 275 | QCBOREncode_OpenMap(&(ctx->ctx.cbor_enc_ctx)); |
| 276 | |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 277 | /* Add challenge value, which is the only input from the caller. */ |
| 278 | buf.ptr = ctx->challenge; |
| 279 | buf.len = ATTEST_CHALLENGE_SIZE; |
| 280 | QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx), |
| 281 | CCA_REALM_CHALLENGE, |
| 282 | buf); |
| 283 | |
| 284 | QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx), |
| 285 | CCA_REALM_PERSONALIZATION_VALUE, |
Mate Toth-Pal | 071aa56 | 2023-07-04 09:09:26 +0200 | [diff] [blame] | 286 | rpv_ub); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 287 | |
| 288 | ret = attest_get_realm_public_key(&buf); |
| 289 | if (ret != 0) { |
| 290 | return ret; |
| 291 | } |
| 292 | |
| 293 | QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx), |
| 294 | CCA_REALM_PUB_KEY, |
| 295 | buf); |
| 296 | |
| 297 | attest_get_hash_algo_text(algorithm, &buf); |
| 298 | QCBOREncode_AddTextToMapN(&(ctx->ctx.cbor_enc_ctx), |
| 299 | CCA_REALM_HASH_ALGM_ID, |
| 300 | buf); |
| 301 | |
| 302 | attest_get_hash_algo_text(attest_get_realm_public_key_hash_algo_id(), |
| 303 | &buf); |
| 304 | QCBOREncode_AddTextToMapN(&(ctx->ctx.cbor_enc_ctx), |
| 305 | CCA_REALM_PUB_KEY_HASH_ALGO_ID, |
| 306 | buf); |
| 307 | |
| 308 | measurement_size = measurement_get_size(algorithm); |
| 309 | assert(measurement_size <= MAX_MEASUREMENT_SIZE); |
| 310 | |
| 311 | /* RIM: 0, REM: 1..4 */ |
| 312 | buf.ptr = &measurements[RIM_MEASUREMENT_SLOT]; |
| 313 | buf.len = measurement_size; |
| 314 | QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx), |
| 315 | CCA_REALM_INITIAL_MEASUREMENT, |
| 316 | buf); |
| 317 | |
| 318 | QCBOREncode_OpenArrayInMapN(&(ctx->ctx.cbor_enc_ctx), |
| 319 | CCA_REALM_EXTENSIBLE_MEASUREMENTS); |
| 320 | |
| 321 | for (unsigned int i = 1U; i < num_measurements; ++i) { |
| 322 | buf.ptr = &measurements[i]; |
| 323 | buf.len = measurement_size; |
| 324 | QCBOREncode_AddBytes(&(ctx->ctx.cbor_enc_ctx), buf); |
| 325 | } |
| 326 | |
| 327 | QCBOREncode_CloseArray(&(ctx->ctx.cbor_enc_ctx)); |
| 328 | QCBOREncode_CloseMap(&(ctx->ctx.cbor_enc_ctx)); |
Mate Toth-Pal | fda673a | 2023-06-13 12:25:43 +0200 | [diff] [blame] | 329 | QCBOREncode_CloseBstrWrap2(&(ctx->ctx.cbor_enc_ctx), false, |
| 330 | &(ctx->ctx.signed_payload)); |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 331 | |
AlexeiFedorov | f4e37b3 | 2023-08-24 13:20:09 +0100 | [diff] [blame] | 332 | return (int)ATTEST_TOKEN_ERR_SUCCESS; |
Soby Mathew | b4c6df4 | 2022-11-09 11:13:29 +0000 | [diff] [blame] | 333 | } |