xref: /aosp_15_r20/external/vboot_reference/futility/file_type_usbpd1.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2015 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * The USB Type-C chargers released with Samus ("Pixel (2015)") have upgradable
6  * firmware. Due to space considerations, we don't have room for handy things
7  * like an FMAP or headers for the signatures. Accordingly, all the normally
8  * variable factors (image size, signature algorithms, etc.) are hard coded
9  * and the image itself just looks like a bunch of random numbers.
10  *
11  * This file handles those images, but PLEASE don't use it as a template for
12  * new devices. Look at file_type_rwsig.c instead.
13  */
14 
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 
19 #include "2common.h"
20 #include "2rsa.h"
21 #include "2sha.h"
22 #include "2sysincludes.h"
23 #include "file_type.h"
24 #include "futility.h"
25 #include "futility_options.h"
26 #include "host_common.h"
27 #include "host_common21.h"
28 #include "host_key21.h"
29 #include "host_signature21.h"
30 #include "util_misc.h"
31 
32 /* Return 1 if okay, 0 if not */
parse_size_opts(const uint32_t len,uint32_t * ro_size_ptr,uint32_t * rw_size_ptr,uint32_t * ro_offset_ptr,uint32_t * rw_offset_ptr)33 static int parse_size_opts(const uint32_t len,
34 			   uint32_t *ro_size_ptr, uint32_t *rw_size_ptr,
35 			   uint32_t *ro_offset_ptr, uint32_t * rw_offset_ptr)
36 {
37 	/* Assume the image has both RO and RW, evenly split. */
38 	uint32_t ro_offset = 0;
39 	uint32_t ro_size = len / 2;
40 	uint32_t rw_size = len / 2;
41 	uint32_t rw_offset = len / 2;
42 
43 	/* Unless told otherwise... */
44 	if (sign_option.ro_size != 0xffffffff)
45 		ro_size = sign_option.ro_size;
46 	if (sign_option.ro_offset != 0xffffffff)
47 		ro_offset = sign_option.ro_offset;
48 
49 	/* If RO is missing, the whole thing must be RW */
50 	if (!ro_size) {
51 		rw_size = len;
52 		rw_offset = 0;
53 	}
54 
55 	/* Unless that's overridden too */
56 	if (sign_option.rw_size != 0xffffffff)
57 		rw_size = sign_option.rw_size;
58 	if (sign_option.rw_offset != 0xffffffff)
59 		rw_offset = sign_option.rw_offset;
60 
61 	VB2_DEBUG("ro_size     0x%08x\n", ro_size);
62 	VB2_DEBUG("ro_offset   0x%08x\n", ro_offset);
63 	VB2_DEBUG("rw_size     0x%08x\n", rw_size);
64 	VB2_DEBUG("rw_offset   0x%08x\n", rw_offset);
65 
66 	/* Now let's do some validity checks. */
67 	if (ro_size > len || ro_offset > len - ro_size ||
68 	    rw_size > len || rw_offset > len - rw_size) {
69 		printf("size/offset values are bogus\n");
70 		return 0;
71 	}
72 
73 	*ro_size_ptr = ro_size;
74 	*rw_size_ptr = rw_size;
75 	*ro_offset_ptr = ro_offset;
76 	*rw_offset_ptr = rw_offset;
77 
78 	return 1;
79 }
80 
ft_sign_usbpd1(const char * fname)81 int ft_sign_usbpd1(const char *fname)
82 {
83 	struct vb2_private_key *key_ptr = 0;
84 	struct vb21_signature *sig_ptr = 0;
85 	uint8_t *keyb_data = 0;
86 	uint32_t keyb_size;
87 	int retval = 1;
88 	uint32_t sig_size;
89 	uint32_t sig_offset;
90 	uint32_t pub_size;
91 	uint32_t pub_offset;
92 	uint32_t ro_size;
93 	uint32_t rw_size;
94 	uint32_t ro_offset;
95 	uint32_t rw_offset;
96 	uint32_t r;
97 	uint8_t *buf = NULL;
98 	uint32_t len;
99 	int fd = -1;
100 
101 	if (futil_open_and_map_file(fname, &fd, FILE_MODE_SIGN(sign_option),
102 				    &buf, &len))
103 		return 1;
104 
105 	VB2_DEBUG("name %s len  %#.8x (%d)\n", fname, len, len);
106 
107 	/* Get image locations */
108 	if (!parse_size_opts(len, &ro_size, &rw_size, &ro_offset, &rw_offset))
109 		goto done;
110 
111 	/* Read the signing keypair file */
112 	if (vb2_private_key_read_pem(&key_ptr, sign_option.pem_signpriv)) {
113 		ERROR("Unable to read keypair from %s\n",
114 		      sign_option.pem_signpriv);
115 		goto done;
116 	}
117 
118 	/* Set the algs */
119 	key_ptr->hash_alg = sign_option.hash_alg;
120 	key_ptr->sig_alg = vb2_rsa_sig_alg(key_ptr->rsa_private_key);
121 	if (key_ptr->sig_alg == VB2_SIG_INVALID) {
122 		ERROR("Unsupported sig algorithm in RSA key\n");
123 		goto done;
124 	}
125 
126 	/* Figure out what needs signing */
127 	sig_size = vb2_rsa_sig_size(key_ptr->sig_alg);
128 	if (rw_size < sig_size) {
129 		ERROR("The RW image is too small to hold the signature"
130 		      " (0x%08x < %08x)\n",
131 		      rw_size, sig_size);
132 		goto done;
133 	}
134 	rw_size -= sig_size;
135 	sig_offset = rw_offset + rw_size;
136 
137 	VB2_DEBUG("rw_size   => 0x%08x\n", rw_size);
138 	VB2_DEBUG("rw_offset => 0x%08x\n", rw_offset);
139 	VB2_DEBUG("sig_size     0x%08x\n", sig_size);
140 	VB2_DEBUG("sig_offset   0x%08x\n", sig_offset);
141 
142 	/* Sign the blob */
143 	r = vb21_sign_data(&sig_ptr, buf + rw_offset, rw_size, key_ptr, "Bah");
144 	if (r) {
145 		ERROR("Unable to sign data (error 0x%08x, if that helps)\n", r);
146 		goto done;
147 	}
148 
149 	/* Double-check the size */
150 	if (sig_ptr->sig_size != sig_size) {
151 		ERROR("The sig size is %d bytes, not %d as expected.\n",
152 		      sig_ptr->sig_size, sig_size);
153 		goto done;
154 	}
155 
156 	/* Okay, looking good. Update the signature. */
157 	memcpy(buf + sig_offset, (uint8_t *)sig_ptr + sig_ptr->sig_offset,
158 	       sig_ptr->sig_size);
159 
160 	/* If there's no RO section, we're done. */
161 	if (!ro_size) {
162 		retval = 0;
163 		goto done;
164 	}
165 
166 	/* Otherwise, now update the public key */
167 	if (vb_keyb_from_private_key(key_ptr, &keyb_data, &keyb_size)) {
168 		ERROR("Could not extract the public key\n");
169 		goto done;
170 	}
171 	VB2_DEBUG("keyb_size is %#x (%d):\n", keyb_size, keyb_size);
172 
173 	/*
174 	 * Of course the packed public key format is different. Why would you
175 	 * think otherwise? Since the dawn of time, vboot has used this:
176 	 *
177 	 *   uint32_t  nwords        size of RSA key in 32-bit words
178 	 *   uint32_t  n0inv         magic RSA n0inv
179 	 *   uint32_t  n[nwords]     magic RSA modulus little endian array
180 	 *   uint32_t  rr[nwords]    magic RSA R^2 little endian array
181 	 *
182 	 * But for no discernable reason, the usbpd1 format uses this:
183 	 *
184 	 *   uint32_t  n[nwords]     magic RSA modulus little endian array
185 	 *   uint32_t  rr[nwords]    magic RSA R^2 little endian array
186 	 *   uint32_t  n0inv         magic RSA n0inv
187 	 *
188 	 * There's no nwords field, and n0inv is last insted of first. Sigh.
189 	 */
190 	pub_size = keyb_size - 4;
191 
192 	/* align pubkey size to 16-byte boundary */
193 	uint32_t pub_pad = pub_size;
194 	pub_size = (pub_size + 16) / 16 * 16;
195 	pub_pad = pub_size - pub_pad;
196 
197 	pub_offset = ro_offset + ro_size - pub_size;
198 
199 	if (ro_size < pub_size) {
200 		ERROR("The RO image is too small to hold the public key"
201 		      " (0x%08x < %08x)\n",
202 		      ro_size, pub_size);
203 		goto done;
204 	}
205 
206 	/* How many bytes in the arrays? */
207 	uint32_t nbytes = 4 * (*(uint32_t *)keyb_data);
208 	/* Source offsets from keyb_data */
209 	uint32_t src_ofs_n0inv = 4;
210 	uint32_t src_ofs_n = src_ofs_n0inv + 4;
211 	uint32_t src_ofs_rr = src_ofs_n + nbytes;
212 	/* Dest offsets from buf */
213 	uint32_t dst_ofs_n = pub_offset + 0;
214 	uint32_t dst_ofs_rr = dst_ofs_n + nbytes;
215 	uint32_t dst_ofs_n0inv = dst_ofs_rr + nbytes;
216 
217 	VB2_DEBUG("len 0x%08x ro_size 0x%08x ro_offset 0x%08x\n",
218 		  len, ro_size, ro_offset);
219 	VB2_DEBUG("pub_size 0x%08x pub_offset 0x%08x nbytes 0x%08x\n",
220 		  pub_size, pub_offset, nbytes);
221 	VB2_DEBUG("pub_pad 0x%08x\n", pub_pad);
222 
223 	/* Copy n[nwords] */
224 	memcpy(buf + dst_ofs_n, keyb_data + src_ofs_n, nbytes);
225 	/* Copy rr[nwords] */
226 	memcpy(buf + dst_ofs_rr, keyb_data + src_ofs_rr, nbytes);
227 	/* Copy n0inv */
228 	memcpy(buf + dst_ofs_n0inv, keyb_data + src_ofs_n0inv, 4);
229 	/* Pad with 0xff */
230 	memset(buf + dst_ofs_n0inv + 4, 0xff, pub_pad);
231 
232 	/* Finally */
233 	retval = 0;
234 done:
235 	futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len);
236 	if (key_ptr)
237 		vb2_free_private_key(key_ptr);
238 	if (keyb_data)
239 		free(keyb_data);
240 
241 	return retval;
242 }
243 
244 /*
245  * Algorithms that we want to try, in order. We've only ever shipped with
246  * RSA2048 / SHA256, but the others should work in tests.
247  */
248 static enum vb2_signature_algorithm sigs[] = {
249 	VB2_SIG_RSA2048,
250 	VB2_SIG_RSA2048_EXP3,
251 	VB2_SIG_RSA1024,
252 	VB2_SIG_RSA4096,
253 	VB2_SIG_RSA8192,
254 };
255 static enum vb2_hash_algorithm hashes[] = {
256 	VB2_HASH_SHA256,
257 	VB2_HASH_SHA1,
258 	VB2_HASH_SHA512,
259 };
260 
261 /*
262  * The size of the public key structure used by usbpd1 is
263  * 2 x RSANUMBYTES for n and rr fields
264  * plus 4 for n0inv, aligned on a multiple of 16
265  */
usbpd1_packed_key_size(enum vb2_signature_algorithm sig_alg)266 static uint32_t usbpd1_packed_key_size(enum vb2_signature_algorithm sig_alg)
267 {
268 	switch (sig_alg) {
269 	case VB2_SIG_RSA1024:
270 		return 272;
271 	case VB2_SIG_RSA2048:
272 	case VB2_SIG_RSA2048_EXP3:
273 		return 528;
274 	case VB2_SIG_RSA4096:
275 		return 1040;
276 	case VB2_SIG_RSA8192:
277 		return 2064;
278 	default:
279 		return 0;
280 	}
281 }
vb2_pubkey_from_usbpd1(struct vb2_public_key * key,enum vb2_signature_algorithm sig_alg,enum vb2_hash_algorithm hash_alg,const uint8_t * o_pubkey,uint32_t o_pubkey_size)282 static void vb2_pubkey_from_usbpd1(struct vb2_public_key *key,
283 				   enum vb2_signature_algorithm sig_alg,
284 				   enum vb2_hash_algorithm hash_alg,
285 				   const uint8_t *o_pubkey,
286 				   uint32_t o_pubkey_size)
287 {
288 	key->arrsize = vb2_rsa_sig_size(sig_alg) / sizeof(uint32_t);
289 	key->n0inv = *((uint32_t *)o_pubkey + 2 * key->arrsize);
290 	key->n = (uint32_t *)o_pubkey;
291 	key->rr = (uint32_t *)o_pubkey + key->arrsize;
292 	key->sig_alg = sig_alg;
293 	key->hash_alg = hash_alg;
294 	key->desc = 0;
295 	key->version = 0;
296 	key->id = vb2_hash_id(hash_alg);
297 }
298 
vb21_sig_from_usbpd1(struct vb21_signature ** sig,enum vb2_signature_algorithm sig_alg,enum vb2_hash_algorithm hash_alg,const uint8_t * o_sig,uint32_t o_sig_size,uint32_t data_size)299 static vb2_error_t vb21_sig_from_usbpd1(struct vb21_signature **sig,
300 					enum vb2_signature_algorithm sig_alg,
301 					enum vb2_hash_algorithm hash_alg,
302 					const uint8_t *o_sig,
303 					uint32_t o_sig_size, uint32_t data_size)
304 {
305 	struct vb21_signature s = {
306 		.c.magic = VB21_MAGIC_SIGNATURE,
307 		.c.struct_version_major = VB21_SIGNATURE_VERSION_MAJOR,
308 		.c.struct_version_minor = VB21_SIGNATURE_VERSION_MINOR,
309 		.c.fixed_size = sizeof(s),
310 		.sig_alg = sig_alg,
311 		.hash_alg = hash_alg,
312 		.data_size = data_size,
313 		.sig_size = vb2_rsa_sig_size(sig_alg),
314 		.sig_offset = sizeof(s),
315 	};
316 	const uint32_t total_size = sizeof(s) + o_sig_size;
317 	uint8_t *buf = calloc(1, total_size);
318 	if (!buf)
319 		return VB2_ERROR_UNKNOWN;
320 
321 	memcpy(buf, &s, sizeof(s));
322 	memcpy(buf + sizeof(s), o_sig, o_sig_size);
323 
324 	*sig = (struct vb21_signature *)buf;
325 	return VB2_SUCCESS;
326 }
327 
show_usbpd1_stuff(const char * fname,enum vb2_signature_algorithm sig_alg,enum vb2_hash_algorithm hash_alg,const uint8_t * o_pubkey,uint32_t o_pubkey_size)328 static void show_usbpd1_stuff(const char *fname,
329 			      enum vb2_signature_algorithm sig_alg,
330 			      enum vb2_hash_algorithm hash_alg,
331 			      const uint8_t *o_pubkey, uint32_t o_pubkey_size)
332 {
333 	struct vb2_public_key key;
334 	struct vb21_packed_key *pkey;
335 	struct vb2_hash hash;
336 	int i;
337 
338 	vb2_pubkey_from_usbpd1(&key, sig_alg, hash_alg,
339 			       o_pubkey, o_pubkey_size);
340 
341 	if (vb21_public_key_pack(&pkey, &key))
342 		return;
343 
344 	vb2_hash_calculate(false, (uint8_t *)pkey + pkey->key_offset,
345 			   pkey->key_size, VB2_HASH_SHA1, &hash);
346 
347 	printf("USB-PD v1 image:       %s\n", fname);
348 	printf("  Algorithm:           %s %s\n",
349 	       vb2_get_sig_algorithm_name(sig_alg),
350 	       vb2_get_hash_algorithm_name(hash_alg));
351 	printf("  Key sha1sum:         ");
352 	for (i = 0; i < sizeof(hash.sha1); i++)
353 		printf("%02x", hash.sha1[i]);
354 	printf("\n");
355 
356 	free(pkey);
357 }
358 
359 /* Returns VB2_SUCCESS or random error code */
try_our_own(enum vb2_signature_algorithm sig_alg,enum vb2_hash_algorithm hash_alg,const uint8_t * o_pubkey,uint32_t o_pubkey_size,const uint8_t * o_sig,uint32_t o_sig_size,const uint8_t * data,uint32_t data_size)360 static vb2_error_t try_our_own(enum vb2_signature_algorithm sig_alg,
361 			       enum vb2_hash_algorithm hash_alg,
362 			       const uint8_t *o_pubkey, uint32_t o_pubkey_size,
363 			       const uint8_t *o_sig, uint32_t o_sig_size,
364 			       const uint8_t *data, uint32_t data_size)
365 {
366 	struct vb2_public_key pubkey;
367 	struct vb21_signature *sig;
368 	uint8_t buf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
369 		__attribute__((aligned(VB2_WORKBUF_ALIGN)));
370 	struct vb2_workbuf wb = {
371 		.buf = buf,
372 		.size = sizeof(buf),
373 	};
374 	vb2_error_t rv = VB2_ERROR_UNKNOWN;
375 
376 	vb2_pubkey_from_usbpd1(&pubkey, sig_alg, hash_alg,
377 			       o_pubkey, o_pubkey_size);
378 
379 	if ((rv = vb21_sig_from_usbpd1(&sig, sig_alg, hash_alg,
380 				       o_sig, o_sig_size, data_size)))
381 	    return rv;
382 
383 	rv = vb21_verify_data(data, data_size, sig, &pubkey, &wb);
384 
385 	free(sig);
386 
387 	return rv;
388 }
389 
390 /* Returns VB2_SUCCESS if the image validates itself */
check_self_consistency(const uint8_t * buf,const char * fname,uint32_t ro_size,uint32_t rw_size,uint32_t ro_offset,uint32_t rw_offset,enum vb2_signature_algorithm sig_alg,enum vb2_hash_algorithm hash_alg)391 static vb2_error_t check_self_consistency(const uint8_t *buf, const char *fname,
392 					  uint32_t ro_size, uint32_t rw_size,
393 					  uint32_t ro_offset,
394 					  uint32_t rw_offset,
395 					  enum vb2_signature_algorithm sig_alg,
396 					  enum vb2_hash_algorithm hash_alg)
397 {
398 	/* Where are the important bits? */
399 	const uint32_t sig_size = vb2_rsa_sig_size(sig_alg);
400 	const uint32_t sig_offset = rw_offset + rw_size - sig_size;
401 	const uint32_t pubkey_size = usbpd1_packed_key_size(sig_alg);
402 	const uint32_t pubkey_offset = ro_offset + ro_size - pubkey_size;
403 
404 	/* Skip stuff that obviously doesn't work */
405 	if (sig_size > rw_size || pubkey_size > ro_size)
406 		return VB2_ERROR_UNKNOWN;
407 
408 	vb2_error_t rv = try_our_own(sig_alg, hash_alg,		/* algs */
409 			 buf + pubkey_offset, pubkey_size,     /* pubkey blob */
410 			 buf + sig_offset, sig_size,	       /* sig blob */
411 			 buf + rw_offset, rw_size - sig_size); /* RW image */
412 
413 	if (rv == VB2_SUCCESS && fname)
414 		show_usbpd1_stuff(fname, sig_alg, hash_alg,
415 				  buf + pubkey_offset, pubkey_size);
416 
417 	return rv;
418 }
419 
ft_show_usbpd1(const char * fname)420 int ft_show_usbpd1(const char *fname)
421 {
422 	int fd = -1;
423 	uint8_t *buf;
424 	uint32_t len;
425 	int rv = 1;
426 
427 	if (futil_open_and_map_file(fname, &fd, FILE_RO, &buf, &len))
428 		return 1;
429 
430 	VB2_DEBUG("name %s len  0x%08x (%d)\n", fname, len, len);
431 
432 	/* Get image locations */
433 	uint32_t ro_size, rw_size, ro_offset, rw_offset;
434 	if (!parse_size_opts(len, &ro_size, &rw_size, &ro_offset, &rw_offset))
435 		goto done;
436 
437 	/* TODO: If we don't have a RO image, ask for a public key
438 	 * TODO: If we're given an external public key, use it (and its alg) */
439 	if (!ro_size) {
440 		printf("Can't find the public key\n");
441 		goto done;
442 	}
443 
444 	/* TODO: Only loop through the numbers we haven't been given */
445 	for (enum vb2_signature_algorithm s = 0; s < ARRAY_SIZE(sigs); s++) {
446 		for (enum vb2_hash_algorithm h = 0; h < ARRAY_SIZE(hashes); h++) {
447 			if (!check_self_consistency(buf, fname, ro_size, rw_size,
448 						    ro_offset, rw_offset,
449 						    sigs[s], hashes[h])) {
450 				rv = 0;
451 				goto done;
452 			}
453 		}
454 	}
455 
456 	printf("This doesn't appear to be a complete usbpd1 image\n");
457 done:
458 	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
459 	return rv;
460 }
461 
ft_recognize_usbpd1(uint8_t * buf,uint32_t len)462 enum futil_file_type ft_recognize_usbpd1(uint8_t *buf, uint32_t len)
463 {
464 	/*
465 	 * Since we don't use any headers to identify or locate the pubkey and
466 	 * signature, in order to identify blob as the right type we have to
467 	 * just assume that the RO & RW are 1) both present, and 2) evenly
468 	 * split. Then we just try to use what we think might be the pubkey to
469 	 * validate what we think might be the signature.
470 	 */
471 	const uint32_t ro_offset = 0;
472 	const uint32_t ro_size = len / 2;
473 	const uint32_t rw_size = len / 2;
474 	const uint32_t rw_offset = len / 2;
475 
476 	for (enum vb2_signature_algorithm s = 0; s < ARRAY_SIZE(sigs); s++) {
477 		for (enum vb2_hash_algorithm h = 0; h < ARRAY_SIZE(hashes); h++) {
478 			if (!check_self_consistency(buf, 0, ro_size, rw_size,
479 						    ro_offset, rw_offset,
480 						    sigs[s], hashes[h]))
481 				return FILE_TYPE_USBPD1;
482 		}
483 	}
484 
485 	return FILE_TYPE_UNKNOWN;
486 }
487