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