futility: add support for .pem with public key

Add support for PEM file containing a RSA Public key in futility "show"
and "create" commands.

When "futility create" is given a PEM file with only a RSA public key,
generate the proper .vbpubk2 rather than failing.

BRANCH=smaug
BUG=none
TEST=make runtests
and run manually
futility show tests/testkeys/key_rsa4096.pub.pem
futility show tests/testkeys/key_rsa4096.pem

Reviewed-on: https://chromium-review.googlesource.com/306683
Commit-Ready: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
(cherry picked from commit 27c90708e63f5f042aa52de6bc1b89c282ca8c4a)

Change-Id: Idd82d88bd024e7af74046782dd374b9d8400bfb4
Reviewed-on: https://chromium-review.googlesource.com/307433
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
diff --git a/futility/cmd_create.c b/futility/cmd_create.c
index 6da59a7..143ea9a 100644
--- a/futility/cmd_create.c
+++ b/futility/cmd_create.c
@@ -169,6 +169,7 @@
 	uint32_t keyb_size;
 	enum vb2_signature_algorithm sig_alg;
 	uint8_t *pubkey_buf = 0;
+	int has_priv = 0;
 
 	FILE *fp;
 	int ret = 1;
@@ -180,12 +181,21 @@
 	}
 
 	rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
-	fclose(fp);
 
 	if (!rsa_key) {
+		/* Check if the PEM contains only a public key */
+		fseek(fp, 0, SEEK_SET);
+		rsa_key = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
+	}
+	fclose(fp);
+	if (!rsa_key) {
 		fprintf(stderr, "Unable to read RSA key from %s\n", infile);
 		goto done;
 	}
+	/* Public keys doesn't have the private exponent */
+	has_priv = !!rsa_key->d;
+	if (!has_priv)
+		fprintf(stderr, "%s has a public key only.\n", infile);
 
 	sig_alg = vb2_rsa_sig_alg(rsa_key);
 	if (sig_alg == VB2_SIG_INVALID) {
@@ -193,19 +203,21 @@
 		goto done;
 	}
 
-	/* Create the private key */
-	privkey = calloc(1, sizeof(*privkey));
-	if (!privkey) {
-		fprintf(stderr, "Unable to allocate the private key\n");
-		goto done;
-	}
+	if (has_priv) {
+		/* 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;
-	if (opt_desc && vb2_private_key_set_desc(privkey, opt_desc)) {
-		fprintf(stderr, "Unable to set the private key description\n");
-		goto done;
+		privkey->rsa_private_key = rsa_key;
+		privkey->sig_alg = sig_alg;
+		privkey->hash_alg = opt_hash_alg;
+		if (opt_desc && vb2_private_key_set_desc(privkey, opt_desc)) {
+			fprintf(stderr, "Unable to set the private key description\n");
+			goto done;
+		}
 	}
 
 	/* Create the public key */
@@ -248,16 +260,18 @@
 		free(digest);
 	}
 
-	privkey->id = opt_id;
 	memcpy((struct vb2_id *)pubkey->id, &opt_id, sizeof(opt_id));
 
 	/* Write them out */
-	strcpy(outext, ".vbprik2");
-	if (vb2_private_key_write(privkey, outfile)) {
-		fprintf(stderr, "unable to write private key\n");
-		goto done;
+	if (has_priv) {
+		privkey->id = opt_id;
+		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);
 	}
