/* 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. */ #include #include "2sysincludes.h" #include "2common.h" #include "2id.h" #include "2rsa.h" #include "2sha.h" #include "openssl_compat.h" #include "util_misc.h" #include "vb21_common.h" #include "host_common.h" #include "host_key2.h" #include "host_misc2.h" #include "file_type.h" #include "futility.h" #include "futility_options.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_vb21_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 == vb21_unpack_key(&pubkey, buf, len)) return FILE_TYPE_VB2_PUBKEY; /* The private key unpacks into new structs */ if (VB2_SUCCESS == vb21_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 int vb2_public_key_sha1sum(struct vb2_public_key *key, uint8_t *digest) { struct vb21_packed_key *pkey; if (vb21_public_key_pack(&pkey, key)) return 0; vb2_digest_buffer((uint8_t *)pkey + pkey->key_offset, pkey->key_size, VB2_HASH_SHA1, digest, VB2_SHA1_DIGEST_SIZE); free(pkey); return 1; } int ft_show_vb21_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data) { struct vb2_public_key key; uint8_t sha1sum[VB2_SHA1_DIGEST_SIZE]; /* The key's members will point into the state buffer after this. Don't * free anything. */ if (VB2_SUCCESS != vb21_unpack_key(&key, buf, len)) return 1; printf("Public Key file: %s\n", name); printf(" Vboot API: 2.1\n"); printf(" Desc: \"%s\"\n", key.desc); printf(" Signature Algorithm: %d %s\n", key.sig_alg, vb2_get_sig_algorithm_name(key.sig_alg)); printf(" Hash Algorithm: %d %s\n", key.hash_alg, vb2_get_hash_algorithm_name(key.hash_alg)); printf(" Version: 0x%08x\n", key.version); printf(" ID: "); vb2_print_bytes(key.id, sizeof(*key.id)); printf("\n"); if (vb2_public_key_sha1sum(&key, sha1sum) && memcmp(key.id, sha1sum, sizeof(*key.id))) { printf(" Key sha1sum: "); vb2_print_bytes(sha1sum, sizeof(sha1sum)); printf("\n"); } return 0; } static int vb2_private_key_sha1sum(struct vb2_private_key *key, uint8_t *digest) { uint8_t *buf; uint32_t buflen; if (vb_keyb_from_rsa(key->rsa_private_key, &buf, &buflen)) return 0; vb2_digest_buffer(buf, buflen, VB2_HASH_SHA1, digest, VB2_SHA1_DIGEST_SIZE); free(buf); return 1; } int ft_show_vb21_privkey(const char *name, uint8_t *buf, uint32_t len, void *data) { struct vb2_private_key *key = 0; uint8_t sha1sum[VB2_SHA1_DIGEST_SIZE]; if (VB2_SUCCESS != vb21_private_key_unpack(&key, buf, len)) return 1; printf("Private key file: %s\n", name); printf(" Vboot API: 2.1\n"); printf(" Desc: \"%s\"\n", key->desc ? key->desc : ""); printf(" Signature Algorithm: %d %s\n", key->sig_alg, vb2_get_sig_algorithm_name(key->sig_alg)); printf(" Hash Algorithm: %d %s\n", key->hash_alg, vb2_get_hash_algorithm_name(key->hash_alg)); printf(" ID: "); vb2_print_bytes(&key->id, sizeof(key->id)); printf("\n"); if (vb2_private_key_sha1sum(key, sha1sum) && memcmp(&key->id, sha1sum, sizeof(key->id))) { printf(" Key sha1sum: "); vb2_print_bytes(sha1sum, sizeof(sha1sum)); printf("\n"); } 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) { if (BIO_reset(bp) < 0) return 0; rsa_key = PEM_read_bio_RSA_PUBKEY(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; uint8_t digest[VB2_SHA1_DIGEST_SIZE]; uint32_t keyb_len; int i, bits; const BIGNUM *rsa_key_n, *rsa_key_d; /* We're called only after ft_recognize_pem, so this should work. */ rsa_key = rsa_from_buffer(buf, len); if (!rsa_key) FATAL("No RSA key found in buffer\n"); /* Use to presence of the private exponent to decide if it's public */ RSA_get0_key(rsa_key, &rsa_key_n, NULL, &rsa_key_d); printf("%s Key file: %s\n", rsa_key_d ? "Private" : "Public", name); 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: "); RSA_free(rsa_key); return 1; } printf(" Key sha1sum: "); vb2_digest_buffer(keyb, keyb_len, VB2_HASH_SHA1, digest, sizeof(digest)); for (i = 0; i < sizeof(digest); i++) printf("%02x", digest[i]); printf("\n"); free(keyb); RSA_free(rsa_key); return 0; }