diff options
author | Bill Richardson <wfrichar@chromium.org> | 2015-02-03 17:07:15 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-03-10 20:44:43 +0000 |
commit | 4e4c19602edf3834b50d66d3ba067e895aca6fa0 (patch) | |
tree | 11b9408e5e6a9c3e3fde95c21656e67562bb3faf | |
parent | 26af0da4f7e0fd5cc9410011ca05ff6539bbf42d (diff) | |
download | vboot-4e4c19602edf3834b50d66d3ba067e895aca6fa0.tar.gz |
futility: Add create command to make keypairs from RSA files
This command reads a single .pem file and emits the public and
private keys generated from it. It can produce both the old-style
vboot 1.0 keys (.vbpubk and .vbprivk), or the new vboot 2.1
format keys (.vbpubk2 and .vbprik2). The default is the new
format, but you can give futility the --vb1 arg to force the old
format.
A test is included.
BUG=chromium:231547
BRANCH=ToT
TEST=make runtests
Change-Id: I4713dc5bf34151052870f88ba52ddccf9d4dab50
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/246766
Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | firmware/2lib/include/2misc.h | 2 | ||||
-rw-r--r-- | firmware/2lib/include/2return_codes.h | 8 | ||||
-rw-r--r-- | futility/cmd_create.c | 402 | ||||
-rw-r--r-- | host/lib/host_key.c | 3 | ||||
-rw-r--r-- | host/lib/host_signature.c | 2 | ||||
-rw-r--r-- | host/lib/include/util_misc.h | 25 | ||||
-rw-r--r-- | host/lib/signature_digest.c | 4 | ||||
-rw-r--r-- | host/lib/util_misc.c | 133 | ||||
-rw-r--r-- | host/lib21/host_key.c | 116 | ||||
-rw-r--r-- | host/lib21/host_misc.c | 69 | ||||
-rw-r--r-- | host/lib21/host_signature.c | 2 | ||||
-rw-r--r-- | host/lib21/include/host_key2.h | 67 | ||||
-rw-r--r-- | host/lib21/include/host_misc2.h | 36 | ||||
-rwxr-xr-x | tests/futility/run_test_scripts.sh | 9 | ||||
-rwxr-xr-x | tests/futility/test_create.sh | 39 | ||||
-rw-r--r-- | utility/dumpRSAPublicKey.c | 7 |
17 files changed, 879 insertions, 50 deletions
@@ -605,6 +605,7 @@ FUTIL_STATIC_SRCS = \ FUTIL_SRCS = \ ${FUTIL_STATIC_SRCS} \ + futility/cmd_create.c \ futility/cmd_dump_kernel_config.c \ futility/cmd_load_fmap.c \ futility/cmd_pcr.c \ @@ -630,6 +631,10 @@ FUTIL_STATIC_OBJS = ${FUTIL_STATIC_SRCS:%.c=${BUILD}/%.o} \ ${FUTIL_STATIC_CMD_LIST:%.c=%.o} FUTIL_OBJS = ${FUTIL_SRCS:%.c=${BUILD}/%.o} ${FUTIL_CMD_LIST:%.c=%.o} +${FUTIL_OBJS}: INCLUDES += -Ihost/lib21/include -Ifirmware/lib21/include +${FUTIL_BIN}: ${UTILLIB21} +${FUTIL_BIN}: LIBS += ${UTILLIB21} + ALL_OBJS += ${FUTIL_OBJS} diff --git a/firmware/2lib/include/2misc.h b/firmware/2lib/include/2misc.h index 928ada3c..1eccde9b 100644 --- a/firmware/2lib/include/2misc.h +++ b/firmware/2lib/include/2misc.h @@ -27,7 +27,7 @@ static __inline struct vb2_shared_data *vb2_get_sd(struct vb2_context *ctx) { * Validate gbb signature (the magic number) * * @param sig Pointer to the signature bytes to validate - * @return VB2_SUCCESS if valid or VB2_ERROR_GBB_MAGIC otherwise. + * @return VB2_SUCCESS if valid or non-zero if error. */ int vb2_validate_gbb_signature(uint8_t *sig); diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h index 7b54f6db..384879dc 100644 --- a/firmware/2lib/include/2return_codes.h +++ b/firmware/2lib/include/2return_codes.h @@ -490,6 +490,12 @@ enum vb2_return_code { /* Unable to write data in write_file() */ VB2_ERROR_WRITE_FILE_DATA, + /* Unable to convert string to struct vb_guid */ + VB2_ERROR_STR_TO_GUID, + + /* Unable to convert struct vb_guid to string */ + VB2_ERROR_GUID_TO_STR, + /********************************************************************** * Errors generated by host library key functions */ @@ -573,7 +579,7 @@ enum vb2_return_code { /* Unable to determine key size in vb2_public_key_pack() */ VB2_ERROR_PUBLIC_KEY_PACK_SIZE, - /* Bad hash algorithm in vb2_publc_key_hash() */ + /* Bad hash algorithm in vb2_public_key_hash() */ VB2_ERROR_PUBLIC_KEY_HASH, /********************************************************************** diff --git a/futility/cmd_create.c b/futility/cmd_create.c new file mode 100644 index 00000000..f4eb3f2a --- /dev/null +++ b/futility/cmd_create.c @@ -0,0 +1,402 @@ +/* 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 <getopt.h> +#include <stdio.h> +#include <unistd.h> + +#define OPENSSL_NO_SHA +#include <openssl/pem.h> + +#include "2sysincludes.h" +#include "2common.h" +#include "2guid.h" +#include "2rsa.h" +#include "util_misc.h" +#include "vb2_common.h" +#include "vb2_struct.h" + +#include "host_key.h" +#include "host_key2.h" +#include "host_misc2.h" + +#include "futility.h" + +/* Command line options */ +enum { + OPT_OUTFILE = 1000, + OPT_VERSION, + OPT_DESC, + OPT_GUID, + OPT_HASH_ALG, +}; + +#define DEFAULT_VERSION 1 +#define DEFAULT_HASH VB2_HASH_SHA256; + +static char *infile, *outfile, *outext; +static uint32_t opt_version = DEFAULT_VERSION; +enum vb2_hash_algorithm opt_hash_alg = DEFAULT_HASH; +static char *opt_desc; +static struct vb2_guid opt_guid; + +static const struct option long_opts[] = { + {"version", 1, 0, OPT_VERSION}, + {"desc", 1, 0, OPT_DESC}, + {"guid", 1, 0, OPT_GUID}, + {"hash_alg", 1, 0, OPT_HASH_ALG}, + {NULL, 0, 0, 0} +}; + +static void print_help(const char *progname) +{ + struct vb2_text_vs_enum *entry; + + printf("\n" +"Usage: " MYNAME " %s [options] <INFILE> [<BASENAME>]\n", progname); + printf("\n" +"Create a keypair from an RSA key (.pem file).\n" +"\n" +"Options:\n" +"\n" +" --version <number> Key version (default %d)\n" +" --hash_alg <number> Hashing algorithm to use:\n", + DEFAULT_VERSION); + for (entry = vb2_text_vs_hash; entry->name; entry++) + printf(" %d / %s%s\n", + entry->num, entry->name, + entry->num == VB2_HASH_SHA256 ? " (default)" : ""); + printf( +" --guid <guid> Identifier for this keypair (vb21 only)\n" +" --desc <text> Human-readable description (vb21 only)\n" +"\n"); + +} + +static int vb1_make_keypair() +{ + VbPrivateKey *privkey = 0; + VbPublicKey *pubkey = 0; + RSA *rsa_key = 0; + uint8_t *keyb_data = 0; + uint32_t keyb_size; + enum vb2_signature_algorithm sig_alg; + uint64_t vb1_algorithm; + FILE *fp; + int ret = 1; + + fp = fopen(infile, "rb"); + if (!fp) { + fprintf(stderr, "Unable to open %s\n", infile); + goto done; + } + + rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); + fclose(fp); + + if (!rsa_key) { + fprintf(stderr, "Unable to read RSA key from %s\n", infile); + goto done; + } + + sig_alg = vb2_rsa_sig_alg(rsa_key); + if (sig_alg == VB2_SIG_INVALID) { + fprintf(stderr, "Unsupported sig algorithm in RSA key\n"); + goto done; + } + + /* combine the sig_alg with the hash_alg to get the vb1 algorithm */ + vb1_algorithm = (sig_alg - VB2_SIG_RSA1024) * 3 + + opt_hash_alg - VB2_HASH_SHA1; + + /* Create the private key */ + privkey = (VbPrivateKey *)malloc(sizeof(VbPrivateKey)); + if (!privkey) + goto done; + + privkey->rsa_private_key = rsa_key; + privkey->algorithm = vb1_algorithm; + + /* Write it out */ + strcpy(outext, ".vbprivk"); + if (0 != PrivateKeyWrite(outfile, privkey)) { + fprintf(stderr, "unable to write private key\n"); + goto done; + } + fprintf(stderr, "wrote %s\n", outfile); + + /* Create the public key */ + ret = vb_keyb_from_rsa(rsa_key, &keyb_data, &keyb_size); + if (ret) { + fprintf(stderr, "couldn't extract the public key\n"); + goto done; + } + + pubkey = PublicKeyAlloc(keyb_size, vb1_algorithm, opt_version); + if (!pubkey) + goto done; + memcpy(GetPublicKeyData(pubkey), keyb_data, keyb_size); + + /* Write it out */ + strcpy(outext, ".vbpubk"); + if (0 != PublicKeyWrite(outfile, pubkey)) { + fprintf(stderr, "unable to write public key\n"); + goto done; + } + fprintf(stderr, "wrote %s\n", outfile); + + ret = 0; + +done: + free(privkey); + free(pubkey); + free(keyb_data); + RSA_free(rsa_key); + return ret; +} + +static int vb2_make_keypair() +{ + struct vb2_private_key *privkey = 0; + struct vb2_public_key *pubkey = 0; + RSA *rsa_key = 0; + uint8_t *keyb_data = 0; + uint32_t keyb_size; + enum vb2_signature_algorithm sig_alg; + uint8_t *pubkey_buf = 0; + + FILE *fp; + int ret = 1; + + fp = fopen(infile, "rb"); + if (!fp) { + fprintf(stderr, "Unable to open %s\n", infile); + goto done; + } + + rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); + fclose(fp); + + if (!rsa_key) { + fprintf(stderr, "Unable to read RSA key from %s\n", infile); + goto done; + } + + sig_alg = vb2_rsa_sig_alg(rsa_key); + if (sig_alg == VB2_SIG_INVALID) { + fprintf(stderr, "Unsupported sig algorithm in RSA key\n"); + goto done; + } + + /* Create the private key */ + privkey = calloc(1, sizeof(*privkey)); + if (!privkey) { + fprintf(stderr, "Unable to allocate the private key\n"); + goto done; + } + privkey->rsa_private_key = rsa_key; + privkey->sig_alg = sig_alg; + privkey->hash_alg = opt_hash_alg; + privkey->guid = opt_guid; + if (opt_desc && vb2_private_key_set_desc(privkey, opt_desc)) { + fprintf(stderr, "Unable to set the private key description\n"); + goto done; + } + + /* Write it out */ + strcpy(outext, ".vbprik2"); + if (vb2_private_key_write(privkey, outfile)) { + fprintf(stderr, "unable to write private key\n"); + goto done; + } + fprintf(stderr, "wrote %s\n", outfile); + + /* Create the public key */ + if (vb2_public_key_alloc(&pubkey, sig_alg)) { + fprintf(stderr, "Unable to allocate the public key\n"); + goto done; + } + + /* Extract the keyb blob */ + if (vb_keyb_from_rsa(rsa_key, &keyb_data, &keyb_size)) { + fprintf(stderr, "Couldn't extract the public key\n"); + goto done; + } + + /* + * Copy the keyb blob to the public key's buffer, because that's where + * vb2_unpack_key_data() and vb2_public_key_pack() expect to find it. + */ + pubkey_buf = vb2_public_key_packed_data(pubkey); + memcpy(pubkey_buf, keyb_data, keyb_size); + + /* Fill in the internal struct pointers */ + if (vb2_unpack_key_data(pubkey, pubkey_buf, keyb_size)) { + fprintf(stderr, "Unable to unpack the public key blob\n"); + goto done; + } + + pubkey->hash_alg = opt_hash_alg; + pubkey->version = opt_version; + memcpy((struct vb2_guid *)pubkey->guid, &opt_guid, sizeof(opt_guid)); + if (opt_desc && vb2_public_key_set_desc(pubkey, opt_desc)) { + fprintf(stderr, "Unable to set pubkey description\n"); + goto done; + } + + /* Write it out */ + strcpy(outext, ".vbpubk2"); + if (vb2_public_key_write(pubkey, outfile)) { + fprintf(stderr, "unable to write public key\n"); + goto done; + } + fprintf(stderr, "wrote %s\n", outfile); + + ret = 0; + +done: + RSA_free(rsa_key); + if (privkey) /* prevent double-free */ + privkey->rsa_private_key = 0; + vb2_private_key_free(privkey); + vb2_public_key_free(pubkey); + free(keyb_data); + return ret; +} + +static int do_create(int argc, char *argv[]) +{ + int errorcnt = 0; + char *e, *s; + int i, r, len, remove_ext = 0; + const struct vb2_text_vs_enum *entry; + + while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (i) { + + case OPT_VERSION: + opt_version = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, + "invalid version \"%s\"\n", optarg); + errorcnt = 1; + } + break; + + case OPT_DESC: + opt_desc = optarg; + break; + + case OPT_GUID: + if (VB2_SUCCESS != vb2_str_to_guid(optarg, + &opt_guid)) { + fprintf(stderr, "invalid guid \"%s\"\n", + optarg); + errorcnt = 1; + } + break; + + case OPT_HASH_ALG: + /* try string first */ + entry = vb2_lookup_by_name(vb2_text_vs_hash, optarg); + if (entry) { + opt_hash_alg = entry->num; + break; + } + /* fine, try number */ + opt_hash_alg = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, + "invalid hash_alg \"%s\"\n", optarg); + errorcnt++; + break; + } + if (!vb2_lookup_by_num(vb2_text_vs_hash, + opt_hash_alg)) { + fprintf(stderr, + "Hash algorithm %d is unsupported\n", + opt_hash_alg); + errorcnt++; + } + break; + + case '?': + if (optopt) + fprintf(stderr, "Unrecognized option: -%c\n", + optopt); + else + fprintf(stderr, "Unrecognized option\n"); + errorcnt++; + break; + case ':': + fprintf(stderr, "Missing argument to -%c\n", optopt); + errorcnt++; + break; + case 0: /* handled option */ + break; + default: + DIE; + } + } + + /* If we don't have an input file already, we need one */ + if (!infile) { + if (argc - optind <= 0) { + fprintf(stderr, "ERROR: missing input filename\n"); + errorcnt++; + } else { + infile = argv[optind++]; + } + } + + if (errorcnt) { + print_help(argv[0]); + return 1; + } + + /* Decide how to determine the output filenames. */ + if (argc > optind) { + s = argv[optind++]; /* just use this */ + } else { + s = infile; /* based on pem file name */ + remove_ext = 1; + } + + /* Make an extra-large copy to leave room for filename extensions */ + len = strlen(s) + 20; + outfile = (char *)malloc(len); + if (!outfile) { + fprintf(stderr, "ERROR: malloc() failed\n"); + return 1; + } + strcpy(outfile, s); + + if (remove_ext) { + /* Find the last '/' if any, then the last '.' before that. */ + s = strrchr(outfile, '/'); + if (!s) + s = outfile; + s = strrchr(s, '.'); + /* Cut off the extension */ + if (s) + *s = '\0'; + } + /* Remember that spot for later */ + outext = outfile + strlen(outfile); + + /* Okay, do it */ + if (vboot_version == VBOOT_VERSION_1_0) + r = vb1_make_keypair(); + else + r = vb2_make_keypair(); + + free(outfile); + return r; +} + +DECLARE_FUTIL_COMMAND(create, do_create, + VBOOT_VERSION_ALL, + "Create a keypair from an RSA .pem file", + print_help); diff --git a/host/lib/host_key.c b/host/lib/host_key.c index c9efa85c..067a188e 100644 --- a/host/lib/host_key.c +++ b/host/lib/host_key.c @@ -8,10 +8,7 @@ /* TODO: change all 'return 0', 'return 1' into meaningful return codes */ #define OPENSSL_NO_SHA -#include <openssl/engine.h> #include <openssl/pem.h> -#include <openssl/rsa.h> -#include <openssl/x509.h> #include <stdio.h> #include <stdlib.h> diff --git a/host/lib/host_signature.c b/host/lib/host_signature.c index 1ea6bc40..43766cfa 100644 --- a/host/lib/host_signature.c +++ b/host/lib/host_signature.c @@ -8,8 +8,6 @@ /* TODO: change all 'return 0', 'return 1' into meaningful return codes */ #define OPENSSL_NO_SHA -#include <openssl/engine.h> -#include <openssl/pem.h> #include <openssl/rsa.h> #include <stdio.h> diff --git a/host/lib/include/util_misc.h b/host/lib/include/util_misc.h index 788929de..0a6ed4c4 100644 --- a/host/lib/include/util_misc.h +++ b/host/lib/include/util_misc.h @@ -9,8 +9,33 @@ #define VBOOT_REFERENCE_UTIL_MISC_H_ #include "vboot_struct.h" +struct rsa_st; /* Prints the sha1sum of the given VbPublicKey to stdout. */ void PrintPubKeySha1Sum(VbPublicKey* key); +/* + * Our packed RSBPublicKey buffer (historically in files ending with ".keyb", + * but also the part of VbPublicKey and struct vb2_packed_key that is + * referenced by .key_offset) has this binary format: + * + * struct { + * uint32_t nwords; // size of RSA key in 32-bit words + * uint32_t N0inv; // -1 / N[0] mod 2^32 + * uint32_t modulus[nwords]; // modulus as a little endian array + * uint32_t R2[nwords]; // R^2 as little endian array + * }; + * + * This function allocates and extracts that binary structure directly + * from the RSA private key, rather than from a file. + * + * @param rsa_private_key RSA private key (duh) + * @param keyb_data Pointer to newly allocated binary blob + * @param keyb_size Size of newly allocated binary blob + * + * @return 0 on success, non-zero if unable to allocate enough memory. + */ +int vb_keyb_from_rsa(struct rsa_st *rsa_private_key, + uint8_t **keyb_data, uint32_t *keyb_size); + #endif /* VBOOT_REFERENCE_UTIL_MISC_H_ */ diff --git a/host/lib/signature_digest.c b/host/lib/signature_digest.c index 81c666ea..c9e721e4 100644 --- a/host/lib/signature_digest.c +++ b/host/lib/signature_digest.c @@ -3,11 +3,8 @@ * found in the LICENSE file. */ -#include "signature_digest.h" #define OPENSSL_NO_SHA -#include <openssl/engine.h> #include <openssl/pem.h> -#include <openssl/rsa.h> #include <stdio.h> #include <stdlib.h> @@ -15,6 +12,7 @@ #include "cryptolib.h" #include "host_common.h" +#include "signature_digest.h" uint8_t* PrependDigestInfo(unsigned int algorithm, uint8_t* digest) { diff --git a/host/lib/util_misc.c b/host/lib/util_misc.c index 09df8eef..d2c21f52 100644 --- a/host/lib/util_misc.c +++ b/host/lib/util_misc.c @@ -5,6 +5,9 @@ * Miscellaneous functions for userspace vboot utilities. */ +#define OPENSSL_NO_SHA +#include <openssl/rsa.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -15,12 +18,126 @@ #include "util_misc.h" #include "vboot_common.h" -void PrintPubKeySha1Sum(VbPublicKey* key) { - uint8_t* buf = ((uint8_t *)key) + key->key_offset; - uint64_t buflen = key->key_size; - uint8_t* digest = DigestBuf(buf, buflen, SHA1_DIGEST_ALGORITHM); - int i; - for (i=0; i<SHA1_DIGEST_SIZE; i++) - printf("%02x", digest[i]); - free(digest); +void PrintPubKeySha1Sum(VbPublicKey *key) +{ + uint8_t *buf = ((uint8_t *)key) + key->key_offset; + uint64_t buflen = key->key_size; + uint8_t *digest = DigestBuf(buf, buflen, SHA1_DIGEST_ALGORITHM); + int i; + for (i = 0; i < SHA1_DIGEST_SIZE; i++) + printf("%02x", digest[i]); + free(digest); +} + +int vb_keyb_from_rsa(struct rsa_st *rsa_private_key, + uint8_t **keyb_data, uint32_t *keyb_size) +{ + uint32_t i, nwords; + BIGNUM *N = NULL; + BIGNUM *Big1 = NULL, *Big2 = NULL, *Big32 = NULL, *BigMinus1 = NULL; + BIGNUM *B = NULL; + BIGNUM *N0inv = NULL, *R = NULL, *RR = NULL; + BIGNUM *RRTemp = NULL, *NnumBits = NULL; + BIGNUM *n = NULL, *rr = NULL; + BN_CTX *bn_ctx = BN_CTX_new(); + uint32_t n0invout; + uint32_t bufsize; + uint32_t *outbuf; + int retval = 1; + + /* Size of RSA key in 32-bit words */ + nwords = BN_num_bits(rsa_private_key->n) / 32; + + bufsize = (2 + nwords + nwords) * sizeof(uint32_t); + outbuf = malloc(bufsize); + if (!outbuf) + goto done; + + *keyb_data = (uint8_t *)outbuf; + *keyb_size = bufsize; + + *outbuf++ = nwords; + + /* Initialize BIGNUMs */ +#define NEW_BIGNUM(x) do { x = BN_new(); if (!x) goto done; } while (0) + NEW_BIGNUM(N); + NEW_BIGNUM(Big1); + NEW_BIGNUM(Big2); + NEW_BIGNUM(Big32); + NEW_BIGNUM(BigMinus1); + NEW_BIGNUM(N0inv); + NEW_BIGNUM(R); + NEW_BIGNUM(RR); + NEW_BIGNUM(RRTemp); + NEW_BIGNUM(NnumBits); + NEW_BIGNUM(n); + NEW_BIGNUM(rr); + NEW_BIGNUM(B); +#undef NEW_BIGNUM + + BN_copy(N, rsa_private_key->n); + BN_set_word(Big1, 1L); + BN_set_word(Big2, 2L); + BN_set_word(Big32, 32L); + BN_sub(BigMinus1, Big1, Big2); + + BN_exp(B, Big2, Big32, bn_ctx); /* B = 2^32 */ + + /* Calculate and output N0inv = -1 / N[0] mod 2^32 */ + BN_mod_inverse(N0inv, N, B, bn_ctx); + BN_sub(N0inv, B, N0inv); + n0invout = BN_get_word(N0inv); + + *outbuf++ = n0invout; + + /* Calculate R = 2^(# of key bits) */ + BN_set_word(NnumBits, BN_num_bits(N)); + BN_exp(R, Big2, NnumBits, bn_ctx); + + /* Calculate RR = R^2 mod N */ + BN_copy(RR, R); + BN_mul(RRTemp, RR, R, bn_ctx); + BN_mod(RR, RRTemp, N, bn_ctx); + + + /* Write out modulus as little endian array of integers. */ + for (i = 0; i < nwords; ++i) { + uint32_t nout; + + BN_mod(n, N, B, bn_ctx); /* n = N mod B */ + nout = BN_get_word(n); + *outbuf++ = nout; + + BN_rshift(N, N, 32); /* N = N/B */ + } + + /* Write R^2 as little endian array of integers. */ + for (i = 0; i < nwords; ++i) { + uint32_t rrout; + + BN_mod(rr, RR, B, bn_ctx); /* rr = RR mod B */ + rrout = BN_get_word(rr); + *outbuf++ = rrout; + + BN_rshift(RR, RR, 32); /* RR = RR/B */ + } + + outbuf = NULL; + retval = 0; + +done: + free(outbuf); + /* Free BIGNUMs. */ + BN_free(Big1); + BN_free(Big2); + BN_free(Big32); + BN_free(BigMinus1); + BN_free(N0inv); + BN_free(R); + BN_free(RRTemp); + BN_free(NnumBits); + BN_free(n); + BN_free(rr); + + return retval; } diff --git a/host/lib21/host_key.c b/host/lib21/host_key.c index 5123b85d..4acba9cb 100644 --- a/host/lib21/host_key.c +++ b/host/lib21/host_key.c @@ -5,11 +5,10 @@ * Host functions for keys. */ +#include <stdio.h> + #define OPENSSL_NO_SHA -#include <openssl/engine.h> #include <openssl/pem.h> -#include <openssl/rsa.h> -#include <openssl/x509.h> #include "2sysincludes.h" #include "2common.h" @@ -20,6 +19,57 @@ #include "host_key2.h" #include "host_misc.h" +struct vb2_text_vs_enum vb2_text_vs_algorithm[] = { + {"RSA1024 SHA1", VB2_ALG_RSA1024_SHA1}, + {"RSA1024 SHA256", VB2_ALG_RSA1024_SHA256}, + {"RSA1024 SHA512", VB2_ALG_RSA1024_SHA512}, + {"RSA2048 SHA1", VB2_ALG_RSA2048_SHA1}, + {"RSA2048 SHA256", VB2_ALG_RSA2048_SHA256}, + {"RSA2048 SHA512", VB2_ALG_RSA2048_SHA512}, + {"RSA4096 SHA1", VB2_ALG_RSA4096_SHA1}, + {"RSA4096 SHA256", VB2_ALG_RSA4096_SHA256}, + {"RSA4096 SHA512", VB2_ALG_RSA4096_SHA512}, + {"RSA8192 SHA1", VB2_ALG_RSA8192_SHA1}, + {"RSA8192 SHA256", VB2_ALG_RSA8192_SHA256}, + {"RSA8192 SHA512", VB2_ALG_RSA8192_SHA512}, + {0, 0} +}; + +struct vb2_text_vs_enum vb2_text_vs_sig[] = { + {"RSA1024", VB2_SIG_RSA1024}, + {"RSA2048", VB2_SIG_RSA2048}, + {"RSA4096", VB2_SIG_RSA4096}, + {"RSA8192", VB2_SIG_RSA8192}, + {0, 0} +}; + +struct vb2_text_vs_enum vb2_text_vs_hash[] = { + {"SHA1", VB2_HASH_SHA1}, + {"SHA256", VB2_HASH_SHA256}, + {"SHA512", VB2_HASH_SHA512}, + {0, 0} +}; + +const struct vb2_text_vs_enum *vb2_lookup_by_num( + const struct vb2_text_vs_enum *table, + const unsigned int num) +{ + for (; table->name; table++) + if (table->num == num) + return table; + return 0; +} + +const struct vb2_text_vs_enum *vb2_lookup_by_name( + const struct vb2_text_vs_enum *table, + const char *name) +{ + for (; table->name; table++) + if (!strcasecmp(table->name, name)) + return table; + return 0; +} + void vb2_private_key_free(struct vb2_private_key *key) { if (!key) @@ -284,19 +334,8 @@ int vb2_private_key_hash(const struct vb2_private_key **key_ptr, } } -/** - * Allocate a public key buffer of sufficient size for the signature algorithm. - * - * This only initializes the sig_alg field and the guid field to an empty - * guid. It does not set any of the other fields in *key_ptr. - * - * @param key_ptr Destination for newly allocated key; this must be - * freed with vb2_public_key_free(). - * @param sig_alg Signature algorithm for key. - * @return VB2_SUCCESS, or non-zero error code if error. - */ -static int vb2_public_key_alloc(struct vb2_public_key **key_ptr, - enum vb2_signature_algorithm sig_alg) +int vb2_public_key_alloc(struct vb2_public_key **key_ptr, + enum vb2_signature_algorithm sig_alg) { struct vb2_public_key *key; uint32_t key_data_size = vb2_packed_key_size(sig_alg); @@ -322,18 +361,16 @@ static int vb2_public_key_alloc(struct vb2_public_key **key_ptr, void vb2_public_key_free(struct vb2_public_key *key) { + if (!key) + return; + if (key->desc) free((void *)key->desc); free(key); } -/** - * Return the packed data for a key allocated with vb2_public_key_alloc(). - * - * The packed data is in the same buffer, following the key struct and GUID. - */ -static uint8_t *vb2_public_key_packed_data(struct vb2_public_key *key) +uint8_t *vb2_public_key_packed_data(struct vb2_public_key *key) { return (uint8_t *)(key->guid + 1); } @@ -505,3 +542,38 @@ int vb2_public_key_hash(struct vb2_public_key *key, key->guid = vb2_hash_guid(hash_alg); return VB2_SUCCESS; } + +enum vb2_signature_algorithm vb2_rsa_sig_alg(struct rsa_st *rsa) +{ + int bits = BN_num_bits(rsa->n); + + switch (bits) { + case 1024: + return VB2_SIG_RSA1024; + case 2048: + return VB2_SIG_RSA2048; + case 4096: + return VB2_SIG_RSA4096; + case 8192: + return VB2_SIG_RSA8192; + } + + /* no clue */ + return VB2_SIG_INVALID; +} + +int vb2_public_key_write(const struct vb2_public_key *key, + const char *filename) +{ + struct vb2_packed_key *pkey; + int ret; + + ret = vb2_public_key_pack(&pkey, key); + if (ret) + return ret; + + ret = vb2_write_object(filename, pkey); + + free(pkey); + return ret; +} diff --git a/host/lib21/host_misc.c b/host/lib21/host_misc.c index 555867a2..c55996eb 100644 --- a/host/lib21/host_misc.c +++ b/host/lib21/host_misc.c @@ -13,6 +13,7 @@ #include "2sha.h" #include "vb2_common.h" #include "host_common.h" +#include "host_misc2.h" int vb2_read_file(const char *filename, uint8_t **data_ptr, uint32_t *size_ptr) { @@ -93,3 +94,71 @@ uint32_t vb2_desc_size(const char *desc) return roundup32(strlen(desc) + 1); } +int vb2_str_to_guid(const char *str, struct vb2_guid *guid) +{ + uint32_t time_low; + uint16_t time_mid; + uint16_t time_high_and_version; + unsigned int chunk[11]; + + if (!str || + 11 != sscanf(str, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + chunk+0, + chunk+1, + chunk+2, + chunk+3, + chunk+4, + chunk+5, + chunk+6, + chunk+7, + chunk+8, + chunk+9, + chunk+10)) { + return VB2_ERROR_STR_TO_GUID; + } + + time_low = chunk[0] & 0xffffffff; + time_mid = chunk[1] & 0xffff; + time_high_and_version = chunk[2] & 0xffff; + + guid->uuid.time_low = htole32(time_low); + guid->uuid.time_mid = htole16(time_mid); + guid->uuid.time_high_and_version = htole16(time_high_and_version); + + guid->uuid.clock_seq_high_and_reserved = chunk[3] & 0xff; + guid->uuid.clock_seq_low = chunk[4] & 0xff; + guid->uuid.node[0] = chunk[5] & 0xff; + guid->uuid.node[1] = chunk[6] & 0xff; + guid->uuid.node[2] = chunk[7] & 0xff; + guid->uuid.node[3] = chunk[8] & 0xff; + guid->uuid.node[4] = chunk[9] & 0xff; + guid->uuid.node[5] = chunk[10] & 0xff; + + return VB2_SUCCESS; +} + +int vb2_guid_to_str(const struct vb2_guid *guid, + char *buf, unsigned int buflen) +{ + int n; + + if (!buf || buflen < VB2_GUID_MIN_STRLEN) + return VB2_ERROR_GUID_TO_STR; + + n = snprintf(buf, buflen, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + le32toh(guid->uuid.time_low), + le16toh(guid->uuid.time_mid), + le16toh(guid->uuid.time_high_and_version), + guid->uuid.clock_seq_high_and_reserved, + guid->uuid.clock_seq_low, + guid->uuid.node[0], guid->uuid.node[1], + guid->uuid.node[2], guid->uuid.node[3], + guid->uuid.node[4], guid->uuid.node[5]); + + if (n != VB2_GUID_MIN_STRLEN - 1) + return VB2_ERROR_GUID_TO_STR; + + return VB2_SUCCESS; +} diff --git a/host/lib21/host_signature.c b/host/lib21/host_signature.c index 553aa386..11785c71 100644 --- a/host/lib21/host_signature.c +++ b/host/lib21/host_signature.c @@ -6,8 +6,6 @@ */ #define OPENSSL_NO_SHA -#include <openssl/engine.h> -#include <openssl/pem.h> #include <openssl/rsa.h> #include "2sysincludes.h" diff --git a/host/lib21/include/host_key2.h b/host/lib21/include/host_key2.h index 7c48dcaf..b219ae63 100644 --- a/host/lib21/include/host_key2.h +++ b/host/lib21/include/host_key2.h @@ -21,6 +21,34 @@ struct vb2_private_key { struct vb2_guid guid; /* Key GUID */ }; +/* Convert between enums and human-readable form. Terminated with {0, 0}. */ +struct vb2_text_vs_enum { + const char *name; + unsigned int num; +}; + +/** + * @param table Table to search + * @param num Enum value to search for + * @return pointer to table entry or NULL if no match + */ +const struct vb2_text_vs_enum *vb2_lookup_by_num( + const struct vb2_text_vs_enum *table, + const unsigned int num); + +/** + * @param table Table to search + * @param name String value to search for + * @return pointer to table entry or NULL if no match + */ +const struct vb2_text_vs_enum *vb2_lookup_by_name( + const struct vb2_text_vs_enum *table, + const char *name); + +extern struct vb2_text_vs_enum vb2_text_vs_algorithm[]; +extern struct vb2_text_vs_enum vb2_text_vs_sig[]; +extern struct vb2_text_vs_enum vb2_text_vs_hash[]; + /** * Free a private key. * @@ -97,6 +125,27 @@ int vb2_private_key_hash(const struct vb2_private_key **key_ptr, enum vb2_hash_algorithm hash_alg); /** + * Allocate a public key buffer of sufficient size for the signature algorithm. + * + * This only initializes the sig_alg field and the guid field to an empty + * guid. It does not set any of the other fields in *key_ptr. + * + * @param key_ptr Destination for newly allocated key; this must be + * freed with vb2_public_key_free(). + * @param sig_alg Signature algorithm for key. + * @return VB2_SUCCESS, or non-zero error code if error. + */ +int vb2_public_key_alloc(struct vb2_public_key **key_ptr, + enum vb2_signature_algorithm sig_alg); + +/** + * Return the packed data for a key allocated with vb2_public_key_alloc(). + * + * The packed data is in the same buffer, following the key struct and GUID. + */ +uint8_t *vb2_public_key_packed_data(struct vb2_public_key *key); + +/** * Free a public key allocated by one of the functions below. * * Note that this should ONLY be called for public keys allocated via one @@ -165,4 +214,22 @@ int vb2_public_key_hash(struct vb2_public_key *key, enum vb2_hash_algorithm hash_alg); +/** + * Return the signature algorithm implied by the bit length of an RSA key + * + * @param rsa RSA key + * @return vb2 signature algorithm + */ +enum vb2_signature_algorithm vb2_rsa_sig_alg(struct rsa_st *rsa); + +/** + * Write a public key to the vb2_packed_key format. + * + * @param key Key to write + * @param filename File to write key data to. + * @return VB2_SUCCESS, or non-zero error code if error. + */ +int vb2_public_key_write(const struct vb2_public_key *key, + const char *filename); + #endif /* VBOOT_REFERENCE_HOST_KEY2_H_ */ diff --git a/host/lib21/include/host_misc2.h b/host/lib21/include/host_misc2.h new file mode 100644 index 00000000..5d1679be --- /dev/null +++ b/host/lib21/include/host_misc2.h @@ -0,0 +1,36 @@ +/* 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. + */ + +#ifndef VBOOT_REFERENCE_HOST_MISC2_H_ +#define VBOOT_REFERENCE_HOST_MISC2_H_ + +#include <stdint.h> +#include <stdio.h> + +#include "2guid.h" + +/* Length of string representation, including trailing '\0' */ +#define VB2_GUID_MIN_STRLEN 37 + +/** + * Convert string to struct vb2_guid. + * + * @param str Example: "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" + * @param guid Destination for binary representation + * @return VB2_SUCCESS, or non-zero if error. + */ +int vb2_str_to_guid(const char *str, struct vb2_guid *guid); + +/** + * Convert struct vb2_guid to string. + * + * @param guid Binary representation + * @param str Buffer for result "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" + * @return VB2_SUCCESS, or non-zero if error. + */ +int vb2_guid_to_str(const struct vb2_guid *guid, + char *buf, unsigned int buflen); + +#endif /* VBOOT_REFERENCE_HOST_MISC2_H_ */ diff --git a/tests/futility/run_test_scripts.sh b/tests/futility/run_test_scripts.sh index f6bbe885..0f654d89 100755 --- a/tests/futility/run_test_scripts.sh +++ b/tests/futility/run_test_scripts.sh @@ -40,16 +40,17 @@ export OUTDIR # These are the scripts to run. Binaries are invoked directly by the Makefile. TESTS=" -${SCRIPTDIR}/test_main.sh +${SCRIPTDIR}/test_create.sh ${SCRIPTDIR}/test_dump_fmap.sh -${SCRIPTDIR}/test_load_fmap.sh ${SCRIPTDIR}/test_gbb_utility.sh +${SCRIPTDIR}/test_load_fmap.sh +${SCRIPTDIR}/test_main.sh ${SCRIPTDIR}/test_show_kernel.sh ${SCRIPTDIR}/test_show_vs_verify.sh -${SCRIPTDIR}/test_sign_keyblocks.sh -${SCRIPTDIR}/test_sign_fw_main.sh ${SCRIPTDIR}/test_sign_firmware.sh +${SCRIPTDIR}/test_sign_fw_main.sh ${SCRIPTDIR}/test_sign_kernel.sh +${SCRIPTDIR}/test_sign_keyblocks.sh " # Get ready... diff --git a/tests/futility/test_create.sh b/tests/futility/test_create.sh new file mode 100755 index 00000000..e1d8d334 --- /dev/null +++ b/tests/futility/test_create.sh @@ -0,0 +1,39 @@ +#!/bin/bash -eux +# 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. + +me=${0##*/} +TMP="$me.tmp" + +# Work in scratch directory +cd "$OUTDIR" + +# Current vb1 keys, including original .pem files. +TESTKEYS=${SRCDIR}/tests/testkeys + +# Demonstrate that we can recreate the same vb1 keys without the .keyb files +for sig in rsa1024 rsa2048 rsa4096 rsa8192; do + for hash in sha1 sha256 sha512; do + ${FUTILITY} --vb1 create --hash_alg "${hash}" \ + "${TESTKEYS}/key_${sig}.pem" "${TMP}_key_${sig}.${hash}" + cmp "${TESTKEYS}/key_${sig}.${hash}.vbprivk" \ + "${TMP}_key_${sig}.${hash}.vbprivk" + cmp "${TESTKEYS}/key_${sig}.${hash}.vbpubk" \ + "${TMP}_key_${sig}.${hash}.vbpubk" + done +done + + +# Demonstrate that we can create some vb21 keypairs. This doesn't prove +# prove anything until we've used them to sign some stuff, though. +for sig in rsa1024 rsa2048 rsa4096 rsa8192; do + for hash in sha1 sha256 sha512; do + ${FUTILITY} --vb21 create --hash_alg "${hash}" \ + "${TESTKEYS}/key_${sig}.pem" "${TMP}_key_${sig}.${hash}" + done +done + +# cleanup +rm -rf ${TMP}* +exit 0 diff --git a/utility/dumpRSAPublicKey.c b/utility/dumpRSAPublicKey.c index 113e9a0b..e97fa027 100644 --- a/utility/dumpRSAPublicKey.c +++ b/utility/dumpRSAPublicKey.c @@ -8,11 +8,10 @@ * /tools/DumpPublicKey.java). Uses the OpenSSL X509 and BIGNUM library. */ -#include <stdint.h> -#include <openssl/bn.h> -#include <openssl/evp.h> +#define OPENSSL_NO_SHA #include <openssl/pem.h> -#include <openssl/x509.h> + +#include <stdint.h> #include <string.h> #include <unistd.h> |