-	fprintf(stderr, "wrote %s\n", outfile);
 
 	strcpy(outext, ".vbpubk2");
 	if (vb2_public_key_write(pubkey, outfile)) {
diff --git a/futility/vb2_helper.c b/futility/vb2_helper.c
index 4ee0a28..51a7837 100644
--- a/futility/vb2_helper.c
+++ b/futility/vb2_helper.c
@@ -184,6 +184,11 @@
 
 	rsa_key = PEM_read_bio_RSAPrivateKey(bp, NULL, NULL, NULL);
 	if (!rsa_key) {
+		if (BIO_reset(bp) < 0)
+			return 0;
+		rsa_key = PEM_read_bio_RSA_PUBKEY(bp, NULL, NULL, NULL);
+	}
+	if (!rsa_key) {
 		BIO_free(bp);
 		return 0;
 	}
@@ -212,13 +217,15 @@
 	uint32_t keyb_len;
 	int i, bits;
 
-	printf("Private Key file:      %s\n", name);
-
 	/* We're called only after ft_recognize_pem, so this should work. */
 	rsa_key = rsa_from_buffer(buf, len);
 	if (!rsa_key)
 		DIE;
 
+	/* Use to presence of the private exponent to decide if it's public */
+	printf("%s Key file:      %s\n", rsa_key->d ? "Private" : "Public",
+					 name);
+
 	bits = BN_num_bits(rsa_key->n);
 	printf("  Key length:          %d\n", bits);
 
diff --git a/tests/futility/test_create.sh b/tests/futility/test_create.sh
index 662b2dd..55c648c 100755
--- a/tests/futility/test_create.sh
+++ b/tests/futility/test_create.sh
@@ -52,6 +52,18 @@
   [ "$pem_sum" = "$uniq_sums" ]
 done
 
+# Demonstrate that we can create some vb21 public key from PEM containing
+# only the pubkeypairs and verify it's the same as the one generated from
+# the private key.
+for sig in rsa1024 rsa2048 rsa4096 rsa8192; do
+  for hash in sha1 sha256 sha512; do
+    ${FUTILITY} --vb21 create --hash_alg "${hash}" \
+      "${TESTKEYS}/key_${sig}.pub.pem" "${TMP}_key_${sig}.pubonly.${hash}"
+    cmp "${TMP}_key_${sig}.pubonly.${hash}.vbpubk2" \
+      "${TMP}_key_${sig}.${hash}.vbpubk2"
+  done
+done
+
 # cleanup
 rm -rf ${TMP}*
 exit 0
diff --git a/tests/futility/test_file_types.sh b/tests/futility/test_file_types.sh
index 470d631..4b7a9fb 100755
--- a/tests/futility/test_file_types.sh
+++ b/tests/futility/test_file_types.sh
@@ -43,6 +43,7 @@
 test_case "pubkey21"        "tests/futility/data/sample.vbpubk2"
 test_case "prikey21"        "tests/futility/data/sample.vbprik2"
 test_case "pem"             "tests/testkeys/key_rsa2048.pem"
+test_case "pem"             "tests/testkeys/key_rsa8192.pub.pem"
 
 # Expect failure here.
 fail_case "/Sir/Not/Appearing/In/This/Film"
diff --git a/tests/testkeys/key_rsa1024.pub.pem b/tests/testkeys/key_rsa1024.pub.pem
new file mode 100644
index 0000000..85646f4
--- /dev/null
+++ b/tests/testkeys/key_rsa1024.pub.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdYBOJIJvGX9vC4E5XD1jb9zJ9
+9FzR4G0n8HNyWy5ZKyy/hi80ibXpy6QdWcm4wqTvmVjU+20sP4AgzKC65fKyFvvA
+HUiD4yGr1qWtg4YFUcBbUiXOCQ66W3AC4g2Ju9C16AzMpBk043bQsUQvxILEumQq
+Q1VS33uM7Kq8dWpL6QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/tests/testkeys/key_rsa2048.pub.pem b/tests/testkeys/key_rsa2048.pub.pem
new file mode 100644
index 0000000..c45a80c
--- /dev/null
+++ b/tests/testkeys/key_rsa2048.pub.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlF3KFZo9kW2YYaUJTce1
+1BYEq9nTsP8E0+e+Tw5JUJ1M45s8UJSzOgKQeSLR3399TSq0WSqsSa8QFvBACv7L
+mM7CgkgI4mMj2Zl96XJVyZP2+2c6hgvwRuB3eG6J5K2sW5YwiIz+5SQcPolp5F6r
+17tMZzgidgIxrN32VvUZt5VplILTU4h7J9ZNaipoG3JdFloxqOqOda5Lksf8Cics
+hGJqSiqgpvdx2zVNX9cjKNpqzEvZrNKPLKDteFzohPqrM7n2g+nKgAbwWLa9zELC
+RG8h1qfbLOXOjrgVgy/g8t5ixWOrRBrbY5nQCv7eeKEetH8ru3ZMNtOgeWzOup0Q
+1QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/tests/testkeys/key_rsa4096.pub.pem b/tests/testkeys/key_rsa4096.pub.pem
new file mode 100644
index 0000000..a36d44e
--- /dev/null
+++ b/tests/testkeys/key_rsa4096.pub.pem
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAm5v71oqFynujT4FVq5lK
+aYxpmKfXdeBNKDmLzgu7fXLUKaEqTGEDsseE5qyaaP+dmTnQKfne7G31zgf46//Y
+El+u5Gt/S4oAgYyvs3rjymzD5kVOLEAzgrIXAwyhDFARRzAFWos43hypunHGvu4f
+DBAzZ3zGVulhjgAzD/gNjToVYCP7bj6kTaDx1u9siCKdYN09vGwSUt9WuV+yort7
+kns/B8ArVxt3bFSjsAxuWel/dJyLwCMQ9XAxdgWpg3RBUsK/KgekQybPLrhLYJn1
+AeOApwzJ4HoJSqU/1jCEaGrKA/KtCRXiurZz6lBi7sElsigjBvEZH0iCmmRgH3Oi
+/cbpHIs1C6YHvCCbO90ntwgtDf0+2WJtFtbGt5Do3CXri0tcsXBWqISSK3VzzjHH
+691BVwLuoBvF1XICMEjmq9aJ+MdbEe4E+GU8TV9NnRnuYyOUoxeisyXiArUUI9+1
+qL6pIgulTlY2Ch51QZY5n2aYY97PtosNotbSylMrLvWXGiiQWxux12eOnB3c/3wN
+YWey8Km4cmOhEOYz7hLz2r1uIoC/SzM5wLnnTEQmaiUDNV9R3Gj3E3xkpTq3UNSS
+PsV7k8lInMtWqzps6aTvBw1k6i6CUvWbEZqmt/0bimQHOEdg3OrJjQpwTKSp4ouS
+yVu0IphDwy1yjKCfNWKRzrUCAwEAAQ==
+-----END PUBLIC KEY-----
diff --git a/tests/testkeys/key_rsa8192.pub.pem b/tests/testkeys/key_rsa8192.pub.pem
new file mode 100644
index 0000000..616c955
--- /dev/null
+++ b/tests/testkeys/key_rsa8192.pub.pem
@@ -0,0 +1,25 @@
+-----BEGIN PUBLIC KEY-----
+MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEA19BF/7el6ZXitFI71Glw
+4/bjNiOWxRLO+zU2IKIJZYjatWWBOcB7pfnQQtoF6gtItnBT0/6NaCzucKd+TFb8
+Bz7pxK/ljSSJAFSOSf91b25mTcc4ohLkIvETX5g++jlaRuKDX5mnxUgEHUtMGvu5
+xMOSQi7UNM9Yxx26yRkIKaPNk2C5IeoXvKh9Xa4NS5hJSJnm3bG3oURAtugFS9ah
+AAoM0+e21FrlAxCUiVzF/BJip7xN3COjo8noDda3RMDz12Udrwgrme+4xu0FOx1x
+LGOIOgLzbP9HG56uGOMv58ExIem2YgTsMgHIbzqqnpymcnBes6DHhnRRK0jplIxF
+pjqZqzSizYXUIY7vauiYXiZZnr5fpbrT+Y2b4Vza1PlPm68GkOgu39Cq4c+tjJJ3
+R/db9k+DWFfqfOLN4qqOO3szwnTtWQomj/4McZdpmapY5Fnofu01Rw9cg+V1OO/D
+j1Q1BF7CqKmCEBICKT5Mk/oaTwZS4bWcgIJjPdBn9Im/bAulc9eGNg6Fo1Y+iVCj
+DgLbQ+9SmFj6/JKlJRlAn21FburA+RaSirwF1IZ8eqMgUY6/Viu4eJNwbvWkeyaz
+02Ss7hs6VRDhUSzJbg4OMIE4qjxNJcbuyAIbtQs39PtH/iIY/2kPaNFjKU+ah4CI
+3kVIlgb/kgfqnUSQS4AHIubsZVpszUVE2A38R22OEGUenCLsljjWkv3snosY8gyJ
+s9YumTGk2K/OiIAf0X8kXsv5Isq2ky+3T7PJYqQ67WjENCxEOi7AkDlJls7omAhT
+8umGJPfF3R9izWYy5UJ4pNL2Cs8wv1vQcf9nDS5cpgqa6/w9sRo1bJjRlopi53Ph
+6D+7CicoQP5M0tH2p3dD8qP6RZNqtWP0eOZ0el0DMFh5hjYXHDnxZaEL5fcpVX8F
+drDltgFbUUYRDlJDr0j6/TXOdnAwyc6scAbwcWm9dKwJJQogRxXuvh11Yt8j8U3t
+X95isL1QUIube3o8I7vXiMFRVRUg5NVM6sTgVsXRpybTecRsmDD76RerJEhi5vwf
+mJz5qzLTSH9JgCY9EuI38WzmeGZ6F8kfRHEs9Gh5/XvOB7UsqZXaU5NTT5LBiiFX
+IZoYFxnFpLl/crGc7oCP7JwsY0hW5CgK0829tY3aWLpY+a34Z2/wtc6dgKKA40Lj
+7y3pKwwMFaPo+widtjVkCk3n9Rq0X6ubHi+uml42NYBRgvfoaZ4FbCTpRWV6kcGp
+M76O3bqV63iS9wdOFK4IO0zrJ/QI73yHz9LU61BmQGVTze2+tSifYFersjvmoJrg
+x703iljO9Xi1NfwoQpv0XwrdIgfHOSD1S3d1Id/R2tOBF7meHmCfki18KHOzk/2u
+JQIDAQAB
+-----END PUBLIC KEY-----