Define and use AftlSlotVerifyResult enum

Define a new enum for the return value of aftl_slot_verify. This allows
us to be more specific on the type of error encountered. Add an unit
test to catch the invalid signature case.

Test: atest --host libavb_host_unittest:AvbAftlVerifyTest
Bug: 153298013
Change-Id: I855b53ed444ec3b946078f29811638e69e32bb11
diff --git a/libavb_aftl/avb_aftl_verify.c b/libavb_aftl/avb_aftl_verify.c
index d1efdf9..b35e417 100644
--- a/libavb_aftl/avb_aftl_verify.c
+++ b/libavb_aftl/avb_aftl_verify.c
@@ -35,11 +35,11 @@
 /* Read the vbmeta partition, after the AvbVBMetaImageHeader structure, to find
  * the AftlImage.
  */
-static AvbSlotVerifyResult avb_aftl_find_aftl_image(AvbOps* ops,
-                                                    const char* part_name,
-                                                    size_t vbmeta_size,
-                                                    uint8_t* out_image_buf,
-                                                    size_t* out_image_size) {
+static AftlSlotVerifyResult avb_aftl_find_aftl_image(AvbOps* ops,
+                                                     const char* part_name,
+                                                     size_t vbmeta_size,
+                                                     uint8_t* out_image_buf,
+                                                     size_t* out_image_size) {
   AvbIOResult io_ret;
 
   avb_assert(vbmeta_size <= AVB_AFTL_MAX_AFTL_IMAGE_SIZE);
@@ -49,22 +49,28 @@
                                     AVB_AFTL_MAX_AFTL_IMAGE_SIZE - vbmeta_size,
                                     out_image_buf,
                                     out_image_size);
-
-  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
-    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-  } else if (io_ret != AVB_IO_RESULT_OK) {
-    avb_errorv(part_name, ": Error loading AftlImage from partition.\n", NULL);
-    return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+  switch (io_ret) {
+    case AVB_IO_RESULT_OK:
+      break;
+    case AVB_IO_RESULT_ERROR_OOM:
+      return AFTL_SLOT_VERIFY_RESULT_ERROR_OOM;
+    case AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION:
+    case AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION:
+      return AFTL_SLOT_VERIFY_RESULT_ERROR_IMAGE_NOT_FOUND;
+    default:
+      avb_errorv(
+          part_name, ": Error loading AftlImage from partition.\n", NULL);
+      return AFTL_SLOT_VERIFY_RESULT_ERROR_IO;
   }
 
   if (*out_image_size < 4 || (out_image_buf[0] != 'A') ||
       (out_image_buf[1] != 'F') || (out_image_buf[2] != 'T') ||
       (out_image_buf[3] != 'L')) {
     avb_errorv(part_name, ": Unexpected AftlImage magic.\n", NULL);
-    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    return AFTL_SLOT_VERIFY_RESULT_ERROR_IMAGE_NOT_FOUND;
   }
 
-  return AVB_SLOT_VERIFY_RESULT_OK;
+  return AFTL_SLOT_VERIFY_RESULT_OK;
 }
 
 /* Performs the three validation steps for an AFTL image:
@@ -72,20 +78,20 @@
    2. Ensure the root hash of the Merkle tree matches that in the image.
    3. Verify the signature using the transparency log public key.
 */
