libavb: Add new routine to calculate a digest of all vbmeta images.

This is similar to the androidboot.vbmeta.{digest, hash_alg, size}
properties set on the kernel commandline. The intent is to make this
data easily available to the bootloader without having it parse the
commandline.

Bug: None
Test: Update unit tests and all unit tests pass.
Change-Id: I4134f1a4116468bf063db2f15b8b67edd26918c2
diff --git a/examples/things/avb_atx_slot_verify.c b/examples/things/avb_atx_slot_verify.c
index 3129d2e..0de6d2e 100644
--- a/examples/things/avb_atx_slot_verify.c
+++ b/examples/things/avb_atx_slot_verify.c
@@ -133,7 +133,6 @@
   const char* partitions_without_oem[] = {"boot", NULL};
   const char* partitions_with_oem[] = {"boot", "oem_bootloader", NULL};
   AvbSlotVerifyResult result = AVB_SLOT_VERIFY_RESULT_OK;
-  AvbSHA256Ctx ctx;
   size_t i = 0;
   AvbAtxOpsWithContext ops_with_context;
 
@@ -155,13 +154,8 @@
   }
 
   /* Compute the Android Things Verified Boot Hash (VBH) extension. */
-  avb_sha256_init(&ctx);
-  for (i = 0; i < (*verify_data)->num_vbmeta_images; i++) {
-    avb_sha256_update(&ctx,
-                      (*verify_data)->vbmeta_images[i].vbmeta_data,
-                      (*verify_data)->vbmeta_images[i].vbmeta_size);
-  }
-  avb_memcpy(vbh_extension, avb_sha256_final(&ctx), AVB_SHA256_DIGEST_SIZE);
+  avb_slot_verify_data_calculate_vbmeta_digest(
+      *verify_data, AVB_DIGEST_TYPE_SHA256, vbh_extension);
 
   /* Increase rollback index values to match the verified slot. */
   if (slot_state == AVB_ATX_SLOT_MARKED_SUCCESSFUL) {
diff --git a/libavb/avb_cmdline.c b/libavb/avb_cmdline.c
index 426f909..3f4b99a 100644
--- a/libavb/avb_cmdline.c
+++ b/libavb/avb_cmdline.c
@@ -269,13 +269,11 @@
     case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
     case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
     case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
-      AvbSHA256Ctx ctx;
       size_t n, total_size = 0;
-      avb_sha256_init(&ctx);
+      uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE];
+      avb_slot_verify_data_calculate_vbmeta_digest(
+          slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest);
       for (n = 0; n < slot_data->num_vbmeta_images; n++) {
-        avb_sha256_update(&ctx,
-                          slot_data->vbmeta_images[n].vbmeta_data,
-                          slot_data->vbmeta_images[n].vbmeta_size);
         total_size += slot_data->vbmeta_images[n].vbmeta_size;
       }
       if (!cmdline_append_option(
@@ -284,7 +282,7 @@
               slot_data, "androidboot.vbmeta.size", total_size) ||
           !cmdline_append_hex(slot_data,
                               "androidboot.vbmeta.digest",
-                              avb_sha256_final(&ctx),
+                              vbmeta_digest,
                               AVB_SHA256_DIGEST_SIZE)) {
         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
         goto out;
@@ -294,13 +292,11 @@
     case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
     case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
     case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
-      AvbSHA512Ctx ctx;
       size_t n, total_size = 0;
-      avb_sha512_init(&ctx);
+      uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE];
+      avb_slot_verify_data_calculate_vbmeta_digest(
+          slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest);
       for (n = 0; n < slot_data->num_vbmeta_images; n++) {
-        avb_sha512_update(&ctx,
-                          slot_data->vbmeta_images[n].vbmeta_data,
-                          slot_data->vbmeta_images[n].vbmeta_size);
         total_size += slot_data->vbmeta_images[n].vbmeta_size;
       }
       if (!cmdline_append_option(
@@ -309,7 +305,7 @@
               slot_data, "androidboot.vbmeta.size", total_size) ||
           !cmdline_append_hex(slot_data,
                               "androidboot.vbmeta.digest",
-                              avb_sha512_final(&ctx),
+                              vbmeta_digest,
                               AVB_SHA512_DIGEST_SIZE)) {
         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
         goto out;
diff --git a/libavb/avb_crypto.h b/libavb/avb_crypto.h
index 0903baa..30c1e4b 100644
--- a/libavb/avb_crypto.h
+++ b/libavb/avb_crypto.h
@@ -53,6 +53,12 @@
 /* Size in bytes of a SHA-512 digest. */
 #define AVB_SHA512_DIGEST_SIZE 64
 
+/* Possible digest types supported by libavb routines. */
+typedef enum {
+  AVB_DIGEST_TYPE_SHA256,
+  AVB_DIGEST_TYPE_SHA512,
+} AvbDigestType;
+
 /* Algorithms that can be used in the vbmeta image for
  * verification. An algorithm consists of a hash type and a signature
  * type.
diff --git a/libavb/avb_slot_verify.c b/libavb/avb_slot_verify.c
index 3e6b04c..64e2666 100644
--- a/libavb/avb_slot_verify.c
+++ b/libavb/avb_slot_verify.c
@@ -1344,3 +1344,42 @@
 
   return ret;
 }
+
+void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data,
+                                                  AvbDigestType digest_type,
+                                                  uint8_t* out_digest) {
+  bool ret = false;
+  size_t n;
+
+  switch (digest_type) {
+    case AVB_DIGEST_TYPE_SHA256: {
+      AvbSHA256Ctx ctx;
+      avb_sha256_init(&ctx);
+      for (n = 0; n < data->num_vbmeta_images; n++) {
+        avb_sha256_update(&ctx,
+                          data->vbmeta_images[n].vbmeta_data,
+                          data->vbmeta_images[n].vbmeta_size);
+      }
+      avb_memcpy(out_digest, avb_sha256_final(&ctx), AVB_SHA256_DIGEST_SIZE);
+      ret = true;
+    } break;
+
+    case AVB_DIGEST_TYPE_SHA512: {
+      AvbSHA512Ctx ctx;
+      avb_sha512_init(&ctx);
+      for (n = 0; n < data->num_vbmeta_images; n++) {
+        avb_sha512_update(&ctx,
+                          data->vbmeta_images[n].vbmeta_data,
+                          data->vbmeta_images[n].vbmeta_size);
+      }
+      avb_memcpy(out_digest, avb_sha512_final(&ctx), AVB_SHA512_DIGEST_SIZE);
+      ret = true;
+    } break;
+
+      /* Do not add a 'default:' case here because of -Wswitch. */
+  }
+
+  if (!ret) {
+    avb_fatal("Unknown digest type");
+  }
+}
diff --git a/libavb/avb_slot_verify.h b/libavb/avb_slot_verify.h
index 78e7dcc..375db3d 100644
--- a/libavb/avb_slot_verify.h
+++ b/libavb/avb_slot_verify.h
@@ -260,6 +260,15 @@
   uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
 } AvbSlotVerifyData;
 
