blob: be12d390a9a610aacff25ff2be87e3abfdd0e359 [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
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 Mathewb4c6df42022-11-09 11:13:29 +000018#include <measurement.h>
19#include <qcbor/qcbor.h>
Arunachalam Ganapathyf6491212023-02-23 16:04:34 +000020#include <simd.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000021#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 */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +010030static void attest_get_hash_algo_text(enum hash_algo algorithm,
Soby Mathewb4c6df42022-11-09 11:13:29 +000031 struct q_useful_buf_c *algo_text)
32{
33 const char *sha256 = "sha-256";
34 const char *sha512 = "sha-512";
35
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +010036 switch (algorithm) {
AlexeiFedorov4fc3b152023-06-13 12:08:01 +010037 case HASH_SHA_256:
Soby Mathewb4c6df42022-11-09 11:13:29 +000038 *algo_text = UsefulBuf_FromSZ(sha256);
39 break;
AlexeiFedorov4fc3b152023-06-13 12:08:01 +010040 case HASH_SHA_512:
Soby Mathewb4c6df42022-11-09 11:13:29 +000041 *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 */
76static enum attest_token_err_t
77attest_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 Mathewb4c6df42022-11-09 11:13:29 +000084 struct t_cose_key attest_key;
Mate Toth-Palc69951d2023-03-17 17:30:50 +010085 psa_key_handle_t key_handle;
Soby Mathewb4c6df42022-11-09 11:13:29 +000086
87 assert(me != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +000088
89 /* Remember some of the configuration values */
90 me->opt_flags = opt_flags;
91 me->key_select = key_select;
92
Mate Toth-Palfda673a2023-06-13 12:25:43 +020093 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 Mathewb4c6df42022-11-09 11:13:29 +000097
98
99 /*
100 * Get the reference to `mbedtls_ecp_keypair` and set it to t_cose.
101 */
AlexeiFedorovf4e37b32023-08-24 13:20:09 +0100102 if (attest_get_realm_signing_key(&key_handle) != 0) {
103 return ATTEST_TOKEN_ERR_SIGNING_KEY;
104 }
105
Mate Toth-Palc69951d2023-03-17 17:30:50 +0100106 attest_key.key.handle = key_handle;
Mate Toth-Palfda673a2023-06-13 12:25:43 +0200107
108 t_cose_signature_sign_restart_set_signing_key(&me->restartable_signer_ctx, attest_key);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000109
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-Palfda673a2023-06-13 12:25:43 +0200117 cose_res = t_cose_sign_encode_start(&me->sign_ctx, &me->cbor_enc_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000118
119 if (cose_res != T_COSE_SUCCESS) {
120 return ATTEST_TOKEN_ERR_COSE_ERROR;
121 }
122
Soby Mathewb4c6df42022-11-09 11:13:29 +0000123 return ATTEST_TOKEN_ERR_SUCCESS;
124}
125
126enum attest_token_err_t
Soby Mathewf3622132024-07-19 07:31:40 +0100127attest_realm_token_sign(struct token_sign_cntxt *me,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200128 size_t *completed_token_len)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000129{
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-Pal071aa562023-07-04 09:09:26 +0200137 assert(completed_token_len != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000138
Soby Mathewf3622132024-07-19 07:31:40 +0100139 if (me->state != ATTEST_TOKEN_SIGN) {
140 return ATTEST_TOKEN_ERR_INVALID_STATE;
141 }
142
Soby Mathewb4c6df42022-11-09 11:13:29 +0000143 /* Finish up the COSE_Sign1. This is where the signing happens */
Arunachalam Ganapathy51119932023-03-23 12:32:49 +0000144 SIMD_FPU_ALLOW(
Soby Mathewf3622132024-07-19 07:31:40 +0100145 cose_res = t_cose_sign_encode_finish(&me->ctx.sign_ctx,
Mate Toth-Palfda673a2023-06-13 12:25:43 +0200146 NULL_Q_USEFUL_BUF_C,
Soby Mathewf3622132024-07-19 07:31:40 +0100147 me->ctx.signed_payload,
148 &me->ctx.cbor_enc_ctx));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000149
150 if (cose_res == T_COSE_ERR_SIG_IN_PROGRESS) {
151 /* Token signing has not yet finished */
152 return ATTEST_TOKEN_ERR_COSE_SIGN_IN_PROGRESS;
153 }
154
155 if (cose_res != T_COSE_SUCCESS) {
156 /* Main errors are invoking the hash or signature */
157 return ATTEST_TOKEN_ERR_COSE_ERROR;
158 }
159
160 /*
161 * Finally close off the CBOR formatting and get the pointer and length
162 * of the resulting COSE_Sign1
163 */
Soby Mathewf3622132024-07-19 07:31:40 +0100164 qcbor_res = QCBOREncode_Finish(&me->ctx.cbor_enc_ctx,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000165 &completed_token_ub);
166
167 switch (qcbor_res) {
168 case QCBOR_ERR_BUFFER_TOO_SMALL:
169 attest_res = ATTEST_TOKEN_ERR_TOO_SMALL;
170 break;
171 case QCBOR_SUCCESS:
AlexeiFedorovea9d3c92023-09-15 15:35:36 +0100172 /* coverity[uninit_use:SUPPRESS] */
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200173 *completed_token_len = completed_token_ub.len;
Soby Mathewf3622132024-07-19 07:31:40 +0100174 /* This was the last signing cycle. Transition to next state */
175 me->state = ATTEST_TOKEN_CREATE;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000176 break;
177 default:
178 /* likely from array not closed, too many closes ... */
179 attest_res = ATTEST_TOKEN_ERR_CBOR_FORMATTING;
180 }
181
182 return attest_res;
183}
184
Soby Mathewf3622132024-07-19 07:31:40 +0100185size_t attest_cca_token_create(struct token_sign_cntxt *me,
186 void *attest_token_buf,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200187 size_t attest_token_buf_size,
188 const void *realm_token_buf,
189 size_t realm_token_len)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000190{
191 struct q_useful_buf_c completed_token;
192 QCBOREncodeContext cbor_enc_ctx;
193 QCBORError qcbor_res;
AlexeiFedorovf4e37b32023-08-24 13:20:09 +0100194 struct q_useful_buf_c platform_token;
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200195 struct q_useful_buf attest_token_ub = {attest_token_buf, attest_token_buf_size};
196 struct q_useful_buf_c realm_token_ub = {realm_token_buf, realm_token_len};
Soby Mathewf3622132024-07-19 07:31:40 +0100197 size_t ret_len = 0;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000198
199 __unused int ret;
200
Soby Mathewf3622132024-07-19 07:31:40 +0100201 if (me->state != ATTEST_TOKEN_CREATE) {
202 return 0;
203 }
204
Soby Mathewb4c6df42022-11-09 11:13:29 +0000205 /* Get the platform token */
AlexeiFedorovf4e37b32023-08-24 13:20:09 +0100206 ret = attest_get_platform_token(&platform_token.ptr,
207 &platform_token.len);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000208 assert(ret == 0);
209
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200210 QCBOREncode_Init(&cbor_enc_ctx, attest_token_ub);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000211
212 QCBOREncode_AddTag(&cbor_enc_ctx, TAG_CCA_TOKEN);
213
214 QCBOREncode_OpenMap(&cbor_enc_ctx);
215
216 QCBOREncode_AddBytesToMapN(&cbor_enc_ctx,
217 CCA_PLAT_TOKEN,
AlexeiFedorovf4e37b32023-08-24 13:20:09 +0100218 platform_token);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000219
220 QCBOREncode_AddBytesToMapN(&cbor_enc_ctx,
221 CCA_REALM_DELEGATED_TOKEN,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200222 realm_token_ub);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000223 QCBOREncode_CloseMap(&cbor_enc_ctx);
224
225 qcbor_res = QCBOREncode_Finish(&cbor_enc_ctx, &completed_token);
226
227 if (qcbor_res == QCBOR_ERR_BUFFER_TOO_SMALL) {
228 ERROR("CCA output token buffer too small\n");
Soby Mathewb4c6df42022-11-09 11:13:29 +0000229 } else if (qcbor_res != QCBOR_SUCCESS) {
230 /* likely from array not closed, too many closes, ... */
Soby Mathewf3622132024-07-19 07:31:40 +0100231 ERROR("QCBOREncode error for CCA output token\n");
Soby Mathewb4c6df42022-11-09 11:13:29 +0000232 } else {
AlexeiFedorovea9d3c92023-09-15 15:35:36 +0100233 /* coverity[uninit_use:SUPPRESS] */
Soby Mathewf3622132024-07-19 07:31:40 +0100234 ret_len = completed_token.len;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000235 }
Soby Mathewf3622132024-07-19 07:31:40 +0100236
237 /* Transition back to NOT_STARTED */
238 me->state = ATTEST_TOKEN_NOT_STARTED;
239 return ret_len;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000240}
241
242/*
243 * Assemble the Realm Attestation Token in the buffer provided in
244 * realm_token_buf, except the signature.
245 *
246 * As per section A7.2.3.1 of RMM specfication, Realm Attestation token is
247 * composed of:
248 * - Realm Challenge
249 * - Realm Personalization Value
250 * - Realm Hash Algorithm Id
251 * - Realm Public Key
252 * - Realm Public Key Hash Algorithm Id
253 * - Realm Initial Measurement
254 * - Realm Extensible Measurements
255 */
256int attest_realm_token_create(enum hash_algo algorithm,
257 unsigned char measurements[][MAX_MEASUREMENT_SIZE],
258 unsigned int num_measurements,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200259 const void *rpv_buf,
260 size_t rpv_len,
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100261 struct token_sign_cntxt *ctx,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200262 void *realm_token_buf,
263 size_t realm_token_buf_size)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000264{
265 struct q_useful_buf_c buf;
266 size_t measurement_size;
Soby Mathewf3622132024-07-19 07:31:40 +0100267 enum attest_token_err_t token_ret = ATTEST_TOKEN_ERR_INVALID_STATE;
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200268 struct q_useful_buf realm_token_ub = {realm_token_buf, realm_token_buf_size};
269 struct q_useful_buf_c rpv_ub = {rpv_buf, rpv_len};
Soby Mathewb4c6df42022-11-09 11:13:29 +0000270 int ret;
271
272 /* Can only be called in the init state */
Soby Mathewf3622132024-07-19 07:31:40 +0100273 if (ctx->state != ATTEST_TOKEN_INIT) {
274 return (int)token_ret;
275 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000276
277 assert(num_measurements == MEASUREMENT_SLOT_NR);
278
279 /*
280 * Get started creating the token. This sets up the CBOR and COSE
281 * contexts which causes the COSE headers to be constructed.
282 */
283 token_ret = attest_token_encode_start(&(ctx->ctx),
284 0, /* option_flags */
285 0, /* key_select */
286 T_COSE_ALGORITHM_ES384,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200287 &realm_token_ub);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000288 if (token_ret != ATTEST_TOKEN_ERR_SUCCESS) {
AlexeiFedorovf4e37b32023-08-24 13:20:09 +0100289 return (int)token_ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000290 }
291
Mate Toth-Palfda673a2023-06-13 12:25:43 +0200292 QCBOREncode_BstrWrap(&(ctx->ctx.cbor_enc_ctx));
293 QCBOREncode_OpenMap(&(ctx->ctx.cbor_enc_ctx));
294
Soby Mathewb4c6df42022-11-09 11:13:29 +0000295 /* Add challenge value, which is the only input from the caller. */
296 buf.ptr = ctx->challenge;
297 buf.len = ATTEST_CHALLENGE_SIZE;
298 QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
299 CCA_REALM_CHALLENGE,
300 buf);
301
302 QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
303 CCA_REALM_PERSONALIZATION_VALUE,
Mate Toth-Pal071aa562023-07-04 09:09:26 +0200304 rpv_ub);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000305
306 ret = attest_get_realm_public_key(&buf);
307 if (ret != 0) {
308 return ret;
309 }
310
311 QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
312 CCA_REALM_PUB_KEY,
313 buf);
314
315 attest_get_hash_algo_text(algorithm, &buf);
316 QCBOREncode_AddTextToMapN(&(ctx->ctx.cbor_enc_ctx),
317 CCA_REALM_HASH_ALGM_ID,
318 buf);
319
320 attest_get_hash_algo_text(attest_get_realm_public_key_hash_algo_id(),
321 &buf);
322 QCBOREncode_AddTextToMapN(&(ctx->ctx.cbor_enc_ctx),
323 CCA_REALM_PUB_KEY_HASH_ALGO_ID,
324 buf);
325
326 measurement_size = measurement_get_size(algorithm);
327 assert(measurement_size <= MAX_MEASUREMENT_SIZE);
328
329 /* RIM: 0, REM: 1..4 */
330 buf.ptr = &measurements[RIM_MEASUREMENT_SLOT];
331 buf.len = measurement_size;
332 QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
333 CCA_REALM_INITIAL_MEASUREMENT,
334 buf);
335
336 QCBOREncode_OpenArrayInMapN(&(ctx->ctx.cbor_enc_ctx),
337 CCA_REALM_EXTENSIBLE_MEASUREMENTS);
338
339 for (unsigned int i = 1U; i < num_measurements; ++i) {
340 buf.ptr = &measurements[i];
341 buf.len = measurement_size;
342 QCBOREncode_AddBytes(&(ctx->ctx.cbor_enc_ctx), buf);
343 }
344
345 QCBOREncode_CloseArray(&(ctx->ctx.cbor_enc_ctx));
346 QCBOREncode_CloseMap(&(ctx->ctx.cbor_enc_ctx));
Mate Toth-Palfda673a2023-06-13 12:25:43 +0200347 QCBOREncode_CloseBstrWrap2(&(ctx->ctx.cbor_enc_ctx), false,
348 &(ctx->ctx.signed_payload));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000349
Soby Mathewf3622132024-07-19 07:31:40 +0100350 /* Transition to ATTEST_CCA_TOKEN_SIGN state */
351 ctx->state = ATTEST_TOKEN_SIGN;
AlexeiFedorovee2fc822023-10-31 14:54:39 +0000352 return 0;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000353}
Soby Mathewf3622132024-07-19 07:31:40 +0100354
355int attest_token_ctx_init(struct token_sign_cntxt *token_ctx,
356 unsigned char *heap_buf,
357 unsigned int heap_buf_len)
358{
359 int ret = 0;
360
361 if (token_ctx->state != ATTEST_TOKEN_INIT) {
362 ret = attestation_heap_ctx_init(heap_buf,
363 heap_buf_len);
364
365 /* Clear context for signing an attestation token */
366 (void)memset(token_ctx, 0, sizeof(struct token_sign_cntxt));
367
368 token_ctx->state = ATTEST_TOKEN_INIT;
369 }
370
371 return ret;
372}