1 /*
2 * Copyright 2024 The ChromiumOS Authors
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 #include "cbor_boot_param.h"
8 #include "cdi.h"
9 #include "boot_param.h"
10 #include "boot_param_platform.h"
11
12 /* Common structure to build Sig_structure or DICE Handover structure
13 */
14
15 /* Combined headers before cert payload (CWT claims) in DICE handover
16 */
17 struct combined_hdr_s {
18 struct dice_cert_chain_hdr_s cert_chain;
19 struct cdi_cert_hdr_s cert;
20 };
21
22 union header_options_s {
23 uint8_t sig_struct[sizeof(struct combined_hdr_s)];
24 struct combined_hdr_s dice_handover;
25 };
26
27 /* We need the following to be able to fill CDIs in dice_handover_s::hdr
28 * before we temporarily use dice_handover_s::options.sig_struct to calc
29 * signature.
30 */
31 _Static_assert(
32 sizeof(struct combined_hdr_s) >= sizeof(struct cdi_sig_struct_hdr_s),
33 "combined_hdr_s < cdi_sig_struct_hdr_s"
34 );
35
36 struct dice_handover_s {
37 struct dice_handover_hdr_s hdr;
38 union header_options_s options;
39 struct cwt_claims_bstr_s payload;
40 struct cbor_bstr64_s signature;
41 };
42 _Static_assert(
43 sizeof(struct dice_handover_s) - sizeof(struct dice_handover_hdr_s) ==
44 DICE_CHAIN_SIZE,
45 "dice_handover_s != dice_handover_hdr_s + DICE_CHAIN_SIZE"
46 );
47
48 /* BootParam = {
49 * 1 : uint, ; structure version (0)
50 * 2 : GSCBootParam,
51 * 3 : AndroidDiceHandover,
52 * }
53 */
54 #define BOOT_PARAM_VERSION 0
55 struct boot_param_s {
56 /* Map header: 3 entries */
57 uint8_t map_hdr;
58 /* 1. Version: uint(1, 0bytes) => uint(BOOT_PARAM_VERSION, 0bytes) */
59 uint8_t version_label;
60 uint8_t version;
61 /* 2. GSCBootParam: uint(2, 0bytes) => GSCBootParam */
62 uint8_t gsc_boot_param_label;
63 struct gsc_boot_param_s gsc_boot_param;
64 /* 3. AndroidDiceHandover: uint(3, 0bytes) => AndroidDiceHandover */
65 uint8_t dice_handover_label;
66 struct dice_handover_s dice_handover;
67 };
68 _Static_assert(
69 sizeof(struct boot_param_s) == BOOT_PARAM_SIZE,
70 "boot_param_s != BOOT_PARAM_SIZE"
71 );
72
73 /* Context to pass between functions that build the DICE handover structure
74 */
75 struct dice_ctx_s {
76 struct boot_param_s output;
77 struct dice_config_s cfg;
78 };
79
80 /* PCR0 values for various modes - see go/pcr0-tpm2 */
81 static const uint8_t kPcr0NormalMode[DIGEST_BYTES] = {
82 0x89, 0xEA, 0xF3, 0x51, 0x34, 0xB4, 0xB3, 0xC6,
83 0x49, 0xF4, 0x4C, 0x0C, 0x76, 0x5B, 0x96, 0xAE,
84 0xAB, 0x8B, 0xB3, 0x4E, 0xE8, 0x3C, 0xC7, 0xA6,
85 0x83, 0xC4, 0xE5, 0x3D, 0x15, 0x81, 0xC8, 0xC7
86 };
87 static const uint8_t kPcr0RecoveryNormalMode[DIGEST_BYTES] = {
88 0x9F, 0x9E, 0xA8, 0x66, 0xD3, 0xF3, 0x4F, 0xE3,
89 0xA3, 0x11, 0x2A, 0xE9, 0xCB, 0x1F, 0xBA, 0xBC,
90 0x6F, 0xFE, 0x8C, 0xD2, 0x61, 0xD4, 0x24, 0x93,
91 0xBC, 0x68, 0x42, 0xA9, 0xE4, 0xF9, 0x3B, 0x3D
92 };
93
94 /* Const salts - see go/gsc-dice */
95 static const uint8_t kIdSalt[64] = {
96 0xDB, 0xDB, 0xAE, 0xBC, 0x80, 0x20, 0xDA, 0x9F,
97 0xF0, 0xDD, 0x5A, 0x24, 0xC8, 0x3A, 0xA5, 0xA5,
98 0x42, 0x86, 0xDF, 0xC2, 0x63, 0x03, 0x1E, 0x32,
99 0x9B, 0x4D, 0xA1, 0x48, 0x43, 0x06, 0x59, 0xFE,
100 0x62, 0xCD, 0xB5, 0xB7, 0xE1, 0xE0, 0x0F, 0xC6,
101 0x80, 0x30, 0x67, 0x11, 0xEB, 0x44, 0x4A, 0xF7,
102 0x72, 0x09, 0x35, 0x94, 0x96, 0xFC, 0xFF, 0x1D,
103 0xB9, 0x52, 0x0B, 0xA5, 0x1C, 0x7B, 0x29, 0xEA
104 };
105 static const uint8_t kAsymSalt[64] = {
106 0x63, 0xB6, 0xA0, 0x4D, 0x2C, 0x07, 0x7F, 0xC1,
107 0x0F, 0x63, 0x9F, 0x21, 0xDA, 0x79, 0x38, 0x44,
108 0x35, 0x6C, 0xC2, 0xB0, 0xB4, 0x41, 0xB3, 0xA7,
109 0x71, 0x24, 0x03, 0x5C, 0x03, 0xF8, 0xE1, 0xBE,
110 0x60, 0x35, 0xD3, 0x1F, 0x28, 0x28, 0x21, 0xA7,
111 0x45, 0x0A, 0x02, 0x22, 0x2A, 0xB1, 0xB3, 0xCF,
112 0xF1, 0x67, 0x9B, 0x05, 0xAB, 0x1C, 0xA5, 0xD1,
113 0xAF, 0xFB, 0x78, 0x9C, 0xCD, 0x2B, 0x0B, 0x3B
114 };
115 static const uint8_t kSigHdr[2] = CBOR_BSTR64_HDR;
116
117 static const struct cwt_claims_bstr_s kCwtClaimsTemplate = {
118 CWT_CLAIMS_BSTR_HDR,
119 {
120 /* Map header: 10 entries */
121 CBOR_HDR1(CBOR_MAJOR_MAP, 10),
122 /* 1. ISS: uint(1, 0bytes) => tstr(hex(UDS_ID)) */
123 CWT_LABEL_ISS,
124 CBOR_TSTR40_EMPTY, /* CALC - calc from UDS */
125 /* 2. SUB: uint(2, 0bytes) =>
126 * tstr(hex(CDI_ID))
127 */
128 CWT_LABEL_SUB,
129 CBOR_TSTR40_EMPTY, /* CALC - calc from CDI */
130 /* 3. Code Hash: nint(-4670545, 4bytes) =>
131 * bstr(32bytes)
132 */
133 CWT_LABEL_CODE_HASH,
134 CBOR_BSTR32_EMPTY, /* VARIABLE */
135 /* 4. Cfg Hash: nint(-4670547, 4bytes) =>
136 * bstr(32bytes)
137 */
138 CWT_LABEL_CFG_HASH,
139 CBOR_BSTR32_EMPTY, /* CALC - calc from CfgDescr */
140 /* 5. Cfg Descr: nint(-4670548, 4bytes) =>
141 * bstr(struct cfg_descr_s)
142 */
143 CWT_LABEL_CFG_DESCR,
144 /* struct cfg_descr_bstr_s */
145 {
146 CFG_DESCR_BSTR_HDR,
147 /* struct cfg_descr_s */
148 {
149 /* Map header: 6 entries */
150 CBOR_HDR1(CBOR_MAJOR_MAP, 6),
151 /* 1. Comp name: nint(-70002, 4bytes) =>
152 * tstr("CrOS AP FW")
153 */
154 CFG_DESCR_LABEL_COMP_NAME,
155 CFG_DESCR_COMP_NAME,
156 /* 2. Resettable: nint(-70004, 4bytes) => null
157 */
158 CFG_DESCR_LABEL_RESETTABLE,
159 CBOR_NULL,
160 /* 3. Sec ver: nint(-70005, 4bytes) =>
161 * uint(Security ver, 4bytes)
162 */
163 CFG_DESCR_LABEL_SEC_VER,
164 CBOR_UINT32_ZERO, /* VARIABLE */
165 /* 4. APROV status:
166 * nint(-71000, 4bytes) =>
167 * uint(APROV status, 4bytes)
168 */
169 CFG_DESCR_LABEL_APROV_STATUS,
170 CBOR_UINT32_ZERO, /* VARIABLE */
171 /* 5. Vboot status: */
172 /* nint(-71000, 4bytes) => */
173 /* bstr(PCR0, 32bytes) */
174 CFG_DESCR_LABEL_VBOOT_STATUS,
175 CBOR_BSTR32_EMPTY, /* VARIABLE */
176 /* 6. AP FW version: */
177 /* nint(-71002, 4bytes) => */
178 /* bstr(PCR10, 32bytes) */
179 CFG_DESCR_LABEL_AP_FW_VERSION,
180 CBOR_BSTR32_EMPTY, /* VARIABLE */
181 },
182 },
183 /* 6. Auth Hash: nint(-4670549, 4bytes) => bstr(32bytes) */
184 CWT_LABEL_AUTH_HASH,
185 CBOR_BSTR32_EMPTY, /* always zero */
186 /* 7. Mode: nint(-4670551, 4bytes) => bstr(1byte) */
187 CWT_LABEL_MODE,
188 CBOR_BSTR1_EMPTY, /* VARIABLE */
189 /* 8. Subject PK: nint(-4670552, 4bytes) => bstr(COSE_Key) */
190 CWT_LABEL_SUBJECT_PK,
191 /* struct cose_key_ecdsa_bstr_s */
192 {
193 COSE_KEY_ECDSA_BSTR_HDR,
194 /* struct cose_key_ecdsa_s */
195 {
196 /* Map header: 6 entries */
197 CBOR_HDR1(CBOR_MAJOR_MAP, 6),
198 /* 1. Key type: uint(1, 0bytes) =>
199 * uint(2, 0bytes)
200 */
201 COSE_KEY_LABEL_KTY,
202 CBOR_UINT0(2), /* EC2 */
203 /* 2. Algorithm: uint(3, 0bytes) =>
204 * nint(-1, 0bytes)
205 */
206 COSE_KEY_LABEL_ALG,
207 CBOR_NINT0(-7), /* ECDSA w/SHA-256 */
208 /* 3. Key ops: uint(4, 0bytes) =>
209 * array(1) { uint(2, 0bytes) }
210 */
211 COSE_KEY_LABEL_KEY_OPS,
212 CBOR_HDR1(CBOR_MAJOR_ARR, 1),
213 CBOR_UINT0(2),
214 /* 4. Curve: nint(-1, 0bytes) => uint(1, 0bytes)
215 */
216 COSE_KEY_LABEL_CRV,
217 CBOR_UINT0(1), /* P-256 */
218 /* 5. X: nint(-2, 0bytes) =>
219 * bstr(X, 32bytes)
220 */
221 COSE_KEY_LABEL_X,
222 CBOR_BSTR32_EMPTY, /* VARIABLE */
223 /* 6. X: nint(-3, 0bytes) =>
224 * bstr(Y, 32bytes)
225 */
226 COSE_KEY_LABEL_Y,
227 CBOR_BSTR32_EMPTY, /* VARIABLE */
228 },
229 },
230 /* 9. Key Usage: nint(-4670553, 4bytes) => bstr(1byte) */
231 CWT_LABEL_KEY_USAGE,
232 {
233 CBOR_HDR1(CBOR_MAJOR_BSTR, 1),
234 0x20, /* keyCertSign */
235 },
236 /* 10. Profile name: nint(-4670554, 4bytes) => */
237 /* tstr("android.16") */
238 CWT_LABEL_PROFILE_NAME,
239 CWT_PROFILE_NAME,
240 },
241 };
242
243 static const struct dice_handover_hdr_s kDiceHandoverHdrTemplate = {
244 /* Map header: 3 elements */
245 CBOR_HDR1(CBOR_MAJOR_MAP, 3),
246 /* 1. CDI_Attest: uint(1, 0bytes) => bstr(32bytes) */
247 DICE_HANDOVER_LABEL_CDI_ATTEST,
248 CBOR_BSTR32_EMPTY, /* CALC - CDI_attest */
249 /* 2. CDI_Seal: uint(2, 0bytes) => bstr(32bytes) */
250 DICE_HANDOVER_LABEL_CDI_SEAL,
251 CBOR_BSTR32_EMPTY, /* CALC - CDI_seal */
252 /* 3. DICE chain: uint(3, 0bytes) => DICE cert chain */
253 DICE_HANDOVER_LABEL_DICE_CHAIN
254 /* DICE cert chain is not included */
255 };
256
257 static const struct cdi_sig_struct_hdr_s kSigStructFixedHdr = {
258 /* Array header: 4 elements */
259 CBOR_HDR1(CBOR_MAJOR_ARR, 4),
260 /* 1. Context: tstr("Signature1") */
261 CDI_SIG_STRUCT_CONTEXT,
262 /* 2. Body protected: bstr(COSE param) */
263 COSE_PARAM_BSTR,
264 /* 3. External AAD: Bstr(0 bytes) */
265 CBOR_HDR1(CBOR_MAJOR_BSTR, 0),
266 /* 4. Payload - not fixed, contained in cdi_sig_struct_t */
267 };
268
269 static const struct combined_hdr_s kCombinedHdrTemplate = {
270 /* struct dice_cert_chain_hdr_s cert_chain */
271 {
272 /* Array header: 2 elements */
273 CBOR_HDR1(CBOR_MAJOR_ARR, 2),
274 /* 1. UDS pub key: COSE_Key
275 * struct cose_key_ecdsa_s
276 */
277 {
278 /* Map header: 6 entries */
279 CBOR_HDR1(CBOR_MAJOR_MAP, 6),
280 /* 1. Key type: uint(1, 0bytes) => uint(2, 0bytes) */
281 COSE_KEY_LABEL_KTY,
282 CBOR_UINT0(2), /* EC2 */
283 /* 2. Algorithm: uint(3, 0bytes) => nint(-1, 0bytes) */
284 COSE_KEY_LABEL_ALG,
285 CBOR_NINT0(-7), /* ECDSA w/ SHA-256 */
286 /* 3. Key ops: uint(4, 0bytes) =>
287 * array(1) { uint(2, 0bytes) }
288 */
289 COSE_KEY_LABEL_KEY_OPS,
290 CBOR_HDR1(CBOR_MAJOR_ARR, 1),
291 CBOR_UINT0(2),
292 /* 4. Curve: nint(-1, 0bytes) => uint(1, 0bytes) */
293 COSE_KEY_LABEL_CRV,
294 CBOR_UINT0(1), /* P-256 */
295 /* 5. X: nint(-2, 0bytes) => bstr(X, 32bytes) */
296 COSE_KEY_LABEL_X,
297 CBOR_BSTR32_EMPTY, /* VARIABLE */
298 /* 6. X: nint(-3, 0bytes) => bstr(Y, 32bytes) */
299 COSE_KEY_LABEL_Y,
300 CBOR_BSTR32_EMPTY, /* VARIABLE */
301 },
302 /* 2. CDI DICE cert: - not included, */
303 /* consists of hdr=cdi_cert_hdr_s, payload=cwt_claims_bstr_s, */
304 /* sig=cbor_bstr64_s */
305 },
306 /* struct cdi_cert_hdr_s cert */
307 {
308 /* Array header: 4 elements */
309 CBOR_HDR1(CBOR_MAJOR_ARR, 4),
310 /* 1. Protected: bstr(COSE param) */
311 COSE_PARAM_BSTR,
312 /* 2. Unprotected: empty map */
313 CBOR_HDR1(CBOR_MAJOR_MAP, 0),
314 /* 3. Payload: bstr(CWT claims) - not fixed, contained in */
315 /* cdi_cert_t */
316 /* 4. Signature: bstr(64 bytes) - not fixed, contained in */
317 /* cdi_cert_t */
318 }
319 };
320
321 static const struct slice_ref_s kCdiAttestLabel = {
322 10 /* strlen("CDI_Attest") */,
323 (const uint8_t *)"CDI_Attest"
324 };
325 static const struct slice_ref_s kCdiSealLabel = {
326 8 /* strlen("CDI_Seal") */,
327 (const uint8_t *)"CDI_Seal"
328 };
329 static const struct slice_ref_s kIdSaltSlice = {
330 64,
331 (const uint8_t *)kIdSalt
332 };
333 static const struct slice_ref_s kAsymSaltSlice = {
334 64,
335 (const uint8_t *)kAsymSalt
336 };
337 static const struct slice_ref_s kIdLabel = {
338 2, /* streln("ID") */
339 (const uint8_t *)"ID"
340 };
341 static const struct slice_ref_s kKeyPairLabel = {
342 8, /* strelen("Key Pair") */
343 (const uint8_t *)"Key Pair"
344 };
345
346 /* Calculates CDI from {UDS, inputs_digest, label}
347 */
calc_cdi_from_digest(const uint8_t uds[DIGEST_BYTES],const uint8_t inputs_digest[DIGEST_BYTES],const struct slice_ref_s label,uint8_t cdi[DIGEST_BYTES])348 static inline bool calc_cdi_from_digest(
349 /* [IN] UDS */
350 const uint8_t uds[DIGEST_BYTES],
351 /* [IN] digest of inputs */
352 const uint8_t inputs_digest[DIGEST_BYTES],
353 /* [IN] label */
354 const struct slice_ref_s label,
355 /* [OUT] CDI */
356 uint8_t cdi[DIGEST_BYTES]
357 )
358 {
359 const struct slice_ref_s uds_slice = digest_as_slice(uds);
360 const struct slice_ref_s inputs_digest_slice =
361 digest_as_slice(inputs_digest);
362 const struct slice_mut_s cdi_slice = digest_as_slice_mut(cdi);
363
364 return __platform_hkdf_sha256(uds_slice, inputs_digest_slice, label,
365 cdi_slice);
366 }
367
368 /* Calculates CDI from {UDS, inputs, label}
369 */
calc_cdi(const uint8_t uds[DIGEST_BYTES],const struct slice_ref_s inputs,const struct slice_ref_s label,uint8_t cdi[DIGEST_BYTES])370 static bool calc_cdi(
371 /* [IN] UDS */
372 const uint8_t uds[DIGEST_BYTES],
373 /* [IN] inputs */
374 const struct slice_ref_s inputs,
375 /* [IN] label */
376 const struct slice_ref_s label,
377 /* [OUT] CDI */
378 uint8_t cdi[DIGEST_BYTES]
379 )
380 {
381 uint8_t inputs_digest[DIGEST_BYTES];
382
383 if (!__platform_sha256(inputs, inputs_digest)) {
384 __platform_log_str("Failed to hash inputs");
385 return false;
386 }
387 return calc_cdi_from_digest(uds, inputs_digest, label, cdi);
388 }
389
390 /* Fills inputs for sealing CDI.
391 * Assumes that ctx->cfg and CfgDescr in ctx->output are already filled.
392 */
fill_inputs_seal(const struct dice_ctx_s * ctx,struct cdi_seal_inputs_s * inputs)393 static inline void fill_inputs_seal(
394 /* [IN] dice context */
395 const struct dice_ctx_s *ctx,
396 /* [OUT] inputs */
397 struct cdi_seal_inputs_s *inputs
398 )
399 {
400 __platform_memset(inputs->auth_data_digest, 0, DIGEST_BYTES);
401 __platform_memcpy(inputs->hidden_digest, ctx->cfg.hidden_digest,
402 DIGEST_BYTES);
403 inputs->mode = ctx->output.dice_handover.payload.data.mode.value;
404 }
405
406 /* Fills inputs for attestation CDI
407 * Assumes that ctx->cfg and CfgDescr in ctx->output are already filled.
408 */
fill_inputs_attest(const struct dice_ctx_s * ctx,struct cdi_attest_inputs_s * inputs)409 static inline void fill_inputs_attest(
410 /* [IN] dice context */
411 const struct dice_ctx_s *ctx,
412 /* [OUT] inputs */
413 struct cdi_attest_inputs_s *inputs
414 )
415 {
416 const struct cwt_claims_s *cwt_claims =
417 &ctx->output.dice_handover.payload.data;
418
419 __platform_memcpy(inputs->code_digest,
420 cwt_claims->code_hash.value,
421 DIGEST_BYTES);
422 __platform_memcpy(inputs->cfg_desr_digest,
423 cwt_claims->cfg_hash.value,
424 DIGEST_BYTES);
425 fill_inputs_seal(ctx, &inputs->seal_inputs);
426 }
427
428 /* Calculates attestation CDI.
429 * Assumes that ctx->cfg and CfgDescr in ctx->output are already filled.
430 */
calc_cdi_attest(const struct dice_ctx_s * ctx,uint8_t cdi[DIGEST_BYTES])431 static inline bool calc_cdi_attest(
432 /* [IN] dice context */
433 const struct dice_ctx_s *ctx,
434 /* [OUT] CDI */
435 uint8_t cdi[DIGEST_BYTES]
436 )
437 {
438 struct cdi_attest_inputs_s inputs;
439 const struct slice_ref_s inputs_slice = {
440 sizeof(inputs), (uint8_t *)&inputs
441 };
442
443 fill_inputs_attest(ctx, &inputs);
444 return calc_cdi(ctx->cfg.uds, inputs_slice, kCdiAttestLabel, cdi);
445 }
446
447 /* Calculates sealing CDI.
448 * Assumes that ctx->cfg and CfgDescr in ctx->output are already filled.
449 */
calc_cdi_seal(const struct dice_ctx_s * ctx,uint8_t cdi[DIGEST_BYTES])450 static inline bool calc_cdi_seal(
451 /* [IN] dice context */
452 const struct dice_ctx_s *ctx,
453 /* [OUT] CDI */
454 uint8_t cdi[DIGEST_BYTES]
455 )
456 {
457 struct cdi_seal_inputs_s inputs;
458 const struct slice_ref_s inputs_slice = {
459 sizeof(inputs), (uint8_t *)&inputs
460 };
461
462 fill_inputs_seal(ctx, &inputs);
463 return calc_cdi(ctx->cfg.uds, inputs_slice, kCdiSealLabel, cdi);
464 }
465
466 /* Calculates boot mode from the data in ctx->cfg
467 * On DT/OT with ti50:
468 * - Normal if
469 * - APROV succeeded or not configured from factory (for legacy devices).
470 * Note: AllowUnverifiedRo counts as a failure AND
471 * - Coreboot reported 'normal' boot mode
472 * - Recovery if
473 * - APROV succeeded or not configured from factory (for legacy devices).
474 * Note: AllowUnverifiedRo counts as a failure AND
475 * - Coreboot reported 'recovery-normal' boot mode
476 * - Debug - in all other cases
477 *
478 * On H1 with Cr50:
479 * - Normal if Coreboot reported 'normal' boot mode
480 * - Recovery if Coreboot reported 'recovery-normal' boot mode
481 * - Debug - in all other cases
482 */
calc_mode(const struct dice_ctx_s * ctx)483 static inline uint8_t calc_mode(
484 /* [IN] dice context */
485 const struct dice_ctx_s *ctx
486 )
487 {
488 if (__platform_aprov_status_allows_normal(ctx->cfg.aprov_status)) {
489 if (__platform_memcmp(ctx->cfg.pcr0, kPcr0NormalMode,
490 DIGEST_BYTES) == 0) {
491 return BOOT_MODE_NORMAL;
492 }
493 if (__platform_memcmp(ctx->cfg.pcr0, kPcr0RecoveryNormalMode,
494 DIGEST_BYTES) == 0) {
495 return BOOT_MODE_RECOVERY;
496 }
497 }
498 return BOOT_MODE_DEBUG;
499 }
500
501 /* Generates CDI cert signature for the initialized builder with pre-filled
502 * CWT claims.
503 */
fill_cdi_cert_signature(struct dice_ctx_s * ctx,const void * key)504 static inline bool fill_cdi_cert_signature(
505 /* [IN/OUT] dice context */
506 struct dice_ctx_s *ctx,
507 /* [IN] key handle to sign */
508 const void *key
509 )
510 {
511 uint8_t *sig_struct = ((uint8_t *)&ctx->output.dice_handover.payload) -
512 sizeof(struct cdi_sig_struct_hdr_s);
513 const struct slice_ref_s data_to_sign = {
514 CDI_SIG_STRUCT_LEN, sig_struct
515 };
516 struct cbor_bstr64_s *sig_bstr64 =
517 &ctx->output.dice_handover.signature;
518
519 __platform_memcpy(sig_struct, &kSigStructFixedHdr,
520 sizeof(struct cdi_sig_struct_hdr_s));
521 __platform_memcpy(sig_bstr64->cbor_hdr, kSigHdr, 2);
522 return __platform_ecdsa_p256_sign(key, data_to_sign,
523 sig_bstr64->value);
524 }
525
526 /* Generates key from UDS or CDI_Attest value.
527 */
generate_key(const uint8_t input[DIGEST_BYTES],const void ** key)528 static bool generate_key(
529 /* [IN] CDI_attest or UDS */
530 const uint8_t input[DIGEST_BYTES],
531 /* [OUT] key handle */
532 const void **key
533 )
534 {
535 uint8_t drbg_seed[DIGEST_BYTES];
536 const struct slice_ref_s input_slice = digest_as_slice(input);
537 const struct slice_mut_s drbg_seed_slice =
538 digest_as_slice_mut(drbg_seed);
539
540 if (!__platform_hkdf_sha256(input_slice, kAsymSaltSlice,
541 kKeyPairLabel, drbg_seed_slice)) {
542 __platform_log_str("ASYM_KDF failed");
543 return false;
544 }
545 return __platform_ecdsa_p256_keygen_hmac_drbg(drbg_seed, key);
546 }
547
548 /* Generates {UDS, CDI}_ID from {UDS, CDI} public key.
549 */
generate_id_from_pub_key(const struct ecdsa_public_s * pub_key,uint8_t dice_id[DICE_ID_BYTES])550 static bool generate_id_from_pub_key(
551 /* [IN] public key */
552 const struct ecdsa_public_s *pub_key,
553 /* [OUT] generated id */
554 uint8_t dice_id[DICE_ID_BYTES]
555 )
556 {
557 const struct slice_ref_s pub_key_slice = {
558 sizeof(struct ecdsa_public_s), (const uint8_t *)pub_key
559 };
560 const struct slice_mut_s dice_id_slice = {
561 DICE_ID_BYTES, (uint8_t *)dice_id
562 };
563
564 return __platform_hkdf_sha256(pub_key_slice, kIdSaltSlice, kIdLabel,
565 dice_id_slice);
566 }
567
568 /* Returns hexdump character for the half-byte.
569 */
hexdump_halfbyte(uint8_t half_byte)570 static inline uint8_t hexdump_halfbyte(uint8_t half_byte)
571 {
572 if (half_byte < 10)
573 return '0' + half_byte;
574 else
575 return 'a' + half_byte - 10;
576 }
577
578 /* Fills hexdump of the byte (lowercase).
579 */
hexdump_byte(uint8_t byte,uint8_t * str)580 static inline void hexdump_byte(
581 /* [IN] byte to hexdump */
582 uint8_t byte,
583 /* [OUT] str (always 2 bytes) with hexdump */
584 uint8_t *str
585 )
586 {
587 str[0] = hexdump_halfbyte((byte & 0xF0) >> 4);
588 str[1] = hexdump_halfbyte(byte & 0x0F);
589 }
590
591 /* Fills {CDI, UDS} ID string from ID bytes.
592 */
fill_dice_id_string(const uint8_t dice_id[DICE_ID_BYTES],uint8_t dice_id_str[DICE_ID_HEX_BYTES])593 static void fill_dice_id_string(
594 /* [IN] IDS_ID or CDI_ID */
595 const uint8_t dice_id[DICE_ID_BYTES],
596 /* [OUT] hexdump of this ID */
597 uint8_t dice_id_str[DICE_ID_HEX_BYTES]
598 )
599 {
600 size_t idx;
601
602 for (idx = 0; idx < DICE_ID_BYTES; idx++, dice_id_str += 2)
603 hexdump_byte(dice_id[idx], dice_id_str);
604 }
605
606 /* Fills COSE_Key structure from pubkey.
607 * Assumes that all fields in COSE_Key except for X, y are already filled
608 * from template.
609 */
fill_cose_pubkey(const struct ecdsa_public_s * pub_key,struct cose_key_ecdsa_s * cose_key)610 static inline void fill_cose_pubkey(
611 /* [IN] pub key */
612 const struct ecdsa_public_s *pub_key,
613 /* [IN/OUT] COSE key structure */
614 struct cose_key_ecdsa_s *cose_key
615 )
616 {
617 __platform_memcpy(cose_key->x.value, pub_key->x, ECDSA_POINT_BYTES);
618 __platform_memcpy(cose_key->y.value, pub_key->y, ECDSA_POINT_BYTES);
619 }
620
621 /* Fills CDI_attest pubkey, CDI_ID in the CDI certificate using generated
622 * CDI_attest key.
623 */
fill_cdi_details_with_key(struct dice_ctx_s * ctx,const void * cdi_key)624 static inline bool fill_cdi_details_with_key(
625 /* [IN/OUT] dice context */
626 struct dice_ctx_s *ctx,
627 /* [IN] CDI_attest key handle */
628 const void *cdi_key
629 )
630 {
631 struct ecdsa_public_s cdi_pub_key;
632 uint8_t cdi_id[DICE_ID_BYTES];
633 struct cwt_claims_s *cwt_claims =
634 &ctx->output.dice_handover.payload.data;
635
636 if (!__platform_ecdsa_p256_get_pub_key(cdi_key, &cdi_pub_key)) {
637 __platform_log_str("Failed to get CDI pubkey");
638 return false;
639 }
640 fill_cose_pubkey(&cdi_pub_key, &cwt_claims->subject_pk.data);
641 if (!generate_id_from_pub_key(&cdi_pub_key, cdi_id)) {
642 __platform_log_str("Failed to generate CDI_ID");
643 return false;
644 }
645 /* SUB = hex(CDI_ID) */
646 fill_dice_id_string(cdi_id, cwt_claims->sub.value);
647
648 return true;
649 }
650
651 /* Fills CDI_attest pubkey, CDI_ID in the CDI certificate.
652 * Assumes that ctx->cfg and CfgDescr in ctx->output are already filled.
653 */
fill_cdi_details(struct dice_ctx_s * ctx)654 static inline bool fill_cdi_details(
655 /* [IN/OUT] dice context */
656 struct dice_ctx_s *ctx
657 )
658 {
659 const void *cdi_key;
660 bool result;
661 struct dice_handover_hdr_s *hdr = &ctx->output.dice_handover.hdr;
662
663 __platform_memcpy(hdr, &kDiceHandoverHdrTemplate,
664 sizeof(struct dice_handover_hdr_s));
665 if (!calc_cdi_attest(ctx, hdr->cdi_attest.value)) {
666 __platform_log_str("Failed to calc CDI_attest");
667 return false;
668 }
669 if (!calc_cdi_seal(ctx, hdr->cdi_seal.value)) {
670 __platform_log_str("Failed to calc CDI_seal");
671 return false;
672 }
673 if (!generate_key(hdr->cdi_attest.value, &cdi_key)) {
674 __platform_log_str("Failed to generate CDI key");
675 return false;
676 }
677 result = fill_cdi_details_with_key(ctx, cdi_key);
678 __platform_ecdsa_p256_free(cdi_key);
679
680 return result;
681 }
682
683 /* Fills UDS_ID, signature into the certificate using generated UDS key.
684 * Assumes that all other fields of CDI certificate are filled already.
685 */
fill_uds_details_with_key(struct dice_ctx_s * ctx,const void * uds_key)686 static inline bool fill_uds_details_with_key(
687 /* [IN/OUT] dice context */
688 struct dice_ctx_s *ctx,
689 /* [IN] UDS key handle */
690 const void *uds_key
691 )
692 {
693 struct ecdsa_public_s uds_pub_key;
694 uint8_t uds_id[DICE_ID_BYTES];
695 struct cwt_claims_s *cwt_claims =
696 &ctx->output.dice_handover.payload.data;
697 struct combined_hdr_s *combined_hdr =
698 &ctx->output.dice_handover.options.dice_handover;
699
700 if (!__platform_ecdsa_p256_get_pub_key(uds_key, &uds_pub_key)) {
701 __platform_log_str("Failed to get UDS pubkey");
702 return false;
703 }
704 if (!generate_id_from_pub_key(&uds_pub_key, uds_id)) {
705 __platform_log_str("Failed to generate UDS_ID");
706 return false;
707 }
708 /* ISS = hex(UDS_ID) */
709 fill_dice_id_string(uds_id, cwt_claims->iss.value);
710 if (!fill_cdi_cert_signature(ctx, uds_key)) {
711 __platform_log_str("Failed to sign CDI cert");
712 return false;
713 }
714
715 /* We can do the rest only after we generated the signature because */
716 /* signature generation uses ctx->output.hdr temporarily to build */
717 /* Sig_struct for signing. */
718 __platform_memcpy(combined_hdr,
719 &kCombinedHdrTemplate,
720 sizeof(struct combined_hdr_s));
721 fill_cose_pubkey(
722 &uds_pub_key,
723 &combined_hdr->cert_chain.uds_pub_key);
724
725 return true;
726 }
727
728 /* Fills UDS_ID, signature into the certificate. */
729 /* Assumes that all other fields of CDI certificate were filled already. */
fill_uds_details(struct dice_ctx_s * ctx)730 static inline bool fill_uds_details(
731 struct dice_ctx_s *ctx /* [IN/OUT] dice context */
732 )
733 {
734 const void *uds_key;
735 bool result;
736
737 if (!generate_key(ctx->cfg.uds, &uds_key)) {
738 __platform_log_str("Failed to generate UDS key");
739 return false;
740 }
741 result = fill_uds_details_with_key(ctx, uds_key);
742 __platform_ecdsa_p256_free(uds_key);
743
744 return result;
745 }
746
747 /* Fills value in struct cbor_uint32_s */
748 /* Assumes that `cbor_var->cbor_hdr` is already pre-set */
set_cbor_u32(uint32_t value,struct cbor_uint32_s * cbor_var)749 static inline void set_cbor_u32(
750 uint32_t value, /* [IN] value to set */
751 struct cbor_uint32_s *cbor_var /* [OUT] CBOR UINT32 variable to fill */
752 )
753 {
754 cbor_var->value[0] = (uint8_t)(((value) & 0xFF000000) >> 24);
755 cbor_var->value[1] = (uint8_t)(((value) & 0x00FF0000) >> 16);
756 cbor_var->value[2] = (uint8_t)(((value) & 0x0000FF00) >> 8);
757 cbor_var->value[3] = (uint8_t)((value) & 0x000000FF);
758 }
759
760 /* Fills CfgDescr, CfgDescr digest and boot mode in CDI certificate */
fill_config_details(struct dice_ctx_s * ctx)761 static inline bool fill_config_details(
762 struct dice_ctx_s *ctx /* [IN/OUT] dice context */
763 )
764 {
765 struct cwt_claims_bstr_s *payload = &ctx->output.dice_handover.payload;
766 struct cwt_claims_s *cwt_claims = &payload->data;
767 struct cfg_descr_s *cfg_descr = &payload->data.cfg_descr.data;
768 const struct slice_ref_s cfg_descr_slice = { sizeof(struct cfg_descr_s),
769 (uint8_t *)cfg_descr };
770
771 /* Copy fixed data from the template */
772 __platform_memcpy(payload, &kCwtClaimsTemplate,
773 sizeof(struct cwt_claims_bstr_s));
774
775 /* Fill Cfg Descriptor variables based on ctx->cfg */
776 set_cbor_u32(ctx->cfg.aprov_status, &cfg_descr->aprov_status);
777 set_cbor_u32(ctx->cfg.sec_ver, &cfg_descr->sec_ver);
778 __platform_memcpy(cfg_descr->vboot_status.value, ctx->cfg.pcr0,
779 DIGEST_BYTES);
780 __platform_memcpy(cfg_descr->ap_fw_version.value, ctx->cfg.pcr10,
781 DIGEST_BYTES);
782
783 /* Calculate Cfg Descriptor digest */
784 if (!__platform_sha256(cfg_descr_slice, cwt_claims->cfg_hash.value)) {
785 __platform_log_str("Failed to calc CfgDescr digest");
786 return false;
787 }
788
789 /* code hash value, could be all zeros in case the device does not */
790 /* support AP RO verification or verification is not provisioned. */
791 __platform_memcpy(cwt_claims->code_hash.value,
792 ctx->cfg.code_digest,
793 sizeof(cwt_claims->code_hash.value));
794
795 /* Calculate boot mode */
796 cwt_claims->mode.value = calc_mode(ctx);
797
798 return true;
799 }
800
801 /* Fills DICE handover structure in struct dice_ctx_s. */
802 /* Assumes ctx.cfg is already filled */
generate_dice_handover(struct dice_ctx_s * ctx)803 static inline bool generate_dice_handover(
804 struct dice_ctx_s *ctx /* [IN/OUT] dice context */
805 )
806 {
807 /* 1. Fill device configuration details in CDI certificate: CfgDescr and
808 * its digest, boot mode.
809 * 2. Fill CDI details in CDI certificate (CDI pubkey, CDI_ID) and DICE
810 * handover (CDIs) Relies on config details to be filled already
811 * 3. Fill UDS details in CDI certificate (UDS_ID, signature by UDS key)
812 * and DICE chain (UDS pubkey) Relies on the rest of CDI certificate to
813 * be filled already.
814 */
815
816 return fill_config_details(ctx) &&
817 fill_cdi_details(ctx) &&
818 fill_uds_details(ctx);
819 }
820
821 /* Fills GSCBootParam. */
fill_gsc_boot_param(struct gsc_boot_param_s * gsc_boot_param)822 static inline bool fill_gsc_boot_param(
823 struct gsc_boot_param_s *gsc_boot_param /* [IN/OUT] GSCBootParam */
824 )
825 {
826 /* GSCBootParam: Map header: 3 entries */
827 gsc_boot_param->map_hdr = CBOR_HDR1(CBOR_MAJOR_MAP, 3);
828
829 /* GSCBootParam entry 1: EarlyEntropy:
830 * uint(1, 0bytes) => bstr(entropy, 64bytes)
831 */
832 gsc_boot_param->early_entropy_label = CBOR_UINT0(1);
833 gsc_boot_param->early_entropy.cbor_hdr[0] =
834 CBOR_HDR1(CBOR_MAJOR_BSTR, CBOR_BYTES1);
835 gsc_boot_param->early_entropy.cbor_hdr[1] = EARLY_ENTROPY_BYTES;
836
837 /* GSCBootParam entry 2: SessionKeySeed:
838 * uint(2, 0bytes) => bstr(entropy, 32bytes)
839 */
840 gsc_boot_param->session_key_seed_label = CBOR_UINT0(2);
841 gsc_boot_param->session_key_seed.cbor_hdr[0] =
842 CBOR_HDR1(CBOR_MAJOR_BSTR, CBOR_BYTES1);
843 gsc_boot_param->session_key_seed.cbor_hdr[1] = KEY_SEED_BYTES;
844
845 /* GSCBootParam entry 3: AuthTokenKeySeed:
846 * uint(3, 0bytes) => bstr(entropy, 32bytes)
847 */
848 gsc_boot_param->auth_token_key_seed_label = CBOR_UINT0(3);
849 gsc_boot_param->auth_token_key_seed.cbor_hdr[0] =
850 CBOR_HDR1(CBOR_MAJOR_BSTR, CBOR_BYTES1);
851 gsc_boot_param->auth_token_key_seed.cbor_hdr[1] = KEY_SEED_BYTES;
852
853 if (!__platform_get_gsc_boot_param(
854 gsc_boot_param->early_entropy.value,
855 gsc_boot_param->session_key_seed.value,
856 gsc_boot_param->auth_token_key_seed.value)) {
857 __platform_log_str("Failed to get GSC boot param");
858 return false;
859 }
860 return true;
861 }
862
863 /* Fills GSCBootParam and BootParam header in struct dice_ctx_s. */
864 /* Doesn't touch DICE handover structure */
fill_boot_param(struct dice_ctx_s * ctx)865 static inline bool fill_boot_param(
866 struct dice_ctx_s *ctx /* [IN/OUT] dice context */
867 )
868 {
869 /* BootParam: Map header: 3 entries */
870 ctx->output.map_hdr = CBOR_HDR1(CBOR_MAJOR_MAP, 3);
871
872 /* BootParam entry 1: Version:
873 * uint(1, 0bytes) => uint(BOOT_PARAM_VERSION, 0bytes)
874 */
875 ctx->output.version_label = CBOR_UINT0(1);
876 ctx->output.version = CBOR_UINT0(0);
877
878 /* BootParam entry 2: GSCBootParam:
879 * uint(2, 0bytes) => GSCBootParam (filled in fill_gsc_boot_param)
880 */
881 ctx->output.gsc_boot_param_label = CBOR_UINT0(2);
882
883 /* BootParam entry 3: AndroidDiceHandover:
884 * uint(3, 0bytes) => AndroidDiceHandover (not touched in this func)
885 */
886 ctx->output.dice_handover_label = CBOR_UINT0(3);
887
888 return fill_gsc_boot_param(&ctx->output.gsc_boot_param);
889 }
890
891 /* Get (part of) BootParam structure: [offset .. offset + size). */
get_boot_param_bytes(uint8_t * dest,size_t offset,size_t size)892 size_t get_boot_param_bytes(
893 /* [OUT] destination buffer to fill */
894 uint8_t *dest,
895 /* [IN] starting offset in the BootParam struct */
896 size_t offset,
897 /* [IN] size of the BootParam struct to copy */
898 size_t size
899 )
900 {
901 struct dice_ctx_s ctx;
902 uint8_t *src = (uint8_t *)&ctx.output;
903
904 if (size == 0 || offset >= BOOT_PARAM_SIZE)
905 return 0;
906 if (size > BOOT_PARAM_SIZE - offset)
907 size = BOOT_PARAM_SIZE - offset;
908
909 if (!__platform_get_dice_config(&ctx.cfg)) {
910 __platform_log_str("Failed to get DICE config");
911 return 0;
912 }
913 if (!generate_dice_handover(&ctx))
914 return 0;
915
916 if (!fill_boot_param(&ctx))
917 return 0;
918
919 __platform_memcpy(dest, src + offset, size);
920 __platform_memset(&ctx, 0, sizeof(struct dice_ctx_s)); /* zeroize */
921 return size;
922 }
923
924 /* Get (part of) DiceChain structure: [offset .. offset + size) */
get_dice_chain_bytes(uint8_t * dest,size_t offset,size_t size)925 size_t get_dice_chain_bytes(
926 /* [OUT] destination buffer to fill */
927 uint8_t *dest,
928 /* [IN] starting offset in the DiceChain struct */
929 size_t offset,
930 /* [IN] size of the data to copy */
931 size_t size
932 )
933 {
934 struct dice_ctx_s ctx;
935 uint8_t *src = (uint8_t *)&ctx.output.dice_handover.options;
936
937 if (size == 0 || offset >= DICE_CHAIN_SIZE)
938 return 0;
939 if (size > DICE_CHAIN_SIZE - offset)
940 size = DICE_CHAIN_SIZE - offset;
941
942 if (!__platform_get_dice_config(&ctx.cfg)) {
943 __platform_log_str("Failed to get DICE config");
944 return 0;
945 }
946 if (!generate_dice_handover(&ctx))
947 return 0;
948
949 __platform_memcpy(dest, src + offset, size);
950 __platform_memset(&ctx, 0, sizeof(struct dice_ctx_s)); /* zeroize */
951 return size;
952 }
953