futility: add support for .pem with public key
authorVincent Palatin <vpalatin@chromium.org>
Fri, 16 Oct 2015 00:54:34 +0000 (17:54 -0700)
committerchrome-bot <chrome-bot@chromium.org>
Sat, 17 Oct 2015 16:53:07 +0000 (09:53 -0700)
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

Change-Id: I707ceca54c80ba21f53869ad86c86fa23b31e665
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>
futility/cmd_create.c
futility/vb2_helper.c
tests/futility/test_create.sh
tests/futility/test_file_types.sh
tests/testkeys/key_rsa1024.pub.pem [new file with mode: 0644]
tests/testkeys/key_rsa2048.pub.pem [new file with mode: 0644]
tests/testkeys/key_rsa4096.pub.pem [new file with mode: 0644]
tests/testkeys/key_rsa8192.pub.pem [new file with mode: 0644]

index 6da59a7..143ea9a 100644 (file)
@@ -169,6 +169,7 @@ static int vb2_make_keypair()
        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 @@ static int vb2_make_keypair()
        }
 
        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 @@ static int vb2_make_keypair()
                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 @@ static int vb2_make_keypair()
                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)) {
index 4ee0a28..51a7837 100644 (file)
@@ -184,6 +184,11 @@ static RSA *rsa_from_buffer(uint8_t *buf, uint32_t len)
 
        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 @@ int ft_show_pem(const char *name, uint8_t *buf, uint32_t len, void *data)
        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);
 
index 662b2dd..55c648c 100755 (executable)
@@ -52,6 +52,18 @@ for sig in rsa1024 rsa2048 rsa4096 rsa8192; do
   [ "$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
index 470d631..4b7a9fb 100755 (executable)
@@ -43,6 +43,7 @@ test_case "prikey"        "tests/devkeys/root_key.vbprivk"
 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 (file)
index 0000000..85646f4
--- /dev/null
@@ -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 (file)
index 0000000..c45a80c
--- /dev/null
@@ -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 (file)
index 0000000..a36d44e
--- /dev/null
@@ -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 (file)
index 0000000..616c955
--- /dev/null
@@ -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-----