• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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