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>
diff --git a/Makefile b/Makefile
index 5b72f47..1a712e1 100644
--- a/Makefile
+++ b/Makefile
@@ -605,6 +605,7 @@
 
 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_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 928ada3..1eccde9 100644
--- a/firmware/2lib/include/2misc.h
+++ b/firmware/2lib/include/2misc.h
@@ -27,7 +27,7 @@
  * 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 7b54f6d..384879d 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -490,6 +490,12 @@
 	/* 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 @@
 	/* 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 0000000..f4eb3f2
--- /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 c9efa85..067a188 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 1ea6bc4..43766cf 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 788929d..0a6ed4c 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 81c666e..c9e721e 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 09df8ee..d2c21f5 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 5123b85..4acba9c 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 @@
 	}
 }
 
-/**
- * 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 @@
 
 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 @@
 	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 555867a..c55996e 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 @@
 	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 553aa38..11785c7 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 7c48dca..b219ae6 100644
--- a/host/lib21/include/host_key2.h
+++ b/host/lib21/include/host_key2.h
@@ -21,6 +21,34 @@
 	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 @@
 			 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 @@
 			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 0000000..5d1679b
--- /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 f6bbe88..0f654d8 100755
--- a/tests/futility/run_test_scripts.sh
+++ b/tests/futility/run_test_scripts.sh
@@ -40,16 +40,17 @@
 
 # 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 0000000..e1d8d33
--- /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 113e9a0..e97fa02 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>