New tools to help debug vboot failures.

This adds some tools to help us figure out why a particular kernel isn't
booting. Often we suspect it's because it was signed with the wrong keys, or
has flags restricting its use to certain boot modes. This change adds some
tools to extract and display all the keys from the BIOS, and try them on the
various kernels. We also display the sha1sum of all the keys we find, to
make comparing them easier.

Change-Id: I38e447bf95cb6c3a0b87aa949611bb135f2f94b4

BUG=chromeos-partner:888
TEST=manual

To test, obtain a root shell, and run dev_debug_vboot. You should see lots
of useful information go by.

Review URL: http://codereview.chromium.org/3303018
diff --git a/utility/vbutil_firmware.c b/utility/vbutil_firmware.c
index d58e2a3..9cff272 100644
--- a/utility/vbutil_firmware.c
+++ b/utility/vbutil_firmware.c
@@ -60,6 +60,9 @@
        "For '--verify <file>', required OPTIONS are:\n"
        "  --signpubkey <file>         Signing public key in .vbpubk format\n"
        "  --fv <file>                 Firmware volume to verify\n"
+       "\n"
+       "For '--verify <file>', optional OPTIONS are:\n"
+       "  --kernelkey <file>          Write the kernel subkey to this file\n"
        "");
   return 1;
 }
@@ -157,14 +160,14 @@
   return 0;
 }
 
-
 static int Verify(const char* infile, const char* signpubkey,
-                  const char* fv_file) {
+                  const char* fv_file, const char* kernelkey_file) {
 
   VbKeyBlockHeader* key_block;
   VbFirmwarePreambleHeader* preamble;
   VbPublicKey* data_key;
   VbPublicKey* sign_key;
+  VbPublicKey* kernel_subkey;
   RSAPublicKey* rsa;
   uint8_t* blob;
   uint64_t blob_size;
@@ -210,11 +213,15 @@
   printf("Key block:\n");
   data_key = &key_block->data_key;
   printf("  Size:                %" PRIu64 "\n", key_block->key_block_size);
+  printf("  Flags:               %" PRIu64 " (ignored)\n",
+         key_block->key_block_flags);
   printf("  Data key algorithm:  %" PRIu64 " %s\n", data_key->algorithm,
          (data_key->algorithm < kNumAlgorithms ?
           algo_strings[data_key->algorithm] : "(invalid)"));
   printf("  Data key version:    %" PRIu64 "\n", data_key->key_version);
-  printf("  Flags:               %" PRIu64 "\n", key_block->key_block_flags);
+  printf("  Data key sha1sum:    ");
+  PrintPubKeySha1Sum(data_key);
+  printf("\n");
 
   rsa = PublicKeyToRSA(&key_block->data_key);
   if (!rsa) {
@@ -235,12 +242,16 @@
   printf("  Header version:        %" PRIu32 ".%" PRIu32"\n",
          preamble->header_version_major, preamble->header_version_minor);
   printf("  Firmware version:      %" PRIu64 "\n", preamble->firmware_version);
+  kernel_subkey = &preamble->kernel_subkey;
   printf("  Kernel key algorithm:  %" PRIu64 " %s\n",
-         preamble->kernel_subkey.algorithm,
-         (preamble->kernel_subkey.algorithm < kNumAlgorithms ?
-          algo_strings[preamble->kernel_subkey.algorithm] : "(invalid)"));
+         kernel_subkey->algorithm,
+         (kernel_subkey->algorithm < kNumAlgorithms ?
+          algo_strings[kernel_subkey->algorithm] : "(invalid)"));
   printf("  Kernel key version:    %" PRIu64 "\n",
-         preamble->kernel_subkey.key_version);
+         kernel_subkey->key_version);
+  printf("  Kernel key sha1sum:    ");
+  PrintPubKeySha1Sum(kernel_subkey);
+  printf("\n");
   printf("  Firmware body size:    %" PRIu64 "\n",
          preamble->body_signature.data_size);
 
@@ -252,6 +263,15 @@
     return 1;
   }
   printf("Body verification succeeded.\n");
+
+  if (kernelkey_file) {
+    if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
+      fprintf(stderr,
+              "vbutil_firmware: unable to write kernel subkey\n");
+      return 1;
+    }
+  }
+
   return 0;
 }
 
@@ -322,7 +342,7 @@
       return Vblock(filename, key_block_file, signprivate, version, fv_file,
                     kernelkey_file);
     case OPT_MODE_VERIFY:
-      return Verify(filename, signpubkey, fv_file);
+      return Verify(filename, signpubkey, fv_file, kernelkey_file);
     default:
       printf("Must specify a mode.\n");
       return PrintHelp();