mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-09 00:51:29 +00:00
The USB Type-C chargers released with Samus ("Pixel (2015)") have
upgradable firmware. Those firmware images are currently signed
by some custom scripts. This adds support for those images to
futility, so that those custom scripts can be replaced.
Note that due to space considerations, the usbpd firmware images
don't have room for handy things like an FMAP or headers for the
signatures. Accordingly, all the normally variable factors (image
size, signature algorithms, etc.) are hard coded and the image
itself just looks like a bunch of random numbers. Because of
this:
1. There's no way to recognize this type of file, and nothing to
display about it.
2. You have to give the "--type usbpd1" arg to the sign command.
3. I'm designating this file type "v1" because I hope that the
firmware for any future adapters will be more readily
identifiable.
BUG=chromium:231574
BRANCH=none
TEST=make runtests
This adds a new test that signs usbpd1 firmware images using
futility, and compares the result to the same files signed by the
custom scripts, ensuring that they are bitwise identical.
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Change-Id: Idbe061db5b3c8e474ada47b40bcbe04bbecdba3a
Reviewed-on: https://chromium-review.googlesource.com/262899
Reviewed-by: Randall Spangler <rspangler@chromium.org>
242 lines
5.7 KiB
C
242 lines
5.7 KiB
C
/*
|
|
* Copyright 2015 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#define OPENSSL_NO_SHA
|
|
#include <openssl/pem.h>
|
|
|
|
#include "2sysincludes.h"
|
|
#include "2common.h"
|
|
#include "2id.h"
|
|
#include "2rsa.h"
|
|
#include "util_misc.h"
|
|
#include "vb2_common.h"
|
|
#include "vb2_struct.h"
|
|
|
|
#include "host_common.h"
|
|
#include "host_key2.h"
|
|
#include "host_misc2.h"
|
|
|
|
#include "file_type.h"
|
|
#include "futility.h"
|
|
|
|
int vb2_lookup_hash_alg(const char *str, enum vb2_hash_algorithm *alg)
|
|
{
|
|
const struct vb2_text_vs_enum *entry;
|
|
uint32_t val;
|
|
char *e;
|
|
|
|
/* try string first */
|
|
entry = vb2_lookup_by_name(vb2_text_vs_hash, str);
|
|
if (entry) {
|
|
*alg = entry->num;
|
|
return 1;
|
|
}
|
|
|
|
/* fine, try number */
|
|
val = strtoul(str, &e, 0);
|
|
if (!*str || (e && *e))
|
|
/* that's not a number */
|
|
return 0;
|
|
|
|
if (!vb2_lookup_by_num(vb2_text_vs_hash, val))
|
|
/* That's not a valid alg */
|
|
return 0;
|
|
|
|
*alg = val;
|
|
return 1;
|
|
}
|
|
|
|
enum futil_file_type ft_recognize_vb2_key(uint8_t *buf, uint32_t len)
|
|
{
|
|
struct vb2_public_key pubkey;
|
|
struct vb2_private_key *privkey = 0;
|
|
|
|
/* The pubkey points into buf, so nothing to free */
|
|
if (VB2_SUCCESS == vb2_unpack_key(&pubkey, buf, len))
|
|
return FILE_TYPE_VB2_PUBKEY;
|
|
|
|
/* The private key unpacks into new structs */
|
|
if (VB2_SUCCESS == vb2_private_key_unpack(&privkey, buf, len)) {
|
|
vb2_private_key_free(privkey);
|
|
return FILE_TYPE_VB2_PRIVKEY;
|
|
}
|
|
|
|
return FILE_TYPE_UNKNOWN;
|
|
}
|
|
|
|
static inline void vb2_print_bytes(const void *ptr, uint32_t len)
|
|
{
|
|
const uint8_t *buf = (const uint8_t *)ptr;
|
|
int i;
|
|
for (i = 0; i < len; i++)
|
|
printf("%02x", *buf++);
|
|
}
|
|
|
|
static uint8_t *vb2_public_key_sha1sum(struct vb2_public_key *key)
|
|
{
|
|
struct vb2_packed_key *pkey;
|
|
uint8_t *digest;
|
|
|
|
if (vb2_public_key_pack(&pkey, key))
|
|
return 0;
|
|
|
|
digest = DigestBuf((uint8_t *)pkey + pkey->key_offset,
|
|
pkey->key_size, SHA1_DIGEST_ALGORITHM);
|
|
free(pkey);
|
|
|
|
return digest;
|
|
}
|
|
|
|
int ft_show_vb2_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
|
|
{
|
|
struct vb2_public_key key;
|
|
const struct vb2_text_vs_enum *entry;
|
|
uint8_t *sha1sum;
|
|
|
|
/* The key's members will point into the state buffer after this. Don't
|
|
* free anything. */
|
|
if (VB2_SUCCESS != vb2_unpack_key(&key, buf, len))
|
|
return 1;
|
|
|
|
sha1sum = vb2_public_key_sha1sum(&key);
|
|
|
|
printf("Public Key file: %s\n", name);
|
|
printf(" Vboot API: 2.1\n");
|
|
printf(" Desc: \"%s\"\n", key.desc);
|
|
entry = vb2_lookup_by_num(vb2_text_vs_sig, key.sig_alg);
|
|
printf(" Signature Algorithm: %d %s\n", key.sig_alg,
|
|
entry ? entry->name : "(invalid)");
|
|
entry = vb2_lookup_by_num(vb2_text_vs_hash, key.hash_alg);
|
|
printf(" Hash Algorithm: %d %s\n", key.hash_alg,
|
|
entry ? entry->name : "(invalid)");
|
|
printf(" Version: 0x%08x\n", key.version);
|
|
printf(" ID: ");
|
|
vb2_print_bytes(key.id, sizeof(*key.id));
|
|
printf("\n");
|
|
if (sha1sum && memcmp(key.id, sha1sum, sizeof(*key.id))) {
|
|
printf(" Key sha1sum: ");
|
|
vb2_print_bytes(sha1sum, SHA1_DIGEST_SIZE);
|
|
printf("\n");
|
|
}
|
|
free(sha1sum);
|
|
return 0;
|
|
}
|
|
|
|
static uint8_t *vb2_private_key_sha1sum(struct vb2_private_key *key)
|
|
{
|
|
uint8_t *buf, *digest;
|
|
uint32_t buflen;
|
|
|
|
if (vb_keyb_from_rsa(key->rsa_private_key, &buf, &buflen))
|
|
return 0;
|
|
|
|
digest = DigestBuf(buf, buflen, SHA1_DIGEST_ALGORITHM);
|
|
free(buf);
|
|
|
|
return digest;
|
|
}
|
|
|
|
int ft_show_vb2_privkey(const char *name, uint8_t *buf, uint32_t len,
|
|
void *data)
|
|
{
|
|
struct vb2_private_key *key = 0;
|
|
const struct vb2_text_vs_enum *entry;
|
|
uint8_t *sha1sum;
|
|
|
|
if (VB2_SUCCESS != vb2_private_key_unpack(&key, buf, len))
|
|
return 1;
|
|
|
|
sha1sum = vb2_private_key_sha1sum(key);
|
|
|
|
printf("Private key file: %s\n", name);
|
|
printf(" Vboot API: 2.1\n");
|
|
printf(" Desc: \"%s\"\n", key->desc ? key->desc : "");
|
|
entry = vb2_lookup_by_num(vb2_text_vs_sig, key->sig_alg);
|
|
printf(" Signature Algorithm: %d %s\n", key->sig_alg,
|
|
entry ? entry->name : "(invalid)");
|
|
entry = vb2_lookup_by_num(vb2_text_vs_hash, key->hash_alg);
|
|
printf(" Hash Algorithm: %d %s\n", key->hash_alg,
|
|
entry ? entry->name : "(invalid)");
|
|
printf(" ID: ");
|
|
vb2_print_bytes(&key->id, sizeof(key->id));
|
|
printf("\n");
|
|
if (sha1sum && memcmp(&key->id, sha1sum, sizeof(key->id))) {
|
|
printf(" Key sha1sum: ");
|
|
vb2_print_bytes(sha1sum, SHA1_DIGEST_SIZE);
|
|
printf("\n");
|
|
}
|
|
free(sha1sum);
|
|
vb2_private_key_free(key);
|
|
return 0;
|
|
}
|
|
|
|
static RSA *rsa_from_buffer(uint8_t *buf, uint32_t len)
|
|
{
|
|
BIO *bp;
|
|
RSA *rsa_key;
|
|
|
|
bp = BIO_new_mem_buf(buf, len);
|
|
if (!bp)
|
|
return 0;
|
|
|
|
rsa_key = PEM_read_bio_RSAPrivateKey(bp, NULL, NULL, NULL);
|
|
if (!rsa_key) {
|
|
BIO_free(bp);
|
|
return 0;
|
|
}
|
|
|
|
BIO_free(bp);
|
|
|
|
return rsa_key;
|
|
}
|
|
|
|
enum futil_file_type ft_recognize_pem(uint8_t *buf, uint32_t len)
|
|
{
|
|
RSA *rsa_key = rsa_from_buffer(buf, len);
|
|
|
|
if (rsa_key) {
|
|
RSA_free(rsa_key);
|
|
return FILE_TYPE_PEM;
|
|
}
|
|
|
|
return FILE_TYPE_UNKNOWN;
|
|
}
|
|
|
|
int ft_show_pem(const char *name, uint8_t *buf, uint32_t len, void *data)
|
|
{
|
|
RSA *rsa_key;
|
|
uint8_t *keyb, *digest;
|
|
uint32_t keyb_len;
|
|
int i, bits;
|
|
|
|
printf("Private Key file: %s\n", name);
|
|
|
|
/* We're called only after ft_recognize_pem, so this should work. */
|
|
rsa_key = rsa_from_buffer(buf, len);
|
|
if (!rsa_key)
|
|
DIE;
|
|
|
|
bits = BN_num_bits(rsa_key->n);
|
|
printf(" Key length: %d\n", bits);
|
|
|
|
if (vb_keyb_from_rsa(rsa_key, &keyb, &keyb_len)) {
|
|
printf(" Key sha1sum: <error>");
|
|
RSA_free(rsa_key);
|
|
return 1;
|
|
}
|
|
|
|
printf(" Key sha1sum: ");
|
|
digest = DigestBuf(keyb, keyb_len, SHA1_DIGEST_ALGORITHM);
|
|
for (i = 0; i < SHA1_DIGEST_SIZE; i++)
|
|
printf("%02x", digest[i]);
|
|
printf("\n");
|
|
|
|
free(digest);
|
|
free(keyb);
|
|
RSA_free(rsa_key);
|
|
return 0;
|
|
}
|