-static AvbSlotVerifyResult avb_aftl_verify_image(uint8_t* cur_vbmeta_data,
-                                                 size_t cur_vbmeta_size,
-                                                 uint8_t* aftl_blob,
-                                                 size_t aftl_size,
-                                                 uint8_t* key_bytes,
-                                                 size_t key_num_bytes) {
+static AftlSlotVerifyResult avb_aftl_verify_image(uint8_t* cur_vbmeta_data,
+                                                  size_t cur_vbmeta_size,
+                                                  uint8_t* aftl_blob,
+                                                  size_t aftl_size,
+                                                  uint8_t* key_bytes,
+                                                  size_t key_num_bytes) {
   size_t i;
   AftlImage* image;
-  AvbSlotVerifyResult result = AVB_SLOT_VERIFY_RESULT_OK;
+  AftlSlotVerifyResult result = AFTL_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
 
   /* Attempt to parse the AftlImage pointed to by aftl_blob. */
   image = parse_aftl_image(aftl_blob, aftl_size);
   if (!image) {
-    return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+    return AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_IMAGE;
   }
 
   /* Now that a valid AftlImage has been parsed, attempt to verify
@@ -96,7 +102,7 @@
     if (!avb_aftl_verify_vbmeta_hash(
             cur_vbmeta_data, cur_vbmeta_size, image->entries[i])) {
       avb_error("AFTL vbmeta hash verification failed.\n");
-      result = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+      result = AFTL_SLOT_VERIFY_RESULT_ERROR_VBMETA_HASH_MISMATCH;
       break;
     }
     /* 2. Ensure that the root hash of the Merkle tree representing
@@ -104,7 +110,7 @@
        AftlIcpEntry. */
     if (!avb_aftl_verify_icp_root_hash(image->entries[i])) {
       avb_error("AFTL root hash verification failed.\n");
-      result = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+      result = AFTL_SLOT_VERIFY_RESULT_ERROR_TREE_HASH_MISMATCH;
       break;
     }
     /* 3. Verify the signature using the transparency log public
@@ -112,65 +118,65 @@
     if (!avb_aftl_verify_entry_signature(
             key_bytes, key_num_bytes, image->entries[i])) {
       avb_error("AFTL signature verification failed on entry.\n");
-      result = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+      result = AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_PROOF_SIGNATURE;
       break;
     }
+    result = AFTL_SLOT_VERIFY_RESULT_OK;
   }
   free_aftl_image(image);
   return result;
 }
 
-AvbSlotVerifyResult aftl_slot_verify(AvbOps* ops,
-                                     AvbSlotVerifyData* asv_data,
-                                     uint8_t* key_bytes,
-                                     size_t key_size) {
+AftlSlotVerifyResult aftl_slot_verify(AvbOps* ops,
+                                      AvbSlotVerifyData* slot_verify_data,
+                                      uint8_t* key_bytes,
+                                      size_t key_size) {
   size_t i;
   size_t aftl_image_size;
   size_t vbmeta_size;
   uint8_t* current_aftl_blob;
   char part_name[AVB_PART_NAME_MAX_SIZE];
   char* pname;
-  AvbSlotVerifyResult ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+  AftlSlotVerifyResult ret = AFTL_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
 
-  avb_assert(asv_data != NULL);
+  avb_assert(slot_verify_data != NULL);
   avb_assert(key_bytes != NULL);
   avb_assert(key_size == AVB_AFTL_PUB_KEY_SIZE);
-  if (asv_data->vbmeta_images == NULL) {
-    return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+  if (slot_verify_data->vbmeta_images == NULL) {
+    return AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
   }
 
   current_aftl_blob = avb_malloc(AVB_AFTL_MAX_AFTL_IMAGE_SIZE);
   if (current_aftl_blob == NULL) {
-    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    return AFTL_SLOT_VERIFY_RESULT_ERROR_OOM;
   }
 
   /* Walk through each vbmeta blob in the AvbSlotVerifyData struct. */
-  for (i = 0; i < asv_data->num_vbmeta_images; i++) {
+  for (i = 0; i < slot_verify_data->num_vbmeta_images; i++) {
     /* Rebuild partition name, appending the suffix */
-    pname = asv_data->vbmeta_images[i].partition_name;
+    pname = slot_verify_data->vbmeta_images[i].partition_name;
     if (!avb_str_concat(part_name,
                         sizeof part_name,
                         (const char*)pname,
                         avb_strlen(pname),
-                        asv_data->ab_suffix,
-                        avb_strlen(asv_data->ab_suffix))) {
+                        slot_verify_data->ab_suffix,
+                        avb_strlen(slot_verify_data->ab_suffix))) {
       avb_error("Partition name and suffix does not fit.\n");
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+      ret = AFTL_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
       break;
     }
 
     /* Use the partition info to find the AftlImage */
-    vbmeta_size = asv_data->vbmeta_images[i].vbmeta_size;
+    vbmeta_size = slot_verify_data->vbmeta_images[i].vbmeta_size;
     ret = avb_aftl_find_aftl_image(
         ops, part_name, vbmeta_size, current_aftl_blob, &aftl_image_size);
-    if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
-      avb_error("Unable to find the AftlImage.\n");
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    if (ret != AFTL_SLOT_VERIFY_RESULT_OK) {
+      avb_errorv(part_name, ": Unable to find the AftlImage.\n", NULL);
       break;
     }
 
     /* Validate the AFTL image in the vbmeta image. */
-    ret = avb_aftl_verify_image(asv_data->vbmeta_images[i].vbmeta_data,
+    ret = avb_aftl_verify_image(slot_verify_data->vbmeta_images[i].vbmeta_data,
                                 vbmeta_size,
                                 current_aftl_blob,
                                 aftl_image_size,
diff --git a/libavb_aftl/avb_aftl_verify.h b/libavb_aftl/avb_aftl_verify.h
index fe7ef41..7c6799f 100644
--- a/libavb_aftl/avb_aftl_verify.h
+++ b/libavb_aftl/avb_aftl_verify.h
@@ -34,24 +34,71 @@
 extern "C" {
 #endif
 
-/* The entry point of AFTL validation. Takes an AvbSlotVerifyData
-   struct generated by a prior call to avb_slot_verify and the transparency
-   log's public key and validates the inclusion proof. It does this by
-   performing the following three validation steps for an AFTL
-   descriptor:
-   1. Ensure the vbmeta image hash matches that in the descriptor.
-   2. Ensure the root hash of the Merkle tree matches that in the descriptor.
-   3. Verify the signature using the transparency log public key.
-   It returns AVB_SLOT_VERIFY_RESULT_OK upon success,
-   AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA if at least one VBMeta did not
-   have an AftlDescriptor and AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION
-   otherwise.
-*/
+typedef enum {
+  // When the verification succeeded.
+  AFTL_SLOT_VERIFY_RESULT_OK,
 
-AvbSlotVerifyResult aftl_slot_verify(AvbOps* ops,
-                                     AvbSlotVerifyData* asv_data,
-                                     uint8_t* key_bytes,
-                                     size_t key_size);
+  // If at some point during the verification, a memory allocation failed. This
+  // could be the case when handling a large number of log keys or inclusion
+  // proofs.
+  AFTL_SLOT_VERIFY_RESULT_ERROR_OOM,
+
+  // If at some point during the verification, we were not able to access some
+  // devices. This can be the case when reading the AftlImage from the
+  // partition.
+  AFTL_SLOT_VERIFY_RESULT_ERROR_IO,
+
+  // The VBMeta hash in the inclusion proof is not matching the VBMeta image
+  // hash.
+  AFTL_SLOT_VERIFY_RESULT_ERROR_VBMETA_HASH_MISMATCH,
+
+  // The root hash of the reconstructed tree do not match the value contained in
+  // the inclusion proof.
+  AFTL_SLOT_VERIFY_RESULT_ERROR_TREE_HASH_MISMATCH,
+
+  // The inclusion proof signature cannot be verified by the given key.
+  AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_PROOF_SIGNATURE,
+
+  // A generic error occurred during the verification.
+  AFTL_SLOT_VERIFY_RESULT_ERROR_VERIFICATION,
+
+  // At least one of the VBMetas did not have an AftlImage attached.
+  AFTL_SLOT_VERIFY_RESULT_ERROR_IMAGE_NOT_FOUND,
+
+  // Some content of one of the AFTLImages was found corrupted.
+  AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_IMAGE,
+
+  // Returned if the caller passed invalid parameters, for example if the prior
+  // call to avb_slot_verify failed.
+  AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT
+
+} AftlSlotVerifyResult;
+
+/* The entry point of AFTL validation. It uses the AvbSlotVerifyData structure,
+ * |slot_verify_data|, generated by a prior call to the avb_slot_verify
+ * function, and a transparency log key to validate the inclusion proof(s)
+ * attached to each VBMeta images.
+ *
+ * The caller is responsible for ensuring that the previous call to
+ * avb_slot_verify succeeded. If |slot_verify_data| is incomplete or NULL,
+ * AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT will be returned.
+ *
+ * The AftlImage structure is located after the VBMetaImage structure. Uses
+ * |ops| to read the partition where the VBMeta was loaded from.
+ *
+ * For each inclusion proof found, the following three validation steps are
+ * performed:
+ *   1. Match the VBMeta image hash with the hash in the tree leaf.
+ *   2. Match the root hash of the Merkle tree with the hash in the proof.
+ *   3. Verify the signature of the proof using the transparency log public key.
+ * See the definition of AftlSlotVerifyResult for all the possible return
+ * values.
+ */
+
+AftlSlotVerifyResult aftl_slot_verify(AvbOps* ops,
+                                      AvbSlotVerifyData* slot_verify_data,
+                                      uint8_t* key_bytes,
+                                      size_t key_size);
 #ifdef __cplusplus
 }
 #endif
diff --git a/test/avb_aftl_verify_unittest.cc b/test/avb_aftl_verify_unittest.cc
index 8eedcd4..9f64294 100644
--- a/test/avb_aftl_verify_unittest.cc
+++ b/test/avb_aftl_verify_unittest.cc
@@ -125,23 +125,32 @@
 };
 
 TEST_F(AvbAftlVerifyTest, Basic) {
-  AvbSlotVerifyResult result =
+  AftlSlotVerifyResult result =
       aftl_slot_verify(ops_.avb_ops(), asv_test_data_, key_bytes_, key_size_);
-  EXPECT_EQ(result, AVB_SLOT_VERIFY_RESULT_OK);
+  EXPECT_EQ(result, AFTL_SLOT_VERIFY_RESULT_OK);
 }
 
-TEST_F(AvbAftlVerifyTest, MissingAFTLDescriptor) {
+TEST_F(AvbAftlVerifyTest, PartitionError) {
   asv_test_data_->vbmeta_images[0].partition_name = (char*)"do-no-exist";
-  AvbSlotVerifyResult result =
+  AftlSlotVerifyResult result =
       aftl_slot_verify(ops_.avb_ops(), asv_test_data_, key_bytes_, key_size_);
-  EXPECT_EQ(result, AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA);
+  EXPECT_EQ(result, AFTL_SLOT_VERIFY_RESULT_ERROR_IMAGE_NOT_FOUND);
 }
 
-TEST_F(AvbAftlVerifyTest, NonMatchingVBMeta) {
+TEST_F(AvbAftlVerifyTest, MismatchingVBMeta) {
   asv_test_data_->vbmeta_images[0].vbmeta_data[0] = 'X';
-  AvbSlotVerifyResult result =
+  AftlSlotVerifyResult result =
       aftl_slot_verify(ops_.avb_ops(), asv_test_data_, key_bytes_, key_size_);
-  EXPECT_EQ(result, AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION);
+  EXPECT_EQ(result, AFTL_SLOT_VERIFY_RESULT_ERROR_VBMETA_HASH_MISMATCH);
+}
+
+TEST_F(AvbAftlVerifyTest, InvalidKey) {
+  // Corrupt the key in order to fail the verification: complement the last
+  // byte, we keep the key header valid.
+  key_bytes_[key_size_ - 1] = ~key_bytes_[key_size_ - 1];
+  AftlSlotVerifyResult result =
+      aftl_slot_verify(ops_.avb_ops(), asv_test_data_, key_bytes_, key_size_);
+  EXPECT_EQ(result, AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_PROOF_SIGNATURE);
 }
 
 } /* namespace avb */