+/* Calculates a digest of all vbmeta images in |data| using
+ * the digest indicated by |digest_type|. Stores the result
+ * in |out_digest| which must be large enough to hold a digest
+ * of the requested type.
+ */
+void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data,
+                                                  AvbDigestType digest_type,
+                                                  uint8_t* out_digest);
+
 /* Frees a |AvbSlotVerifyData| including all data it points to. */
 void avb_slot_verify_data_free(AvbSlotVerifyData* data);
 
diff --git a/test/avb_slot_verify_unittest.cc b/test/avb_slot_verify_unittest.cc
index 823257e..87c7a1c 100644
--- a/test/avb_slot_verify_unittest.cc
+++ b/test/avb_slot_verify_unittest.cc
@@ -81,6 +81,11 @@
       "androidboot.vbmeta.invalidate_on_error=yes "
       "androidboot.veritymode=enforcing",
       std::string(slot_data->cmdline));
+  uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE];
+  avb_slot_verify_data_calculate_vbmeta_digest(
+      slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest);
+  EXPECT_EQ("4161a7e655eabe16c3fe714de5d43736e7c0a190cf08d36c946d2509ce071e4d",
+            mem_to_hexstring(vbmeta_digest, AVB_SHA256_DIGEST_SIZE));
   avb_slot_verify_data_free(slot_data);
 }
 
@@ -115,6 +120,13 @@
       "androidboot.vbmeta.invalidate_on_error=yes "
       "androidboot.veritymode=enforcing",
       std::string(slot_data->cmdline));
+  uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE];
+  avb_slot_verify_data_calculate_vbmeta_digest(
+      slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest);
+  EXPECT_EQ(
+      "cb913d2f1a884f4e04c1db5bb181f3133fd16ac02fb367a20ef0776c0b07b3656ad1f081"
+      "e01932cf70f38b8960877470b448f1588dff022808387cc52fa77e77",
+      mem_to_hexstring(vbmeta_digest, AVB_SHA512_DIGEST_SIZE));
   avb_slot_verify_data_free(slot_data);
 }