blob: dcaf68ec3bf0864d71f3a11596b76f09f4b55651 [file] [log] [blame]
Maulik Patel2358bbb2023-07-21 10:56:56 +01001/*
David Vincze6edb83b2025-01-13 17:34:16 +00002 * Copyright (c) 2023-2025, 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"
David Vincze6edb83b2025-01-13 17:34:16 +000015#include "t_cose/t_cose_common.h"
16#include "t_cose/t_cose_key.h"
17#include "t_cose/t_cose_sign1_sign.h"
Maulik Patel2358bbb2023-07-21 10:56:56 +010018
19#define ID_HEX_SIZE (2 * DICE_ID_SIZE) /* Size of CDI encoded to ascii hex */
Maulik Patele6adc112023-08-18 14:21:51 +010020#define LABEL_HEX_SIZE (2 * DPE_EXTERNAL_LABEL_MAX_SIZE)
Maulik Patel2358bbb2023-07-21 10:56:56 +010021
Maulik Patel2358bbb2023-07-21 10:56:56 +010022static void convert_to_ascii_hex(const uint8_t *in,
23 size_t in_size,
24 char *out,
25 size_t out_size)
26{
27 const char hex_table[] = "0123456789abcdef";
28 size_t in_pos = 0;
29 size_t out_pos = 0;
30
31 for (in_pos = 0; in_pos < in_size && out_pos < out_size; in_pos++) {
Aditya Deshpande74a01ef2025-01-23 14:34:34 +000032 out[out_pos++] = hex_table[(in[in_pos] & 0xF0) >> 4];
Maulik Patel2358bbb2023-07-21 10:56:56 +010033 out[out_pos++] = hex_table[in[in_pos] & 0x0F];
34 }
35}
36
37static dpe_error_t t_cose_err_to_dpe_err(enum t_cose_err_t err)
38{
39 switch(err) {
40
41 case T_COSE_SUCCESS:
42 return DPE_NO_ERROR;
43
44 case T_COSE_ERR_TOO_SMALL:
45 return DPE_INSUFFICIENT_MEMORY;
46
47 default:
48 /* A lot of the errors are not mapped because they are
49 * primarily internal errors that should never happen. They
50 * end up here.
51 */
52 return DPE_INTERNAL_ERROR;
53 }
54}
55
Tamas Ban257471b2024-03-25 13:49:53 +010056static dpe_error_t certificate_encode_start(QCBOREncodeContext *cbor_enc_ctx,
57 struct t_cose_sign1_sign_ctx *signer_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +010058 psa_key_handle_t private_key)
59{
60 enum t_cose_err_t t_cose_err;
61 struct t_cose_key attest_key;
62 UsefulBufC attest_key_id = {NULL, 0};
63
64 /* DPE Certificate is untagged COSE_Sign1 message */
Tamas Ban257471b2024-03-25 13:49:53 +010065 t_cose_sign1_sign_init(signer_ctx, T_COSE_OPT_OMIT_CBOR_TAG, DPE_T_COSE_ALG);
Maulik Patel2358bbb2023-07-21 10:56:56 +010066
David Vincze6edb83b2025-01-13 17:34:16 +000067 attest_key.key.handle = private_key;
Maulik Patel2358bbb2023-07-21 10:56:56 +010068
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 Ban769966d2024-09-27 14:35:05 +0200159static dpe_error_t encode_public_key(QCBOREncodeContext *cbor_enc_ctx,
160 psa_key_id_t attest_key_id)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100161{
Tamas Ban769966d2024-09-27 14:35:05 +0200162 Q_USEFUL_BUF_MAKE_STACK_UB(cose_key_buf, MAX_ENCODED_COSE_KEY_SIZE);
163 struct t_cose_key attest_key;
164 struct q_useful_buf_c cose_key;
165 enum t_cose_err_t cose_res;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100166
Tamas Ban769966d2024-09-27 14:35:05 +0200167 /* Export the public key and encodes it to be a COSE_Key object */
David Vincze6edb83b2025-01-13 17:34:16 +0000168 attest_key.key.handle = attest_key_id;
Tamas Ban769966d2024-09-27 14:35:05 +0200169 cose_res = t_cose_key_encode(attest_key,
170 cose_key_buf,
171 &cose_key);
172 if (cose_res != T_COSE_SUCCESS) {
173 return DPE_INTERNAL_ERROR;
174 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100175
Tamas Ban769966d2024-09-27 14:35:05 +0200176 QCBOREncode_AddEncoded(cbor_enc_ctx, cose_key);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100177
Tamas Ban769966d2024-09-27 14:35:05 +0200178 return DPE_NO_ERROR;
179}
Maulik Patel2358bbb2023-07-21 10:56:56 +0100180
Tamas Ban769966d2024-09-27 14:35:05 +0200181static dpe_error_t add_public_key_claim(QCBOREncodeContext *cbor_enc_ctx,
182 psa_key_id_t attest_key_id)
183{
184 dpe_error_t err;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100185
Tamas Ban769966d2024-09-27 14:35:05 +0200186 /* COSE_Key is encoded as a map. This map is wrapped into the a
187 * byte string and it is further encoded as a map.
Tamas Ban8ed52802024-03-14 09:36:05 +0100188 */
Tamas Ban257471b2024-03-25 13:49:53 +0100189 QCBOREncode_BstrWrapInMapN(cbor_enc_ctx, DPE_CERT_LABEL_SUBJECT_PUBLIC_KEY);
Tamas Ban769966d2024-09-27 14:35:05 +0200190 err = encode_public_key(cbor_enc_ctx, attest_key_id);
191 if (err != DPE_NO_ERROR) {
192 return err;
193 }
194 QCBOREncode_CloseBstrWrap2(cbor_enc_ctx, false, NULL);
195
196 return DPE_NO_ERROR;
Maulik Patele6adc112023-08-18 14:21:51 +0100197}
198
Tamas Ban769966d2024-09-27 14:35:05 +0200199static dpe_error_t add_public_key_to_certificate_chain(QCBOREncodeContext *cbor_enc_ctx,
200 psa_key_id_t attest_key_id)
Maulik Patele6adc112023-08-18 14:21:51 +0100201{
Tamas Ban769966d2024-09-27 14:35:05 +0200202 dpe_error_t err;
Maulik Patele6adc112023-08-18 14:21:51 +0100203
Tamas Ban769966d2024-09-27 14:35:05 +0200204 /* COSE_Key is encoded as a map wrapped into a byte string */
Tamas Ban257471b2024-03-25 13:49:53 +0100205 QCBOREncode_BstrWrap(cbor_enc_ctx);
Tamas Ban769966d2024-09-27 14:35:05 +0200206 err = encode_public_key(cbor_enc_ctx, attest_key_id);
207 if (err != DPE_NO_ERROR) {
208 return err;
209 }
210 QCBOREncode_CloseBstrWrap2(cbor_enc_ctx, false, NULL);
211
212 return DPE_NO_ERROR;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100213}
214
Tamas Ban257471b2024-03-25 13:49:53 +0100215static dpe_error_t certificate_encode_finish(QCBOREncodeContext *cbor_enc_ctx,
216 struct t_cose_sign1_sign_ctx *signer_ctx,
217 bool finish_cbor_encoding,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100218 UsefulBufC *completed_cert)
219{
220 QCBORError qcbor_result;
221 enum t_cose_err_t cose_return_value;
222
Tamas Ban257471b2024-03-25 13:49:53 +0100223 QCBOREncode_CloseMap(cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100224
225 /* -- Finish up the COSE_Sign1. This is where the signing happens -- */
Tamas Ban257471b2024-03-25 13:49:53 +0100226 cose_return_value = t_cose_sign1_encode_signature(signer_ctx,
227 cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100228 if (cose_return_value) {
229 /* Main errors are invoking the hash or signature */
230 return t_cose_err_to_dpe_err(cose_return_value);
231 }
232
Tamas Ban257471b2024-03-25 13:49:53 +0100233 /* If only a single certificate is created then encoding can be finished.
234 * Otherwise, when multiple certifcate is encoded in a raw
235 * (GetCertificateChain) then encoding will be finished
236 * by close_certificate_chain().
Maulik Patel2358bbb2023-07-21 10:56:56 +0100237 */
Tamas Ban257471b2024-03-25 13:49:53 +0100238 if (finish_cbor_encoding) {
239 /* Finally close off the CBOR formatting and get the pointer and length
240 * of the resulting COSE_Sign1.
241 */
242 qcbor_result = QCBOREncode_Finish(cbor_enc_ctx, completed_cert);
243 if (qcbor_result == QCBOR_ERR_BUFFER_TOO_SMALL) {
244 return DPE_INSUFFICIENT_MEMORY;
245 } else if (qcbor_result != QCBOR_SUCCESS) {
246 /* likely from array not closed, too many closes, ... */
247 return DPE_INTERNAL_ERROR;
Tamas Ban257471b2024-03-25 13:49:53 +0100248 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100249 }
Maulik Patel77186392024-04-15 12:39:04 +0100250
251 return DPE_NO_ERROR;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100252}
253
254static void encode_sw_component_measurements(QCBOREncodeContext *encode_ctx,
255 struct component_context_t *component_ctx)
256{
257 QCBOREncode_OpenMap(encode_ctx);
258
259 /* Encode measurement value as byte string */
260 QCBOREncode_AddBytesToMapN(encode_ctx,
261 DPE_CERT_LABEL_CODE_HASH,
262 (UsefulBufC){ &component_ctx->data.measurement_value,
263 DICE_HASH_SIZE });
264
265 /* Encode measurement descriptor version as byte string */
266 QCBOREncode_AddBytesToMapN(encode_ctx,
267 DPE_CERT_LABEL_CODE_DESCRIPTOR,
268 (UsefulBufC){ &component_ctx->data.measurement_descriptor,
269 component_ctx->data.measurement_descriptor_size });
270
271 /* Encode signer ID Hash as byte string */
272 QCBOREncode_AddBytesToMapN(encode_ctx,
273 DPE_CERT_LABEL_AUTHORITY_HASH,
274 (UsefulBufC){ &component_ctx->data.signer_id,
275 DICE_HASH_SIZE });
276
277 /* Encode signer ID descriptor as byte string */
278 QCBOREncode_AddBytesToMapN(encode_ctx,
279 DPE_CERT_LABEL_AUTHORITY_DESCRIPTOR,
280 (UsefulBufC){ &component_ctx->data.signer_id_descriptor,
281 component_ctx->data.signer_id_descriptor_size });
282
283 if (component_ctx->data.config_descriptor_size > 0) {
284 /* Encode config descriptor as byte string */
285 QCBOREncode_AddBytesToMapN(encode_ctx,
286 DPE_CERT_LABEL_CONFIGURATION_DESCRIPTOR,
287 (UsefulBufC){ &component_ctx->data.config_descriptor,
288 component_ctx->data.config_descriptor_size });
289 /* Encode config value as byte string */
290 QCBOREncode_AddBytesToMapN(encode_ctx,
291 DPE_CERT_LABEL_CONFIGURATION_HASH,
292 (UsefulBufC){ &component_ctx->data.config_value,
293 DICE_INLINE_CONFIG_SIZE });
294 } else {
295 /* Encode config value as byte string */
296 QCBOREncode_AddBytesToMapN(encode_ctx,
297 DPE_CERT_LABEL_CONFIGURATION_DESCRIPTOR,
298 (UsefulBufC){ &component_ctx->data.config_value,
299 DICE_INLINE_CONFIG_SIZE });
300 }
301
302 /* Encode mode value as byte string */
303 QCBOREncode_AddBytesToMapN(encode_ctx,
304 DPE_CERT_LABEL_MODE,
305 (UsefulBufC){ &component_ctx->data.mode,
306 sizeof(DiceMode) });
307
308 QCBOREncode_CloseMap(encode_ctx);
309}
310
Maulik Patel97a61fe2024-07-01 15:55:04 +0100311static dpe_error_t encode_sw_components_array(const struct cert_context_t *cert_ctx,
312 QCBOREncodeContext *cbor_enc_ctx)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100313{
Maulik Patel009450d2024-04-23 12:03:10 +0100314 int i;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100315 struct component_context_t *component_ctx;
316
Tamas Bancb237ce2024-05-03 14:01:33 +0200317 /* Open array which stores SW components claims. */
318 QCBOREncode_OpenArrayInMapN(cbor_enc_ctx, DPE_CERT_LABEL_SW_COMPONENTS);
319
320 /* Add elements to the array if there is any */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100321 for (i = 0; i < cert_ctx->linked_components.count; i++) {
Maulik Patel00d06b62024-07-03 14:51:50 +0100322 component_ctx = cert_ctx->linked_components.ptr[i];
Tamas Bancb237ce2024-05-03 14:01:33 +0200323 if (component_ctx == NULL) {
324 return DPE_INTERNAL_ERROR;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100325 }
Tamas Bancb237ce2024-05-03 14:01:33 +0200326 encode_sw_component_measurements(cbor_enc_ctx, component_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100327 }
Maulik Patel009450d2024-04-23 12:03:10 +0100328
Tamas Bancb237ce2024-05-03 14:01:33 +0200329 /* Close array which stores SW components claims. */
330 QCBOREncode_CloseArray(cbor_enc_ctx);
331
Maulik Patel009450d2024-04-23 12:03:10 +0100332 return DPE_NO_ERROR;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100333}
334
Tamas Ban257471b2024-03-25 13:49:53 +0100335static dpe_error_t add_issuer_claim(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100336 const struct cert_context_t *cert_ctx,
Jamie Fox93225232023-09-22 14:09:30 +0100337 psa_key_id_t root_attest_key_id,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100338 const struct cert_context_t *parent_cert_ctx)
Jamie Fox93225232023-09-22 14:09:30 +0100339{
340 uint8_t rot_cdi_id[DICE_ID_SIZE];
341
Maulik Patel97a61fe2024-07-01 15:55:04 +0100342 if (cert_ctx->is_rot_cert_ctx) {
343 /* For the RoT certificate, issuer id is derived from the root attestation key */
Jamie Fox93225232023-09-22 14:09:30 +0100344 if (derive_cdi_id(root_attest_key_id, rot_cdi_id,
345 sizeof(rot_cdi_id)) != PSA_SUCCESS) {
346 return DPE_INTERNAL_ERROR;
347 }
348
Tamas Ban257471b2024-03-25 13:49:53 +0100349 encode_issuer_claim(cbor_enc_ctx,
Jamie Fox93225232023-09-22 14:09:30 +0100350 rot_cdi_id,
351 sizeof(rot_cdi_id));
352 } else {
Tamas Ban257471b2024-03-25 13:49:53 +0100353 encode_issuer_claim(cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100354 parent_cert_ctx->data.cdi_id,
355 sizeof(parent_cert_ctx->data.cdi_id));
Jamie Fox93225232023-09-22 14:09:30 +0100356 }
357
358 return DPE_NO_ERROR;
359}
Maulik Patel2358bbb2023-07-21 10:56:56 +0100360
Maulik Patel97a61fe2024-07-01 15:55:04 +0100361static dpe_error_t encode_certificate_internal(const struct cert_context_t *cert_ctx,
362 QCBOREncodeContext *cbor_enc_ctx,
363 bool finish_cbor_encoding,
364 size_t *cert_actual_size)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100365{
Tamas Ban257471b2024-03-25 13:49:53 +0100366 struct t_cose_sign1_sign_ctx signer_ctx;
Maulik Patel97a61fe2024-07-01 15:55:04 +0100367 struct cert_context_t *parent_cert_ctx;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100368 dpe_error_t err;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100369 UsefulBufC completed_cert;
Jamie Fox93225232023-09-22 14:09:30 +0100370 psa_key_id_t attest_key_id;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100371
Tamas Ban257471b2024-03-25 13:49:53 +0100372 /* Valid options: true & !NULL OR false & NULL */
373 assert(finish_cbor_encoding ^ (cert_actual_size == NULL));
374
Maulik Patel00d06b62024-07-03 14:51:50 +0100375 parent_cert_ctx = cert_ctx->parent_cert_ptr;
376 assert(parent_cert_ctx != NULL);
Tamas Ban257471b2024-03-25 13:49:53 +0100377
Maulik Patel97a61fe2024-07-01 15:55:04 +0100378 /* The RoT certificate is signed by the provisioned attestation key,
379 * all other certificates are signed by the parent certificate's attestation key.
Jamie Fox93225232023-09-22 14:09:30 +0100380 */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100381 if (cert_ctx->is_rot_cert_ctx) {
Jamie Fox93225232023-09-22 14:09:30 +0100382 attest_key_id = dpe_plat_get_root_attest_key_id();
383 } else {
Maulik Patel97a61fe2024-07-01 15:55:04 +0100384 attest_key_id = parent_cert_ctx->data.attest_key_id;
Jamie Fox93225232023-09-22 14:09:30 +0100385 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100386
Tamas Ban257471b2024-03-25 13:49:53 +0100387 /* Get started creating the certificate. This sets up the CBOR and
Maulik Patel2358bbb2023-07-21 10:56:56 +0100388 * COSE contexts which causes the COSE headers to be constructed.
389 */
Tamas Ban257471b2024-03-25 13:49:53 +0100390 err = certificate_encode_start(cbor_enc_ctx,
391 &signer_ctx,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100392 attest_key_id);
393 if (err != DPE_NO_ERROR) {
394 return err;
395 }
396
397 /* Add all the required claims */
398 /* Add issuer/authority claim */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100399 err = add_issuer_claim(cbor_enc_ctx, cert_ctx, attest_key_id, parent_cert_ctx);
Jamie Fox93225232023-09-22 14:09:30 +0100400 if (err != DPE_NO_ERROR) {
401 return err;
402 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100403
404 /* Add subject claim */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100405 add_subject_claim(cbor_enc_ctx, cert_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100406
Maulik Patel97a61fe2024-07-01 15:55:04 +0100407 /* Encode all firmware measurements for the components linked to this
408 * certificate context
409 */
Maulik Patel2358bbb2023-07-21 10:56:56 +0100410 //TODO:
411 /* It is not yet defined in the open-dice profile how to represent
412 * multiple SW components in a single certificate; In current implementation,
413 * an array is created for all the components' measurements and within the
414 * array, there are multiple maps, one for each SW component
415 */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100416 err = encode_sw_components_array(cert_ctx, cbor_enc_ctx);
Maulik Patel009450d2024-04-23 12:03:10 +0100417 if (err != DPE_NO_ERROR) {
418 return err;
419 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100420
Maulik Patele6adc112023-08-18 14:21:51 +0100421 /* Add label claim */
Tamas Ban257471b2024-03-25 13:49:53 +0100422 add_label_claim(cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100423 &cert_ctx->data.external_key_deriv_label[0],
424 cert_ctx->data.external_key_deriv_label_len);
Maulik Patele6adc112023-08-18 14:21:51 +0100425
Maulik Patel2358bbb2023-07-21 10:56:56 +0100426 /* Add public key claim */
Tamas Ban769966d2024-09-27 14:35:05 +0200427 err = add_public_key_claim(cbor_enc_ctx, cert_ctx->data.attest_key_id);
428 if (err != DPE_NO_ERROR) {
429 return err;
430 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100431
432 /* Add key usage claim */
Tamas Ban257471b2024-03-25 13:49:53 +0100433 add_key_usage_claim(cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100434
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000435 /* Add CDI exported claim */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100436 if (cert_ctx->is_cdi_to_be_exported) {
437 add_cdi_export_claim(cbor_enc_ctx, cert_ctx);
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000438 }
439
Tamas Ban257471b2024-03-25 13:49:53 +0100440 /* Finish up creating the certificate. This is where the actual signature
441 * is generated.
Maulik Patel2358bbb2023-07-21 10:56:56 +0100442 */
Tamas Ban257471b2024-03-25 13:49:53 +0100443 err = certificate_encode_finish(cbor_enc_ctx, &signer_ctx,
444 finish_cbor_encoding, &completed_cert);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100445 if (err != DPE_NO_ERROR) {
446 return err;
447 }
448
Tamas Ban257471b2024-03-25 13:49:53 +0100449 /* Update the final size of the certificate if requested */
450 if (cert_actual_size != NULL) {
451 *cert_actual_size = completed_cert.len;
452 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100453
454 return err;
455}
456
Maulik Patel97a61fe2024-07-01 15:55:04 +0100457dpe_error_t encode_certificate(const struct cert_context_t *cert_ctx,
458 uint8_t *cert_buf,
459 size_t cert_buf_size,
460 size_t *cert_actual_size)
Tamas Ban257471b2024-03-25 13:49:53 +0100461{
462 QCBOREncodeContext cbor_enc_ctx;
463
464 QCBOREncode_Init(&cbor_enc_ctx,
465 (UsefulBuf){ cert_buf,
466 cert_buf_size });
467
468 /* Only a single certificate is encoded */
Maulik Patel97a61fe2024-07-01 15:55:04 +0100469 return encode_certificate_internal(cert_ctx, &cbor_enc_ctx,
470 true, cert_actual_size);
Tamas Ban257471b2024-03-25 13:49:53 +0100471}
472
Maulik Patel97a61fe2024-07-01 15:55:04 +0100473dpe_error_t store_certificate(const struct cert_context_t *cert_ctx)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100474{
475 //TODO:
Maulik Patel97a61fe2024-07-01 15:55:04 +0100476 (void)cert_ctx;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100477 return DPE_NO_ERROR;
478}
Maulik Patele6adc112023-08-18 14:21:51 +0100479
Tamas Ban257471b2024-03-25 13:49:53 +0100480static void open_certificate_chain(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100481 uint8_t *cert_chain_buf,
482 size_t cert_chain_buf_size)
483{
484 /* Set up encoding context with output buffer. */
Tamas Ban257471b2024-03-25 13:49:53 +0100485 QCBOREncode_Init(cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100486 (UsefulBuf){ &cert_chain_buf[0],
487 cert_chain_buf_size });
Tamas Ban257471b2024-03-25 13:49:53 +0100488 QCBOREncode_OpenArray(cbor_enc_ctx);
Maulik Patele6adc112023-08-18 14:21:51 +0100489}
490
Tamas Ban257471b2024-03-25 13:49:53 +0100491static dpe_error_t close_certificate_chain(QCBOREncodeContext *cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100492 size_t *cert_chain_actual_size)
493{
494 QCBORError encode_error;
495 UsefulBufC completed_cert_chain;
496
Tamas Ban257471b2024-03-25 13:49:53 +0100497 QCBOREncode_CloseArray(cbor_enc_ctx);
Maulik Patele6adc112023-08-18 14:21:51 +0100498
Tamas Ban257471b2024-03-25 13:49:53 +0100499 encode_error = QCBOREncode_Finish(cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100500 &completed_cert_chain);
501
502 /* Check for any encoding errors. */
503 if (encode_error == QCBOR_ERR_BUFFER_TOO_SMALL) {
504 return DPE_INSUFFICIENT_MEMORY;
505 } else if (encode_error != QCBOR_SUCCESS) {
506 return DPE_INTERNAL_ERROR;
507 }
508
509 *cert_chain_actual_size = completed_cert_chain.len;
510
511 return DPE_NO_ERROR;
512}
513
Tamas Ban257471b2024-03-25 13:49:53 +0100514static dpe_error_t add_root_attestation_public_key(QCBOREncodeContext *cbor_enc_ctx)
Maulik Patele6adc112023-08-18 14:21:51 +0100515{
Tamas Ban769966d2024-09-27 14:35:05 +0200516 psa_key_id_t attest_key_id = dpe_plat_get_root_attest_key_id();
517 dpe_error_t err;
Maulik Patele6adc112023-08-18 14:21:51 +0100518
Tamas Ban769966d2024-09-27 14:35:05 +0200519 err = add_public_key_to_certificate_chain(cbor_enc_ctx, attest_key_id);
520 if (err != DPE_NO_ERROR) {
521 return err;
Maulik Patele6adc112023-08-18 14:21:51 +0100522 }
523
Maulik Patele6adc112023-08-18 14:21:51 +0100524 return DPE_NO_ERROR;
525}
526
Maulik Patel97a61fe2024-07-01 15:55:04 +0100527dpe_error_t get_certificate_chain(const struct cert_context_t *cert_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100528 uint8_t *cert_chain_buf,
529 size_t cert_chain_buf_size,
530 size_t *cert_chain_actual_size)
531{
Tamas Ban257471b2024-03-25 13:49:53 +0100532 QCBOREncodeContext cbor_enc_ctx;
Maulik Patele6adc112023-08-18 14:21:51 +0100533 dpe_error_t err;
534 int i;
Maulik Patel00d06b62024-07-03 14:51:50 +0100535 const struct cert_context_t *cert_chain[MAX_NUM_OF_CERTIFICATES];
Maulik Patel97a61fe2024-07-01 15:55:04 +0100536 uint16_t cert_cnt = 0;
Maulik Patele6adc112023-08-18 14:21:51 +0100537
Tamas Ban257471b2024-03-25 13:49:53 +0100538 open_certificate_chain(&cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100539 cert_chain_buf,
540 cert_chain_buf_size);
541
542 /* Add DICE/Root public key (IAK public key) as the first entry of array */
Tamas Ban257471b2024-03-25 13:49:53 +0100543 err = add_root_attestation_public_key(&cbor_enc_ctx);
Maulik Patele6adc112023-08-18 14:21:51 +0100544 if (err != DPE_NO_ERROR) {
545 return err;
546 }
547
Maulik Patel97a61fe2024-07-01 15:55:04 +0100548 /* Loop from leaf to the RoT certificate & save all the linked certificates in this chain */
Maulik Patel00d06b62024-07-03 14:51:50 +0100549 while ((cert_ctx != NULL) && (cert_cnt < MAX_NUM_OF_CERTIFICATES)) {
Maulik Patele6adc112023-08-18 14:21:51 +0100550
Maulik Patel00d06b62024-07-03 14:51:50 +0100551 /* Save certificate context pointer */
552 cert_chain[cert_cnt++] = cert_ctx;
Maulik Patele6adc112023-08-18 14:21:51 +0100553
Maulik Patel00d06b62024-07-03 14:51:50 +0100554 if (cert_ctx->is_rot_cert_ctx) {
Maulik Patele6adc112023-08-18 14:21:51 +0100555 /* This is the end of chain */
556 break;
557 }
558
Maulik Patel97a61fe2024-07-01 15:55:04 +0100559 /* Move to the parent certificate context */
Maulik Patel00d06b62024-07-03 14:51:50 +0100560 cert_ctx = cert_ctx->parent_cert_ptr;
Maulik Patele6adc112023-08-18 14:21:51 +0100561 }
562
Maulik Patel97a61fe2024-07-01 15:55:04 +0100563 /* Add certificate from RoT to leaf certificate order */
Maulik Patel00d06b62024-07-03 14:51:50 +0100564 for (i = cert_cnt - 1; i >= 0; i--) {
Tamas Ban257471b2024-03-25 13:49:53 +0100565 /* Might multiple certificate is encoded */
Maulik Patel00d06b62024-07-03 14:51:50 +0100566 err = encode_certificate_internal(cert_chain[i], &cbor_enc_ctx,
Maulik Patel97a61fe2024-07-01 15:55:04 +0100567 false, NULL);
Tamas Ban257471b2024-03-25 13:49:53 +0100568 if (err != DPE_NO_ERROR) {
569 return err;
570 }
Maulik Patele6adc112023-08-18 14:21:51 +0100571 }
572
Tamas Ban257471b2024-03-25 13:49:53 +0100573 return close_certificate_chain(&cbor_enc_ctx,
Maulik Patele6adc112023-08-18 14:21:51 +0100574 cert_chain_actual_size);
575}
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000576
Tamas Ban5179a4d2024-01-25 17:05:30 +0100577dpe_error_t encode_cdi(const uint8_t cdi_attest_buf[DICE_CDI_SIZE],
578 const uint8_t cdi_seal_buf[DICE_CDI_SIZE],
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000579 uint8_t *encoded_cdi_buf,
580 size_t encoded_cdi_buf_size,
581 size_t *encoded_cdi_actual_size)
582{
583 QCBOREncodeContext encode_ctx;
584 QCBORError encode_err;
585 UsefulBufC out;
586
587 QCBOREncode_Init(&encode_ctx, (UsefulBuf){ encoded_cdi_buf, encoded_cdi_buf_size });
588 QCBOREncode_OpenMap(&encode_ctx);
589
590 /* Encode CDI value as byte string */
591 QCBOREncode_AddBytesToMapN(&encode_ctx,
592 DPE_LABEL_CDI_ATTEST,
Tamas Ban5179a4d2024-01-25 17:05:30 +0100593 (UsefulBufC){ cdi_attest_buf, DICE_CDI_SIZE });
594
595 QCBOREncode_AddBytesToMapN(&encode_ctx,
596 DPE_LABEL_CDI_SEAL,
597 (UsefulBufC){ cdi_seal_buf, DICE_CDI_SIZE });
Maulik Patel9fd8bd22023-10-30 10:58:30 +0000598
599 QCBOREncode_CloseMap(&encode_ctx);
600 encode_err = QCBOREncode_Finish(&encode_ctx, &out);
601
602 /* Check for any encoding errors. */
603 if (encode_err == QCBOR_ERR_BUFFER_TOO_SMALL) {
604 return DPE_INSUFFICIENT_MEMORY;
605 } else if (encode_err != QCBOR_SUCCESS) {
606 return DPE_INTERNAL_ERROR;
607 }
608
609 *encoded_cdi_actual_size = out.len;
610
611 return DPE_NO_ERROR;
612}