summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2015-02-03 17:07:15 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-03-10 20:44:43 +0000
commit4e4c19602edf3834b50d66d3ba067e895aca6fa0 (patch)
tree11b9408e5e6a9c3e3fde95c21656e67562bb3faf
parent26af0da4f7e0fd5cc9410011ca05ff6539bbf42d (diff)
downloadvboot-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--Makefile5
-rw-r--r--firmware/2lib/include/2misc.h2
-rw-r--r--firmware/2lib/include/2return_codes.h8
-rw-r--r--futility/cmd_create.c402
-rw-r--r--host/lib/host_key.c3
-rw-r--r--host/lib/host_signature.c2
-rw-r--r--host/lib/include/util_misc.h25
-rw-r--r--host/lib/signature_digest.c4
-rw-r--r--host/lib/util_misc.c133
-rw-r--r--host/lib21/host_key.c116
-rw-r--r--host/lib21/host_misc.c69
-rw-r--r--host/lib21/host_signature.c2
-rw-r--r--host/lib21/include/host_key2.h67
-rw-r--r--host/lib21/include/host_misc2.h36
-rwxr-xr-xtests/futility/run_test_scripts.sh9
-rwxr-xr-xtests/futility/test_create.sh39
-rw-r--r--utility/dumpRSAPublicKey.c7
17 files changed, 879 insertions, 50 deletions
diff --git a/Makefile b/Makefile
index 5b72f47f..1a712e1a 100644
--- a/Makefile
+++ b/Makefile
@@ -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>