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 "boot_param_platform.h"
8
9 #include <openssl/core_names.h>
10 #include <openssl/err.h>
11 #include <openssl/ec.h>
12 #include <openssl/evp.h>
13 #include <openssl/kdf.h>
14 #include <openssl/params.h>
15 #include <openssl/sha.h>
16
17 #include <stdio.h>
18 #include <string.h>
19
print_openssl_error(const char * func_name,const char * prefix_err)20 static void print_openssl_error(const char *func_name, const char *prefix_err)
21 {
22 unsigned long err = ERR_get_error();
23 char *err_str = ERR_error_string(err, NULL);
24
25 printf("%s: %s\n", func_name, prefix_err);
26 if (err_str)
27 __platform_log_str(err_str);
28 }
29
30 /* Perform HKDF-SHA256(ikm, salt, info) */
__platform_hkdf_sha256(const struct slice_ref_s ikm,const struct slice_ref_s salt,const struct slice_ref_s info,const struct slice_mut_s result)31 bool __platform_hkdf_sha256(
32 /* [IN] input key material */
33 const struct slice_ref_s ikm,
34 /* [IN] salt */
35 const struct slice_ref_s salt,
36 /* [IN] info */
37 const struct slice_ref_s info,
38 /* [IN/OUT] .size sets length for hkdf,
39 * .data is where the digest will be placed
40 */
41 const struct slice_mut_s result
42 )
43 {
44 EVP_KDF *kdf;
45 EVP_KDF_CTX *kctx;
46 OSSL_PARAM params[5], *p = params;
47 int res;
48
49 kdf = EVP_KDF_fetch(NULL, "HKDF", NULL);
50 if (kdf == NULL) {
51 print_openssl_error(__func__, "Can't find HKDF");
52 return false;
53 }
54 kctx = EVP_KDF_CTX_new(kdf);
55 EVP_KDF_free(kdf);
56 if (kctx == NULL) {
57 print_openssl_error(__func__, "Can't create HKDF context");
58 return false;
59 }
60
61 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
62 SN_sha256, strlen(SN_sha256));
63 *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
64 (void *)ikm.data, ikm.size);
65 *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
66 (void *)info.data, info.size);
67 *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
68 (void *)salt.data, salt.size);
69 *p = OSSL_PARAM_construct_end();
70
71 res = EVP_KDF_derive(kctx, result.data, result.size, params);
72 if (res <= 0)
73 print_openssl_error(__func__, "Can't perform HKDF");
74
75 EVP_KDF_CTX_free(kctx);
76 return (res > 0);
77 }
78
79 /* Calculate SH256 for the provided buffer */
__platform_sha256(const struct slice_ref_s data,uint8_t digest[DIGEST_BYTES])80 bool __platform_sha256(
81 /* [IN] data to hash */
82 const struct slice_ref_s data,
83 /* [OUT] resulting digest */
84 uint8_t digest[DIGEST_BYTES]
85 )
86 {
87 return SHA256(data.data, data.size, digest) == digest;
88 }
89
90 struct dice_config_s g_dice_config = {
91 .aprov_status = 0x20,
92 .sec_ver = 1,
93 .uds = {
94 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
95 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
96 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
97 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
98 },
99 .hidden_digest = {
100 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
101 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
102 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
103 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
104 },
105 .code_digest = {
106 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
107 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
108 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
109 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
110 },
111 .pcr0 = {
112 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
113 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
114 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
115 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
116 },
117 .pcr10 = {
118 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
119 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
120 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
121 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
122 },
123 };
124
125 /* Get DICE config */
__platform_get_dice_config(struct dice_config_s * cfg)126 bool __platform_get_dice_config(
127 /* [OUT] DICE config */
128 struct dice_config_s *cfg
129 )
130 {
131 memcpy(cfg, &g_dice_config, sizeof(struct dice_config_s));
132 return true;
133 }
134
135 uint8_t g_early_entropy[EARLY_ENTROPY_BYTES] = {
136 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
137 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
138 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
139 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
140 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
141 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
142 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
143 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
144 };
145
146 uint8_t g_session_key_seed[KEY_SEED_BYTES] = {
147 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
148 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
149 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
150 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
151 };
152
153 uint8_t g_auth_token_key_seed[KEY_SEED_BYTES] = {
154 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
155 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
156 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
157 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
158 };
159
160 /* Get GSC boot parameters */
__platform_get_gsc_boot_param(uint8_t early_entropy[EARLY_ENTROPY_BYTES],uint8_t session_key_seed[KEY_SEED_BYTES],uint8_t auth_token_key_seed[KEY_SEED_BYTES])161 bool __platform_get_gsc_boot_param(
162 /* [OUT] early entropy */
163 uint8_t early_entropy[EARLY_ENTROPY_BYTES],
164 /* [OUT] SessionKeySeed */
165 uint8_t session_key_seed[KEY_SEED_BYTES],
166 /* [OUT] AuthTokenKeySeed */
167 uint8_t auth_token_key_seed[KEY_SEED_BYTES]
168 )
169 {
170 memcpy(early_entropy, g_early_entropy, EARLY_ENTROPY_BYTES);
171 memcpy(session_key_seed, g_session_key_seed, KEY_SEED_BYTES);
172 memcpy(auth_token_key_seed, g_auth_token_key_seed, KEY_SEED_BYTES);
173 return true;
174 }
175
176 /* Generate ECDSA P-256 key using HMAC-DRBG initialized by the seed */
__platform_ecdsa_p256_keygen_hmac_drbg(const uint8_t seed[DIGEST_BYTES],const void ** key)177 bool __platform_ecdsa_p256_keygen_hmac_drbg(
178 /* [IN] key seed */
179 const uint8_t seed[DIGEST_BYTES],
180 /* [OUT] ECDSA key handle */
181 const void **key
182 )
183 {
184 /* NOTE: for testing we don't do the actual KDF based on HMAC_DRBG.
185 * We could use EVP_KDF-HMAC-DRBG or EVP_RAND-HMAC-DRBG, but there's
186 * no easy way to generate EC key from a seed we'd get from DRBG.
187 * Instead, we just generate a random EC key ignoring the seed.
188 */
189 *key = EVP_EC_gen("P-256");
190
191 if (*key == NULL) {
192 print_openssl_error(__func__, "Can't generate EC");
193 return false;
194 }
195 return true;
196 }
197
198 /* Generate ECDSA P-256 signature: 64 bytes (R | S) */
__platform_ecdsa_p256_sign(const void * key,const struct slice_ref_s data,uint8_t signature[ECDSA_SIG_BYTES])199 bool __platform_ecdsa_p256_sign(
200 /* [IN] ECDSA key handle */
201 const void *key,
202 /* [IN] data to sign */
203 const struct slice_ref_s data,
204 /* [OUT] resulting signature */
205 uint8_t signature[ECDSA_SIG_BYTES]
206 )
207 {
208 const BIGNUM *r;
209 const BIGNUM *s;
210 EVP_PKEY_CTX *ctx;
211 EVP_SIGNATURE *alg;
212 uint8_t digest[DIGEST_BYTES];
213 uint8_t output[128];
214 int res;
215 size_t siglen;
216 ECDSA_SIG *sig_obj;
217 const uint8_t *sig_ptr = output;
218
219 if (!__platform_sha256(data, digest)) {
220 printf("%s: SHA failed\n", __func__);
221 return false;
222 }
223
224 ctx = EVP_PKEY_CTX_new((EVP_PKEY *)key, NULL /* no engine */);
225 if (ctx == NULL) {
226 print_openssl_error(__func__, "Can't create context");
227 return false;
228 }
229 if (EVP_PKEY_sign_init(ctx) <= 0) {
230 print_openssl_error(__func__, "Can't init sign");
231 EVP_PKEY_CTX_free(ctx);
232 return false;
233 }
234
235 alg = EVP_SIGNATURE_fetch(NULL, "ECDSA", NULL);
236 if (alg == NULL) {
237 print_openssl_error(__func__, "Can't fetch signature alg");
238 EVP_PKEY_CTX_free(ctx);
239 return false;
240 }
241
242 res = EVP_PKEY_sign(ctx, NULL, &siglen, digest, DIGEST_BYTES);
243 if (res <= 0)
244 print_openssl_error(__func__, "Can't detect signature size");
245
246 if (siglen <= sizeof(output)) {
247 res = EVP_PKEY_sign(ctx, output, &siglen, digest, DIGEST_BYTES);
248 if (res <= 0)
249 print_openssl_error(__func__, "Can't sign");
250 } else {
251 printf("%s: unexpected sigsize %zu > %zu\n",
252 __func__, siglen, sizeof(output));
253 res = 0;
254 }
255
256 EVP_PKEY_CTX_free(ctx);
257 EVP_SIGNATURE_free(alg);
258
259 if (res <= 0)
260 return false;
261
262 sig_obj = d2i_ECDSA_SIG(NULL, &sig_ptr, siglen);
263 if (sig_obj == NULL) {
264 print_openssl_error(__func__, "Can't convert signature");
265 return false;
266 }
267
268 r = ECDSA_SIG_get0_r(sig_obj);
269 s = ECDSA_SIG_get0_s(sig_obj);
270
271 if (BN_num_bytes(r) > ECDSA_POINT_BYTES) {
272 printf("%s: unexpected r size %d > %u\n",
273 __func__, BN_num_bytes(r), ECDSA_POINT_BYTES);
274 ECDSA_SIG_free(sig_obj);
275 return false;
276 }
277 if (BN_num_bytes(s) > ECDSA_POINT_BYTES) {
278 printf("%s: unexpected s size %d > %u\n",
279 __func__, BN_num_bytes(s), ECDSA_POINT_BYTES);
280 ECDSA_SIG_free(sig_obj);
281 return false;
282 }
283 memset(signature, 0, ECDSA_SIG_BYTES);
284 BN_bn2bin(r, signature + (ECDSA_POINT_BYTES - BN_num_bytes(r)));
285 BN_bn2bin(s, signature + (ECDSA_SIG_BYTES - BN_num_bytes(s)));
286
287 ECDSA_SIG_free(sig_obj);
288 return true;
289 }
290
291 /* Get ECDSA public key X, Y */
__platform_ecdsa_p256_get_pub_key(const void * key,struct ecdsa_public_s * pub_key)292 bool __platform_ecdsa_p256_get_pub_key(
293 /* [IN] ECDSA key handle */
294 const void *key,
295 /* [OUT] public key structure */
296 struct ecdsa_public_s *pub_key
297 )
298 {
299 BIGNUM *x = NULL;
300 BIGNUM *y = NULL;
301 bool res = true;
302
303 if (!EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_EC_PUB_X, &x)) {
304 print_openssl_error(__func__, "Can't get X");
305 res = false;
306 }
307
308 if (!EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_EC_PUB_Y, &y)) {
309 print_openssl_error(__func__, "Can't get Y");
310 res = false;
311 }
312
313 if (res && (BN_num_bytes(x) > ECDSA_POINT_BYTES)) {
314 printf("%s: unexpected X size %d > %u\n",
315 __func__, BN_num_bytes(x), ECDSA_POINT_BYTES);
316 res = false;
317 }
318 if (res && (BN_num_bytes(y) > ECDSA_POINT_BYTES)) {
319 printf("%s: unexpected Y size %d > %u\n",
320 __func__, BN_num_bytes(y), ECDSA_POINT_BYTES);
321 res = false;
322 }
323
324 if (res) {
325 memset(pub_key->x, 0, ECDSA_POINT_BYTES);
326 BN_bn2bin(x,
327 pub_key->x + (ECDSA_POINT_BYTES - BN_num_bytes(x)));
328 memset(pub_key->y, 0, ECDSA_POINT_BYTES);
329 BN_bn2bin(y,
330 pub_key->y + (ECDSA_POINT_BYTES - BN_num_bytes(y)));
331 }
332
333 BN_free(x);
334 BN_free(y);
335 return res;
336 }
337
338 /* Free ECDSA key handle */
__platform_ecdsa_p256_free(const void * key)339 void __platform_ecdsa_p256_free(
340 /* [IN] ECDSA key handle */
341 const void *key
342 )
343 {
344 EVP_PKEY_free((EVP_PKEY *)key);
345 }
346
347 /* Check if APROV status allows making 'normal' boot mode decision */
__platform_aprov_status_allows_normal(uint32_t aprov_status)348 bool __platform_aprov_status_allows_normal(
349 /* [IN] APROV status */
350 uint32_t aprov_status
351 )
352 {
353 return true;
354 }
355
356 /* Print error string to log */
__platform_log_str(const char * str)357 void __platform_log_str(
358 /* [IN] string to print */
359 const char *str
360 )
361 {
362 puts(str);
363 }
364
365 /* memcpy */
__platform_memcpy(void * dest,const void * src,size_t size)366 void __platform_memcpy(void *dest, const void *src, size_t size)
367 {
368 memcpy(dest, src, size);
369 }
370
371 /* memset */
__platform_memset(void * dest,uint8_t fill,size_t size)372 void __platform_memset(void *dest, uint8_t fill, size_t size)
373 {
374 memset(dest, fill, size);
375 }
376
377 /* memcmp */
__platform_memcmp(const void * str1,const void * str2,size_t size)378 int __platform_memcmp(const void *str1, const void *str2, size_t size)
379 {
380 return memcmp(str1, str2, size);
381 }
382