blob: 5b145d61f4e4ff413cbbbb8f38f0f4827d88f7a5 [file] [log] [blame]
Maulik Patel2358bbb2023-07-21 10:56:56 +01001/*
Tamas Ban5179a4d2024-01-25 17:05:30 +01002 * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
Maulik Patel2358bbb2023-07-21 10:56:56 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include <assert.h>
9#include "dpe_certificate.h"
10#include "dpe_context_mngr.h"
11#include "dpe_crypto_config.h"
12#include "dpe_crypto_interface.h"
Maulik Patele6adc112023-08-18 14:21:51 +010013#include "dpe_plat.h"
Maulik Patel2358bbb2023-07-21 10:56:56 +010014#include "qcbor/qcbor_encode.h"
15#include "t_cose_common.h"
16#include "t_cose_sign1_sign.h"
17
18#define ID_HEX_SIZE (2 * DICE_ID_SIZE) /* Size of CDI encoded to ascii hex */
Maulik Patele6adc112023-08-18 14:21:51 +010019#define LABEL_HEX_SIZE (2 * DPE_EXTERNAL_LABEL_MAX_SIZE)
Maulik Patel2358bbb2023-07-21 10:56:56 +010020
Maulik Patel2358bbb2023-07-21 10:56:56 +010021static void convert_to_ascii_hex(const uint8_t *in,
22 size_t in_size,
23 char *out,
24 size_t out_size)
25{
26 const char hex_table[] = "0123456789abcdef";
27 size_t in_pos = 0;
28 size_t out_pos = 0;
29
30 for (in_pos = 0; in_pos < in_size && out_pos < out_size; in_pos++) {
31 out[out_pos++] = hex_table[(in[in_pos] & 0xF0 >> 4)];
32 out[out_pos++] = hex_table[in[in_pos] & 0x0F];
33 }
34}
35
36static dpe_error_t t_cose_err_to_dpe_err(enum t_cose_err_t err)
37{
38 switch(err) {
39
40 case T_COSE_SUCCESS:
41 return DPE_NO_ERROR;
42
43 case T_COSE_ERR_TOO_SMALL:
44 return DPE_INSUFFICIENT_MEMORY;
45
46 default:
47 /* A lot of the errors are not mapped because they are
48 * primarily internal errors that should never happen. They
49 * end up here.
50 */
51 return DPE_INTERNAL_ERROR;
52 }
53}
54
Tamas Ban257471b2024-03-25 13:49:53 +010055static dpe_error_t certificate_encode_start(QCBOREncodeContext *cbor_enc_ctx,
56 struct t_cose_sign1_sign_ctx *signer_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +010057 psa_key_handle_t private_key)
58{
59 enum t_cose_err_t t_cose_err;
60 struct t_cose_key attest_key;
61 UsefulBufC attest_key_id = {NULL, 0};
62
63 /* DPE Certificate is untagged COSE_Sign1 message */
Tamas Ban257471b2024-03-25 13:49:53 +010064 t_cose_sign1_sign_init(signer_ctx, T_COSE_OPT_OMIT_CBOR_TAG, DPE_T_COSE_ALG);
Maulik Patel2358bbb2023-07-21 10:56:56 +010065
66 attest_key.crypto_lib = T_COSE_CRYPTO_LIB_PSA;
67 attest_key.k.key_handle = private_key;
68
Tamas Ban257471b2024-03-25 13:49:53 +010069 t_cose_sign1_set_signing_key(signer_ctx, attest_key, attest_key_id);
Maulik Patel2358bbb2023-07-21 10:56:56 +010070
Tamas Ban257471b2024-03-25 13:49:53 +010071 /* It is expected that the CBOR encoder is already initialized */
Maulik Patel2358bbb2023-07-21 10:56:56 +010072
Tamas Ban257471b2024-03-25 13:49:53 +010073 /* This encodes and writes the cose headers to be into the CBOR context. */
74 t_cose_err = t_cose_sign1_encode_parameters(signer_ctx,
75 cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +010076 if (t_cose_err) {
77 return t_cose_err_to_dpe_err(t_cose_err);
78 }
79
Tamas Ban257471b2024-03-25 13:49:53 +010080 QCBOREncode_OpenMap(cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +010081
82 return DPE_NO_ERROR;
83}
84
Tamas Ban257471b2024-03-25 13:49:53 +010085static void add_key_usage_claim(QCBOREncodeContext *cbor_enc_ctx)
Maulik Patel2358bbb2023-07-21 10:56:56 +010086{
87 uint8_t key_usage = DPE_CERT_KEY_USAGE_CERT_SIGN;
88
89 /* Encode key usage as byte string */
Tamas Ban257471b2024-03-25 13:49:53 +010090 QCBOREncode_AddBytesToMapN(cbor_enc_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +010091 DPE_CERT_LABEL_KEY_USAGE,
92 (UsefulBufC){ &key_usage,
93 sizeof(key_usage) });
94}
95
Tamas Ban257471b2024-03-25 13:49:53 +010096static void add_label_claim(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +010097 const uint8_t *label,
98 size_t label_size)
99{
100 char label_hex[LABEL_HEX_SIZE];
101
102 /* If label is supplied, add label claim, else skip */
103 if ((label != NULL) && (label_size != 0)) {
104 convert_to_ascii_hex(&label[0],
105 label_size,
106 &label_hex[0],
107 sizeof(label_hex));
108
109 /* Encode label as text string */
Tamas Ban257471b2024-03-25 13:49:53 +0100110 QCBOREncode_AddTextToMapN(cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100111 DPE_CERT_LABEL_EXTERNAL_LABEL,
112 (UsefulBufC){ &label_hex[0],
113 label_size });
114 }
115}
116
Tamas Ban257471b2024-03-25 13:49:53 +0100117static void add_cdi_export_claim(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100118 const struct cert_context_t *cert_ctx)
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000119{
Tamas Ban257471b2024-03-25 13:49:53 +0100120 QCBOREncode_AddBoolToMapN(cbor_enc_ctx,
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000121 DPE_CERT_LABEL_CDI_EXPORT,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100122 cert_ctx->is_cdi_to_be_exported);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000123}
124
Tamas Ban257471b2024-03-25 13:49:53 +0100125static void add_subject_claim(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100126 const struct cert_context_t *cert_ctx)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100127{
128 char cdi_id_hex[ID_HEX_SIZE];
129
Maulik Patel97a61fe2024-07-01 15:55:04 +0100130 convert_to_ascii_hex(&cert_ctx->data.cdi_id[0],
131 sizeof(cert_ctx->data.cdi_id),
Maulik Patel2358bbb2023-07-21 10:56:56 +0100132 &cdi_id_hex[0],
133 sizeof(cdi_id_hex));
134 /* Encode subject as text string */
Tamas Ban257471b2024-03-25 13:49:53 +0100135 QCBOREncode_AddTextToMapN(cbor_enc_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100136 DPE_CERT_LABEL_SUBJECT,
137 (UsefulBufC){ &cdi_id_hex[0],
138 sizeof(cdi_id_hex) });
139}
140
Tamas Ban257471b2024-03-25 13:49:53 +0100141static void encode_issuer_claim(QCBOREncodeContext *cbor_enc_ctx,
Jamie Fox93225232023-09-22 14:09:30 +0100142 const uint8_t *issuer,
143 size_t issuer_size)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100144{
Maulik Patel2358bbb2023-07-21 10:56:56 +0100145 char cdi_id_hex[ID_HEX_SIZE];
146
Jamie Fox93225232023-09-22 14:09:30 +0100147 convert_to_ascii_hex(issuer,
148 issuer_size,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100149 &cdi_id_hex[0],
150 sizeof(cdi_id_hex));
151
152 /* Encode issuer as text string */
Tamas Ban257471b2024-03-25 13:49:53 +0100153 QCBOREncode_AddTextToMapN(cbor_enc_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100154 DPE_CERT_LABEL_ISSUER,
155 (UsefulBufC){ &cdi_id_hex[0],
156 sizeof(cdi_id_hex) });
157}
158
Tamas Ban257471b2024-03-25 13:49:53 +0100159static void encode_public_key(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100160 const uint8_t *pub_key,
161 size_t pub_key_size)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100162{
163 /* As per RFC8152 */
164 const int64_t cose_key_type_value = DPE_T_COSE_KEY_TYPE_VAL;
165 const int64_t cose_key_ops_value = DPE_T_COSE_KEY_OPS_VAL;
166 const int64_t cose_key_ec2_curve_value = DPE_T_COSE_KEY_EC2_CURVE_VAL;
167 const int64_t cose_key_alg_value = DPE_T_COSE_KEY_ALG_VAL;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100168
Tamas Ban257471b2024-03-25 13:49:53 +0100169 QCBOREncode_OpenMap(cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100170
171 /* Add the key type as int */
Tamas Ban257471b2024-03-25 13:49:53 +0100172 QCBOREncode_AddInt64ToMapN(cbor_enc_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100173 DPE_CERT_LABEL_COSE_KEY_TYPE,
174 cose_key_type_value);
175
176 /* Add the algorithm as int */
Tamas Ban257471b2024-03-25 13:49:53 +0100177 QCBOREncode_AddInt64ToMapN(cbor_enc_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100178 DPE_CERT_LABEL_COSE_KEY_ALG,
179 cose_key_alg_value);
180
181 /* Add the key operation as [+ (tstr/int)] */
Tamas Ban257471b2024-03-25 13:49:53 +0100182 QCBOREncode_OpenArrayInMapN(cbor_enc_ctx, DPE_CERT_LABEL_COSE_KEY_OPS);
183 QCBOREncode_AddInt64(cbor_enc_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100184 cose_key_ops_value);
Tamas Ban257471b2024-03-25 13:49:53 +0100185 QCBOREncode_CloseArray(cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100186
187 /* Add the curve */
Tamas Ban257471b2024-03-25 13:49:53 +0100188 QCBOREncode_AddInt64ToMapN(cbor_enc_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100189 DPE_CERT_LABEL_COSE_KEY_EC2_CURVE,
190 cose_key_ec2_curve_value);
191
Tamas Ban8ed52802024-03-14 09:36:05 +0100192 /*
193 * From psa/crypto.h:
194 *
195 * For other elliptic curve public keys (key types for which
196 * #PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY is true), the format is the uncompressed
197 * representation defined by SEC1 &sect;2.3.3 as the content of an ECPoint.
198 * Let `m` be the bit size associated with the curve, i.e. the bit size of
199 * `q` for a curve over `F_q`. The representation consists of:
200 * - The byte 0x04;
201 * - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
202 * - `y_P` as a `ceiling(m/8)`-byte string, big-endian.
203
204 * Furthermore, as per rfc5480 section-2.2:
205 *
206 * The first octet of the OCTET STRING indicates whether the key is
207 * compressed or uncompressed. The uncompressed form is indicated by 0x04
208 * and the compressed form is indicated by either 0x02 or 0x03.
209 */
Tamas Ban257471b2024-03-25 13:49:53 +0100210 QCBOREncode_AddBytesToMapN(cbor_enc_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100211 DPE_CERT_LABEL_COSE_KEY_EC2_X,
Tamas Ban8ed52802024-03-14 09:36:05 +0100212 (UsefulBufC){ &pub_key[1],
Maulik Patele6adc112023-08-18 14:21:51 +0100213 pub_key_size / 2 });
Maulik Patel2358bbb2023-07-21 10:56:56 +0100214
Tamas Ban257471b2024-03-25 13:49:53 +0100215 QCBOREncode_AddBytesToMapN(cbor_enc_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100216 DPE_CERT_LABEL_COSE_KEY_EC2_Y,
Tamas Ban8ed52802024-03-14 09:36:05 +0100217 (UsefulBufC){ &pub_key[1 + (pub_key_size / 2)],
Maulik Patele6adc112023-08-18 14:21:51 +0100218 pub_key_size / 2 });
Maulik Patel2358bbb2023-07-21 10:56:56 +0100219
Tamas Ban257471b2024-03-25 13:49:53 +0100220 QCBOREncode_CloseMap(cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100221
Maulik Patele6adc112023-08-18 14:21:51 +0100222}
223
Tamas Ban257471b2024-03-25 13:49:53 +0100224static void add_public_key_claim(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100225 const uint8_t *pub_key,
226 size_t pub_key_size)
227{
228 UsefulBufC wrapped;
229
230 /* Cose key is encoded as a map. This map is wrapped into the a
231 * byte string and it is further encoded as a map */
Tamas Ban257471b2024-03-25 13:49:53 +0100232 QCBOREncode_BstrWrapInMapN(cbor_enc_ctx, DPE_CERT_LABEL_SUBJECT_PUBLIC_KEY);
233 encode_public_key(cbor_enc_ctx, pub_key, pub_key_size);
234 QCBOREncode_CloseBstrWrap2(cbor_enc_ctx, true, &wrapped);
Maulik Patele6adc112023-08-18 14:21:51 +0100235 assert(wrapped.len <= DICE_MAX_ENCODED_PUBLIC_KEY_SIZE);
236}
237
Tamas Ban257471b2024-03-25 13:49:53 +0100238static void add_public_key_to_certificate_chain(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100239 const uint8_t *pub_key,
240 size_t pub_key_size)
241{
242 UsefulBufC wrapped;
243
244 /* Cose key is encoded as a map wrapped into a byte string */
Tamas Ban257471b2024-03-25 13:49:53 +0100245 QCBOREncode_BstrWrap(cbor_enc_ctx);
246 encode_public_key(cbor_enc_ctx, pub_key, pub_key_size);
247 QCBOREncode_CloseBstrWrap2(cbor_enc_ctx, true, &wrapped);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100248 assert(wrapped.len <= DICE_MAX_ENCODED_PUBLIC_KEY_SIZE);
249}
250
Tamas Ban257471b2024-03-25 13:49:53 +0100251static dpe_error_t certificate_encode_finish(QCBOREncodeContext *cbor_enc_ctx,
252 struct t_cose_sign1_sign_ctx *signer_ctx,
253 bool finish_cbor_encoding,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100254 UsefulBufC *completed_cert)
255{
256 QCBORError qcbor_result;
257 enum t_cose_err_t cose_return_value;
258
Tamas Ban257471b2024-03-25 13:49:53 +0100259 QCBOREncode_CloseMap(cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100260
261 /* -- Finish up the COSE_Sign1. This is where the signing happens -- */
Tamas Ban257471b2024-03-25 13:49:53 +0100262 cose_return_value = t_cose_sign1_encode_signature(signer_ctx,
263 cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100264 if (cose_return_value) {
265 /* Main errors are invoking the hash or signature */
266 return t_cose_err_to_dpe_err(cose_return_value);
267 }
268
Tamas Ban257471b2024-03-25 13:49:53 +0100269 /* If only a single certificate is created then encoding can be finished.
270 * Otherwise, when multiple certifcate is encoded in a raw
271 * (GetCertificateChain) then encoding will be finished
272 * by close_certificate_chain().
Maulik Patel2358bbb2023-07-21 10:56:56 +0100273 */
Tamas Ban257471b2024-03-25 13:49:53 +0100274 if (finish_cbor_encoding) {
275 /* Finally close off the CBOR formatting and get the pointer and length
276 * of the resulting COSE_Sign1.
277 */
278 qcbor_result = QCBOREncode_Finish(cbor_enc_ctx, completed_cert);
279 if (qcbor_result == QCBOR_ERR_BUFFER_TOO_SMALL) {
280 return DPE_INSUFFICIENT_MEMORY;
281 } else if (qcbor_result != QCBOR_SUCCESS) {
282 /* likely from array not closed, too many closes, ... */
283 return DPE_INTERNAL_ERROR;
Tamas Ban257471b2024-03-25 13:49:53 +0100284 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100285 }
Maulik Patel77186392024-04-15 12:39:04 +0100286
287 return DPE_NO_ERROR;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100288}
289
290static void encode_sw_component_measurements(QCBOREncodeContext *encode_ctx,
291 struct component_context_t *component_ctx)
292{
293 QCBOREncode_OpenMap(encode_ctx);
294
295 /* Encode measurement value as byte string */
296 QCBOREncode_AddBytesToMapN(encode_ctx,
297 DPE_CERT_LABEL_CODE_HASH,
298 (UsefulBufC){ &component_ctx->data.measurement_value,
299 DICE_HASH_SIZE });
300
301 /* Encode measurement descriptor version as byte string */
302 QCBOREncode_AddBytesToMapN(encode_ctx,
303 DPE_CERT_LABEL_CODE_DESCRIPTOR,
304 (UsefulBufC){ &component_ctx->data.measurement_descriptor,
305 component_ctx->data.measurement_descriptor_size });
306
307 /* Encode signer ID Hash as byte string */
308 QCBOREncode_AddBytesToMapN(encode_ctx,
309 DPE_CERT_LABEL_AUTHORITY_HASH,
310 (UsefulBufC){ &component_ctx->data.signer_id,
311 DICE_HASH_SIZE });
312
313 /* Encode signer ID descriptor as byte string */
314 QCBOREncode_AddBytesToMapN(encode_ctx,
315 DPE_CERT_LABEL_AUTHORITY_DESCRIPTOR,
316 (UsefulBufC){ &component_ctx->data.signer_id_descriptor,
317 component_ctx->data.signer_id_descriptor_size });
318
319 if (component_ctx->data.config_descriptor_size > 0) {
320 /* Encode config descriptor as byte string */
321 QCBOREncode_AddBytesToMapN(encode_ctx,
322 DPE_CERT_LABEL_CONFIGURATION_DESCRIPTOR,
323 (UsefulBufC){ &component_ctx->data.config_descriptor,
324 component_ctx->data.config_descriptor_size });
325 /* Encode config value as byte string */
326 QCBOREncode_AddBytesToMapN(encode_ctx,
327 DPE_CERT_LABEL_CONFIGURATION_HASH,
328 (UsefulBufC){ &component_ctx->data.config_value,
329 DICE_INLINE_CONFIG_SIZE });
330 } else {
331 /* Encode config value as byte string */
332 QCBOREncode_AddBytesToMapN(encode_ctx,
333 DPE_CERT_LABEL_CONFIGURATION_DESCRIPTOR,
334 (UsefulBufC){ &component_ctx->data.config_value,
335 DICE_INLINE_CONFIG_SIZE });
336 }
337
338 /* Encode mode value as byte string */
339 QCBOREncode_AddBytesToMapN(encode_ctx,
340 DPE_CERT_LABEL_MODE,
341 (UsefulBufC){ &component_ctx->data.mode,
342 sizeof(DiceMode) });
343
344 QCBOREncode_CloseMap(encode_ctx);
345}
346
Maulik Patel97a61fe2024-07-01 15:55:04 +0100347static dpe_error_t encode_sw_components_array(const struct cert_context_t *cert_ctx,
348 QCBOREncodeContext *cbor_enc_ctx)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100349{
Maulik Patel009450d2024-04-23 12:03:10 +0100350 int i;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100351 struct component_context_t *component_ctx;
352
Tamas Bancb237ce2024-05-03 14:01:33 +0200353 /* Open array which stores SW components claims. */
354 QCBOREncode_OpenArrayInMapN(cbor_enc_ctx, DPE_CERT_LABEL_SW_COMPONENTS);
355
356 /* Add elements to the array if there is any */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100357 for (i = 0; i < cert_ctx->linked_components.count; i++) {
Maulik Patel00d06b62024-07-03 14:51:50 +0100358 component_ctx = cert_ctx->linked_components.ptr[i];
Tamas Bancb237ce2024-05-03 14:01:33 +0200359 if (component_ctx == NULL) {
360 return DPE_INTERNAL_ERROR;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100361 }
Tamas Bancb237ce2024-05-03 14:01:33 +0200362 encode_sw_component_measurements(cbor_enc_ctx, component_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100363 }
Maulik Patel009450d2024-04-23 12:03:10 +0100364
Tamas Bancb237ce2024-05-03 14:01:33 +0200365 /* Close array which stores SW components claims. */
366 QCBOREncode_CloseArray(cbor_enc_ctx);
367
Maulik Patel009450d2024-04-23 12:03:10 +0100368 return DPE_NO_ERROR;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100369}
370
Tamas Ban257471b2024-03-25 13:49:53 +0100371static dpe_error_t add_issuer_claim(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100372 const struct cert_context_t *cert_ctx,
Jamie Fox93225232023-09-22 14:09:30 +0100373 psa_key_id_t root_attest_key_id,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100374 const struct cert_context_t *parent_cert_ctx)
Jamie Fox93225232023-09-22 14:09:30 +0100375{
376 uint8_t rot_cdi_id[DICE_ID_SIZE];
377
Maulik Patel97a61fe2024-07-01 15:55:04 +0100378 if (cert_ctx->is_rot_cert_ctx) {
379 /* For the RoT certificate, issuer id is derived from the root attestation key */
Jamie Fox93225232023-09-22 14:09:30 +0100380 if (derive_cdi_id(root_attest_key_id, rot_cdi_id,
381 sizeof(rot_cdi_id)) != PSA_SUCCESS) {
382 return DPE_INTERNAL_ERROR;
383 }
384
Tamas Ban257471b2024-03-25 13:49:53 +0100385 encode_issuer_claim(cbor_enc_ctx,
Jamie Fox93225232023-09-22 14:09:30 +0100386 rot_cdi_id,
387 sizeof(rot_cdi_id));
388 } else {
Tamas Ban257471b2024-03-25 13:49:53 +0100389 encode_issuer_claim(cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100390 parent_cert_ctx->data.cdi_id,
391 sizeof(parent_cert_ctx->data.cdi_id));
Jamie Fox93225232023-09-22 14:09:30 +0100392 }
393
394 return DPE_NO_ERROR;
395}
Maulik Patel2358bbb2023-07-21 10:56:56 +0100396
Maulik Patel97a61fe2024-07-01 15:55:04 +0100397static dpe_error_t encode_certificate_internal(const struct cert_context_t *cert_ctx,
398 QCBOREncodeContext *cbor_enc_ctx,
399 bool finish_cbor_encoding,
400 size_t *cert_actual_size)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100401{
Tamas Ban257471b2024-03-25 13:49:53 +0100402 struct t_cose_sign1_sign_ctx signer_ctx;
Maulik Patel97a61fe2024-07-01 15:55:04 +0100403 struct cert_context_t *parent_cert_ctx;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100404 dpe_error_t err;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100405 UsefulBufC completed_cert;
Jamie Fox93225232023-09-22 14:09:30 +0100406 psa_key_id_t attest_key_id;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100407
Tamas Ban257471b2024-03-25 13:49:53 +0100408 /* Valid options: true & !NULL OR false & NULL */
409 assert(finish_cbor_encoding ^ (cert_actual_size == NULL));
410
Maulik Patel00d06b62024-07-03 14:51:50 +0100411 parent_cert_ctx = cert_ctx->parent_cert_ptr;
412 assert(parent_cert_ctx != NULL);
Tamas Ban257471b2024-03-25 13:49:53 +0100413
Maulik Patel97a61fe2024-07-01 15:55:04 +0100414 /* The RoT certificate is signed by the provisioned attestation key,
415 * all other certificates are signed by the parent certificate's attestation key.
Jamie Fox93225232023-09-22 14:09:30 +0100416 */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100417 if (cert_ctx->is_rot_cert_ctx) {
Jamie Fox93225232023-09-22 14:09:30 +0100418 attest_key_id = dpe_plat_get_root_attest_key_id();
419 } else {
Maulik Patel97a61fe2024-07-01 15:55:04 +0100420 attest_key_id = parent_cert_ctx->data.attest_key_id;
Jamie Fox93225232023-09-22 14:09:30 +0100421 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100422
Tamas Ban257471b2024-03-25 13:49:53 +0100423 /* Get started creating the certificate. This sets up the CBOR and
Maulik Patel2358bbb2023-07-21 10:56:56 +0100424 * COSE contexts which causes the COSE headers to be constructed.
425 */
Tamas Ban257471b2024-03-25 13:49:53 +0100426 err = certificate_encode_start(cbor_enc_ctx,
427 &signer_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100428 attest_key_id);
429 if (err != DPE_NO_ERROR) {
430 return err;
431 }
432
433 /* Add all the required claims */
434 /* Add issuer/authority claim */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100435 err = add_issuer_claim(cbor_enc_ctx, cert_ctx, attest_key_id, parent_cert_ctx);
Jamie Fox93225232023-09-22 14:09:30 +0100436 if (err != DPE_NO_ERROR) {
437 return err;
438 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100439
440 /* Add subject claim */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100441 add_subject_claim(cbor_enc_ctx, cert_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100442
Maulik Patel97a61fe2024-07-01 15:55:04 +0100443 /* Encode all firmware measurements for the components linked to this
444 * certificate context
445 */
Maulik Patel2358bbb2023-07-21 10:56:56 +0100446 //TODO:
447 /* It is not yet defined in the open-dice profile how to represent
448 * multiple SW components in a single certificate; In current implementation,
449 * an array is created for all the components' measurements and within the
450 * array, there are multiple maps, one for each SW component
451 */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100452 err = encode_sw_components_array(cert_ctx, cbor_enc_ctx);
Maulik Patel009450d2024-04-23 12:03:10 +0100453 if (err != DPE_NO_ERROR) {
454 return err;
455 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100456
Maulik Patele6adc112023-08-18 14:21:51 +0100457 /* Add label claim */
Tamas Ban257471b2024-03-25 13:49:53 +0100458 add_label_claim(cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100459 &cert_ctx->data.external_key_deriv_label[0],
460 cert_ctx->data.external_key_deriv_label_len);
Maulik Patele6adc112023-08-18 14:21:51 +0100461
Maulik Patel2358bbb2023-07-21 10:56:56 +0100462 /* Add public key claim */
Tamas Ban257471b2024-03-25 13:49:53 +0100463 add_public_key_claim(cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100464 &cert_ctx->data.attest_pub_key[0],
465 cert_ctx->data.attest_pub_key_len);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100466
467 /* Add key usage claim */
Tamas Ban257471b2024-03-25 13:49:53 +0100468 add_key_usage_claim(cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100469
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000470 /* Add CDI exported claim */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100471 if (cert_ctx->is_cdi_to_be_exported) {
472 add_cdi_export_claim(cbor_enc_ctx, cert_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000473 }
474
Tamas Ban257471b2024-03-25 13:49:53 +0100475 /* Finish up creating the certificate. This is where the actual signature
476 * is generated.
Maulik Patel2358bbb2023-07-21 10:56:56 +0100477 */
Tamas Ban257471b2024-03-25 13:49:53 +0100478 err = certificate_encode_finish(cbor_enc_ctx, &signer_ctx,
479 finish_cbor_encoding, &completed_cert);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100480 if (err != DPE_NO_ERROR) {
481 return err;
482 }
483
Tamas Ban257471b2024-03-25 13:49:53 +0100484 /* Update the final size of the certificate if requested */
485 if (cert_actual_size != NULL) {
486 *cert_actual_size = completed_cert.len;
487 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100488
489 return err;
490}
491
Maulik Patel97a61fe2024-07-01 15:55:04 +0100492dpe_error_t encode_certificate(const struct cert_context_t *cert_ctx,
493 uint8_t *cert_buf,
494 size_t cert_buf_size,
495 size_t *cert_actual_size)
Tamas Ban257471b2024-03-25 13:49:53 +0100496{
497 QCBOREncodeContext cbor_enc_ctx;
498
499 QCBOREncode_Init(&cbor_enc_ctx,
500 (UsefulBuf){ cert_buf,
501 cert_buf_size });
502
503 /* Only a single certificate is encoded */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100504 return encode_certificate_internal(cert_ctx, &cbor_enc_ctx,
505 true, cert_actual_size);
Tamas Ban257471b2024-03-25 13:49:53 +0100506}
507
Maulik Patel97a61fe2024-07-01 15:55:04 +0100508dpe_error_t store_certificate(const struct cert_context_t *cert_ctx)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100509{
510 //TODO:
Maulik Patel97a61fe2024-07-01 15:55:04 +0100511 (void)cert_ctx;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100512 return DPE_NO_ERROR;
513}
Maulik Patele6adc112023-08-18 14:21:51 +0100514
Tamas Ban257471b2024-03-25 13:49:53 +0100515static void open_certificate_chain(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100516 uint8_t *cert_chain_buf,
517 size_t cert_chain_buf_size)
518{
519 /* Set up encoding context with output buffer. */
Tamas Ban257471b2024-03-25 13:49:53 +0100520 QCBOREncode_Init(cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100521 (UsefulBuf){ &cert_chain_buf[0],
522 cert_chain_buf_size });
Tamas Ban257471b2024-03-25 13:49:53 +0100523 QCBOREncode_OpenArray(cbor_enc_ctx);
Maulik Patele6adc112023-08-18 14:21:51 +0100524}
525
Tamas Ban257471b2024-03-25 13:49:53 +0100526static dpe_error_t close_certificate_chain(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100527 size_t *cert_chain_actual_size)
528{
529 QCBORError encode_error;
530 UsefulBufC completed_cert_chain;
531
Tamas Ban257471b2024-03-25 13:49:53 +0100532 QCBOREncode_CloseArray(cbor_enc_ctx);
Maulik Patele6adc112023-08-18 14:21:51 +0100533
Tamas Ban257471b2024-03-25 13:49:53 +0100534 encode_error = QCBOREncode_Finish(cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100535 &completed_cert_chain);
536
537 /* Check for any encoding errors. */
538 if (encode_error == QCBOR_ERR_BUFFER_TOO_SMALL) {
539 return DPE_INSUFFICIENT_MEMORY;
540 } else if (encode_error != QCBOR_SUCCESS) {
541 return DPE_INTERNAL_ERROR;
542 }
543
544 *cert_chain_actual_size = completed_cert_chain.len;
545
546 return DPE_NO_ERROR;
547}
548
Tamas Ban257471b2024-03-25 13:49:53 +0100549static dpe_error_t add_root_attestation_public_key(QCBOREncodeContext *cbor_enc_ctx)
Maulik Patele6adc112023-08-18 14:21:51 +0100550{
551 psa_status_t status;
552 psa_key_id_t attest_key_id;
553 uint8_t attest_pub_key[DPE_ATTEST_PUB_KEY_SIZE];
554 size_t attest_pub_key_len;
555
556 attest_key_id = dpe_plat_get_root_attest_key_id();
557
558 status = psa_export_public_key(attest_key_id, attest_pub_key,
559 sizeof(attest_pub_key), &attest_pub_key_len);
560 if (status != PSA_SUCCESS) {
561 return DPE_INTERNAL_ERROR;
562 }
563
Tamas Ban257471b2024-03-25 13:49:53 +0100564 add_public_key_to_certificate_chain(cbor_enc_ctx, &attest_pub_key[0], attest_pub_key_len);
Maulik Patele6adc112023-08-18 14:21:51 +0100565
566 return DPE_NO_ERROR;
567}
568
Maulik Patel97a61fe2024-07-01 15:55:04 +0100569dpe_error_t get_certificate_chain(const struct cert_context_t *cert_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100570 uint8_t *cert_chain_buf,
571 size_t cert_chain_buf_size,
572 size_t *cert_chain_actual_size)
573{
Tamas Ban257471b2024-03-25 13:49:53 +0100574 QCBOREncodeContext cbor_enc_ctx;
Maulik Patele6adc112023-08-18 14:21:51 +0100575 dpe_error_t err;
576 int i;
Maulik Patel00d06b62024-07-03 14:51:50 +0100577 const struct cert_context_t *cert_chain[MAX_NUM_OF_CERTIFICATES];
Maulik Patel97a61fe2024-07-01 15:55:04 +0100578 uint16_t cert_cnt = 0;
Maulik Patele6adc112023-08-18 14:21:51 +0100579
Tamas Ban257471b2024-03-25 13:49:53 +0100580 open_certificate_chain(&cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100581 cert_chain_buf,
582 cert_chain_buf_size);
583
584 /* Add DICE/Root public key (IAK public key) as the first entry of array */
Tamas Ban257471b2024-03-25 13:49:53 +0100585 err = add_root_attestation_public_key(&cbor_enc_ctx);
Maulik Patele6adc112023-08-18 14:21:51 +0100586 if (err != DPE_NO_ERROR) {
587 return err;
588 }
589
Maulik Patel97a61fe2024-07-01 15:55:04 +0100590 /* Loop from leaf to the RoT certificate & save all the linked certificates in this chain */
Maulik Patel00d06b62024-07-03 14:51:50 +0100591 while ((cert_ctx != NULL) && (cert_cnt < MAX_NUM_OF_CERTIFICATES)) {
Maulik Patele6adc112023-08-18 14:21:51 +0100592
Maulik Patel00d06b62024-07-03 14:51:50 +0100593 /* Save certificate context pointer */
594 cert_chain[cert_cnt++] = cert_ctx;
Maulik Patele6adc112023-08-18 14:21:51 +0100595
Maulik Patel00d06b62024-07-03 14:51:50 +0100596 if (cert_ctx->is_rot_cert_ctx) {
Maulik Patele6adc112023-08-18 14:21:51 +0100597 /* This is the end of chain */
598 break;
599 }
600
Maulik Patel97a61fe2024-07-01 15:55:04 +0100601 /* Move to the parent certificate context */
Maulik Patel00d06b62024-07-03 14:51:50 +0100602 cert_ctx = cert_ctx->parent_cert_ptr;
Maulik Patele6adc112023-08-18 14:21:51 +0100603 }
604
Maulik Patel97a61fe2024-07-01 15:55:04 +0100605 /* Add certificate from RoT to leaf certificate order */
Maulik Patel00d06b62024-07-03 14:51:50 +0100606 for (i = cert_cnt - 1; i >= 0; i--) {
Tamas Ban257471b2024-03-25 13:49:53 +0100607 /* Might multiple certificate is encoded */
Maulik Patel00d06b62024-07-03 14:51:50 +0100608 err = encode_certificate_internal(cert_chain[i], &cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100609 false, NULL);
Tamas Ban257471b2024-03-25 13:49:53 +0100610 if (err != DPE_NO_ERROR) {
611 return err;
612 }
Maulik Patele6adc112023-08-18 14:21:51 +0100613 }
614
Tamas Ban257471b2024-03-25 13:49:53 +0100615 return close_certificate_chain(&cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100616 cert_chain_actual_size);
617}
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000618
Tamas Ban5179a4d2024-01-25 17:05:30 +0100619dpe_error_t encode_cdi(const uint8_t cdi_attest_buf[DICE_CDI_SIZE],
620 const uint8_t cdi_seal_buf[DICE_CDI_SIZE],
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000621 uint8_t *encoded_cdi_buf,
622 size_t encoded_cdi_buf_size,
623 size_t *encoded_cdi_actual_size)
624{
625 QCBOREncodeContext encode_ctx;
626 QCBORError encode_err;
627 UsefulBufC out;
628
629 QCBOREncode_Init(&encode_ctx, (UsefulBuf){ encoded_cdi_buf, encoded_cdi_buf_size });
630 QCBOREncode_OpenMap(&encode_ctx);
631
632 /* Encode CDI value as byte string */
633 QCBOREncode_AddBytesToMapN(&encode_ctx,
634 DPE_LABEL_CDI_ATTEST,
Tamas Ban5179a4d2024-01-25 17:05:30 +0100635 (UsefulBufC){ cdi_attest_buf, DICE_CDI_SIZE });
636
637 QCBOREncode_AddBytesToMapN(&encode_ctx,
638 DPE_LABEL_CDI_SEAL,
639 (UsefulBufC){ cdi_seal_buf, DICE_CDI_SIZE });
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000640
641 QCBOREncode_CloseMap(&encode_ctx);
642 encode_err = QCBOREncode_Finish(&encode_ctx, &out);
643
644 /* Check for any encoding errors. */
645 if (encode_err == QCBOR_ERR_BUFFER_TOO_SMALL) {
646 return DPE_INSUFFICIENT_MEMORY;
647 } else if (encode_err != QCBOR_SUCCESS) {
648 return DPE_INTERNAL_ERROR;
649 }
650
651 *encoded_cdi_actual_size = out.len;
652
653 return DPE_NO_ERROR;
654}