blob: 6dec050f36003c3c02cef16f0fc571cf8d3354fb [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 */
30static void attest_get_hash_algo_text(enum hash_algo algo_id,
31 struct q_useful_buf_c *algo_text)
32{
33 const char *sha256 = "sha-256";
34 const char *sha512 = "sha-512";
35
36 switch (algo_id) {
37 case HASH_ALGO_SHA256:
38 *algo_text = UsefulBuf_FromSZ(sha256);
39 break;
40 case HASH_ALGO_SHA512:
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 */
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);
88 assert(out_buf != NULL);
89
90 /* Remember some of the configuration values */
91 me->opt_flags = opt_flags;
92 me->key_select = key_select;
93
Mate Toth-Palfda673a2023-06-13 12:25:43 +020094 t_cose_signature_sign_restart_init(&me->restartable_signer_ctx, cose_alg_id);
95 t_cose_signature_sign_restart_set_crypto_context(&me->restartable_signer_ctx, &(me->crypto_ctx));
96 t_cose_sign_sign_init(&me->sign_ctx, T_COSE_OPT_MESSAGE_TYPE_SIGN1);
97 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 +000098
99
100 /*
101 * Get the reference to `mbedtls_ecp_keypair` and set it to t_cose.
102 */
Mate Toth-Palc69951d2023-03-17 17:30:50 +0100103 attest_get_realm_signing_key(&key_handle);
104 attest_key.key.handle = key_handle;
Mate Toth-Palfda673a2023-06-13 12:25:43 +0200105
106 t_cose_signature_sign_restart_set_signing_key(&me->restartable_signer_ctx, attest_key);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000107
108 /* Spin up the CBOR encoder */
109 QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf);
110
111 /*
112 * This will cause the cose headers to be encoded and written into
113 * out_buf using me->cbor_enc_ctx
114 */
Mate Toth-Palfda673a2023-06-13 12:25:43 +0200115 cose_res = t_cose_sign_encode_start(&me->sign_ctx, &me->cbor_enc_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000116
117 if (cose_res != T_COSE_SUCCESS) {
118 return ATTEST_TOKEN_ERR_COSE_ERROR;
119 }
120
Soby Mathewb4c6df42022-11-09 11:13:29 +0000121 return ATTEST_TOKEN_ERR_SUCCESS;
122}
123
124enum attest_token_err_t
125attest_realm_token_sign(struct attest_token_encode_ctx *me,
126 struct q_useful_buf_c *completed_token)
127{
128 /* The completed and signed encoded cose_sign1 */
129 struct q_useful_buf_c completed_token_ub;
130 enum attest_token_err_t attest_res = ATTEST_TOKEN_ERR_SUCCESS;
131 QCBORError qcbor_res;
132 enum t_cose_err_t cose_res;
133
134 assert(me != NULL);
135 assert(completed_token != NULL);
136
137 /* Finish up the COSE_Sign1. This is where the signing happens */
Arunachalam Ganapathy51119932023-03-23 12:32:49 +0000138 SIMD_FPU_ALLOW(
Mate Toth-Palfda673a2023-06-13 12:25:43 +0200139 cose_res = t_cose_sign_encode_finish(&me->sign_ctx,
140 NULL_Q_USEFUL_BUF_C,
141 me->signed_payload,
142 &me->cbor_enc_ctx));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000143
144 if (cose_res == T_COSE_ERR_SIG_IN_PROGRESS) {
145 /* Token signing has not yet finished */
146 return ATTEST_TOKEN_ERR_COSE_SIGN_IN_PROGRESS;
147 }
148
149 if (cose_res != T_COSE_SUCCESS) {
150 /* Main errors are invoking the hash or signature */
151 return ATTEST_TOKEN_ERR_COSE_ERROR;
152 }
153
154 /*
155 * Finally close off the CBOR formatting and get the pointer and length
156 * of the resulting COSE_Sign1
157 */
158 qcbor_res = QCBOREncode_Finish(&(me->cbor_enc_ctx),
159 &completed_token_ub);
160
161 switch (qcbor_res) {
162 case QCBOR_ERR_BUFFER_TOO_SMALL:
163 attest_res = ATTEST_TOKEN_ERR_TOO_SMALL;
164 break;
165 case QCBOR_SUCCESS:
166 *completed_token = completed_token_ub;
167 break;
168 default:
169 /* likely from array not closed, too many closes ... */
170 attest_res = ATTEST_TOKEN_ERR_CBOR_FORMATTING;
171 }
172
173 return attest_res;
174}
175
176size_t attest_cca_token_create(struct q_useful_buf *attest_token_buf,
177 const struct q_useful_buf_c *realm_token)
178{
179 struct q_useful_buf_c completed_token;
180 QCBOREncodeContext cbor_enc_ctx;
181 QCBORError qcbor_res;
182 struct q_useful_buf_c *rmm_platform_token;
183
184 __unused int ret;
185
186 /* Get the platform token */
187 ret = attest_get_platform_token(&rmm_platform_token);
188 assert(ret == 0);
189
190 QCBOREncode_Init(&cbor_enc_ctx, *attest_token_buf);
191
192 QCBOREncode_AddTag(&cbor_enc_ctx, TAG_CCA_TOKEN);
193
194 QCBOREncode_OpenMap(&cbor_enc_ctx);
195
196 QCBOREncode_AddBytesToMapN(&cbor_enc_ctx,
197 CCA_PLAT_TOKEN,
198 *rmm_platform_token);
199
200 QCBOREncode_AddBytesToMapN(&cbor_enc_ctx,
201 CCA_REALM_DELEGATED_TOKEN,
202 *realm_token);
203 QCBOREncode_CloseMap(&cbor_enc_ctx);
204
205 qcbor_res = QCBOREncode_Finish(&cbor_enc_ctx, &completed_token);
206
207 if (qcbor_res == QCBOR_ERR_BUFFER_TOO_SMALL) {
208 ERROR("CCA output token buffer too small\n");
209 return 0;
210 } else if (qcbor_res != QCBOR_SUCCESS) {
211 /* likely from array not closed, too many closes, ... */
212 assert(false);
213 } else {
214 return completed_token.len;
215 }
216 return 0;
217}
218
219/*
220 * Assemble the Realm Attestation Token in the buffer provided in
221 * realm_token_buf, except the signature.
222 *
223 * As per section A7.2.3.1 of RMM specfication, Realm Attestation token is
224 * composed of:
225 * - Realm Challenge
226 * - Realm Personalization Value
227 * - Realm Hash Algorithm Id
228 * - Realm Public Key
229 * - Realm Public Key Hash Algorithm Id
230 * - Realm Initial Measurement
231 * - Realm Extensible Measurements
232 */
233int attest_realm_token_create(enum hash_algo algorithm,
234 unsigned char measurements[][MAX_MEASUREMENT_SIZE],
235 unsigned int num_measurements,
236 struct q_useful_buf_c *rpv,
237 struct token_sign_ctx *ctx,
238 struct q_useful_buf *realm_token_buf)
239{
240 struct q_useful_buf_c buf;
241 size_t measurement_size;
242 enum attest_token_err_t token_ret;
243 int ret;
244
245 /* Can only be called in the init state */
246 assert(ctx->state == ATTEST_SIGN_NOT_STARTED);
247
248 assert(num_measurements == MEASUREMENT_SLOT_NR);
249
250 /*
251 * Get started creating the token. This sets up the CBOR and COSE
252 * contexts which causes the COSE headers to be constructed.
253 */
254 token_ret = attest_token_encode_start(&(ctx->ctx),
255 0, /* option_flags */
256 0, /* key_select */
257 T_COSE_ALGORITHM_ES384,
258 realm_token_buf);
259 if (token_ret != ATTEST_TOKEN_ERR_SUCCESS) {
260 return token_ret;
261 }
262
Mate Toth-Palfda673a2023-06-13 12:25:43 +0200263 QCBOREncode_BstrWrap(&(ctx->ctx.cbor_enc_ctx));
264 QCBOREncode_OpenMap(&(ctx->ctx.cbor_enc_ctx));
265
Soby Mathewb4c6df42022-11-09 11:13:29 +0000266 /* Add challenge value, which is the only input from the caller. */
267 buf.ptr = ctx->challenge;
268 buf.len = ATTEST_CHALLENGE_SIZE;
269 QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
270 CCA_REALM_CHALLENGE,
271 buf);
272
273 QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
274 CCA_REALM_PERSONALIZATION_VALUE,
275 *rpv);
276
277 ret = attest_get_realm_public_key(&buf);
278 if (ret != 0) {
279 return ret;
280 }
281
282 QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
283 CCA_REALM_PUB_KEY,
284 buf);
285
286 attest_get_hash_algo_text(algorithm, &buf);
287 QCBOREncode_AddTextToMapN(&(ctx->ctx.cbor_enc_ctx),
288 CCA_REALM_HASH_ALGM_ID,
289 buf);
290
291 attest_get_hash_algo_text(attest_get_realm_public_key_hash_algo_id(),
292 &buf);
293 QCBOREncode_AddTextToMapN(&(ctx->ctx.cbor_enc_ctx),
294 CCA_REALM_PUB_KEY_HASH_ALGO_ID,
295 buf);
296
297 measurement_size = measurement_get_size(algorithm);
298 assert(measurement_size <= MAX_MEASUREMENT_SIZE);
299
300 /* RIM: 0, REM: 1..4 */
301 buf.ptr = &measurements[RIM_MEASUREMENT_SLOT];
302 buf.len = measurement_size;
303 QCBOREncode_AddBytesToMapN(&(ctx->ctx.cbor_enc_ctx),
304 CCA_REALM_INITIAL_MEASUREMENT,
305 buf);
306
307 QCBOREncode_OpenArrayInMapN(&(ctx->ctx.cbor_enc_ctx),
308 CCA_REALM_EXTENSIBLE_MEASUREMENTS);
309
310 for (unsigned int i = 1U; i < num_measurements; ++i) {
311 buf.ptr = &measurements[i];
312 buf.len = measurement_size;
313 QCBOREncode_AddBytes(&(ctx->ctx.cbor_enc_ctx), buf);
314 }
315
316 QCBOREncode_CloseArray(&(ctx->ctx.cbor_enc_ctx));
317 QCBOREncode_CloseMap(&(ctx->ctx.cbor_enc_ctx));
Mate Toth-Palfda673a2023-06-13 12:25:43 +0200318 QCBOREncode_CloseBstrWrap2(&(ctx->ctx.cbor_enc_ctx), false,
319 &(ctx->ctx.signed_payload));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000320
321 return ATTEST_TOKEN_ERR_SUCCESS;
322}