[apkverify] Refactor verify_signed_data to use SignatureAlgorithmID

This CL refactor verify_signed_data to use SignatureAlgorithmID
enum instead of the raw integers. There's no behavior change in
this CL.

Bug: 246254355
Test: libapkverify.integration_test
Change-Id: I1296efb9a700d2fe3f6ec93f69cdc407a6882a0d
diff --git a/libs/apkverify/src/algorithms.rs b/libs/apkverify/src/algorithms.rs
index f15f0a4..ee9c869 100644
--- a/libs/apkverify/src/algorithms.rs
+++ b/libs/apkverify/src/algorithms.rs
@@ -16,9 +16,12 @@
 
 //! Algorithms used for APK Signature Scheme.
 
-use anyhow::{bail, Result};
+use anyhow::{bail, ensure, Result};
 use num_derive::FromPrimitive;
 use openssl::hash::MessageDigest;
+use openssl::pkey::{self, PKey};
+use openssl::rsa::Padding;
+use openssl::sign::Verifier;
 use std::cmp::Ordering;
 
 /// [Signature Algorithm IDs]: https://source.android.com/docs/security/apksigning/v2#signature-algorithm-ids
@@ -76,6 +79,77 @@
             }
         }
     }
+
+    pub(crate) fn new_verifier<'a>(
+        &self,
+        public_key: &'a PKey<pkey::Public>,
+    ) -> Result<Verifier<'a>> {
+        ensure!(
+            !matches!(
+                self,
+                SignatureAlgorithmID::EcdsaWithSha512
+                    | SignatureAlgorithmID::DsaWithSha256
+                    | SignatureAlgorithmID::VerityDsaWithSha256
+            ),
+            "TODO(b/197052981): Algorithm '{:#?}' is not implemented.",
+            self
+        );
+        ensure!(public_key.id() == self.pkey_id(), "Public key has the wrong ID");
+        let mut verifier = Verifier::new(self.new_message_digest(), public_key)?;
+        if public_key.id() == pkey::Id::RSA {
+            verifier.set_rsa_padding(self.rsa_padding())?;
+        }
+        Ok(verifier)
+    }
+
+    /// Returns the message digest corresponding to the signature algorithm
+    /// according to the spec [Signature Algorithm IDs].
+    fn new_message_digest(&self) -> MessageDigest {
+        match self {
+            SignatureAlgorithmID::RsaPssWithSha256
+            | SignatureAlgorithmID::RsaPkcs1V15WithSha256
+            | SignatureAlgorithmID::EcdsaWithSha256
+            | SignatureAlgorithmID::DsaWithSha256
+            | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
+            | SignatureAlgorithmID::VerityEcdsaWithSha256
+            | SignatureAlgorithmID::VerityDsaWithSha256 => MessageDigest::sha256(),
+            SignatureAlgorithmID::RsaPssWithSha512
+            | SignatureAlgorithmID::RsaPkcs1V15WithSha512
+            | SignatureAlgorithmID::EcdsaWithSha512 => MessageDigest::sha512(),
+        }
+    }
+
+    fn pkey_id(&self) -> pkey::Id {
+        match self {
+            SignatureAlgorithmID::RsaPssWithSha256
+            | SignatureAlgorithmID::RsaPssWithSha512
+            | SignatureAlgorithmID::RsaPkcs1V15WithSha256
+            | SignatureAlgorithmID::RsaPkcs1V15WithSha512
+            | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256 => pkey::Id::RSA,
+            SignatureAlgorithmID::EcdsaWithSha256
+            | SignatureAlgorithmID::EcdsaWithSha512
+            | SignatureAlgorithmID::VerityEcdsaWithSha256 => pkey::Id::EC,
+            SignatureAlgorithmID::DsaWithSha256 | SignatureAlgorithmID::VerityDsaWithSha256 => {
+                pkey::Id::DSA
+            }
+        }
+    }
+
+    fn rsa_padding(&self) -> Padding {
+        match self {
+            SignatureAlgorithmID::RsaPssWithSha256 | SignatureAlgorithmID::RsaPssWithSha512 => {
+                Padding::PKCS1_PSS
+            }
+            SignatureAlgorithmID::RsaPkcs1V15WithSha256
+            | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
+            | SignatureAlgorithmID::RsaPkcs1V15WithSha512 => Padding::PKCS1,
+            SignatureAlgorithmID::EcdsaWithSha256
+            | SignatureAlgorithmID::EcdsaWithSha512
+            | SignatureAlgorithmID::VerityEcdsaWithSha256
+            | SignatureAlgorithmID::DsaWithSha256
+            | SignatureAlgorithmID::VerityDsaWithSha256 => Padding::NONE,
+        }
+    }
 }
 
 /// The rank of the content digest algorithm in this enum is used to help pick
diff --git a/libs/apkverify/src/sigutil.rs b/libs/apkverify/src/sigutil.rs
index ea6d63a..98edf49 100644
--- a/libs/apkverify/src/sigutil.rs
+++ b/libs/apkverify/src/sigutil.rs
@@ -16,6 +16,10 @@
 
 //! Utilities for Signature Verification
 
+// TODO(b/246254355): Remove this once we migrate all the usages of
+// raw signature algorithm id to the enum.
+#![allow(dead_code)]
+
 use anyhow::{anyhow, ensure, Error, Result};
 use byteorder::{LittleEndian, ReadBytesExt};
 use bytes::{Buf, BufMut, Bytes, BytesMut};
diff --git a/libs/apkverify/src/v3.rs b/libs/apkverify/src/v3.rs
index c86696f..2f13837 100644
--- a/libs/apkverify/src/v3.rs
+++ b/libs/apkverify/src/v3.rs
@@ -21,10 +21,7 @@
 use anyhow::{anyhow, bail, ensure, Context, Result};
 use bytes::Bytes;
 use num_traits::FromPrimitive;
-use openssl::hash::MessageDigest;
 use openssl::pkey::{self, PKey};
-use openssl::rsa::Padding;
-use openssl::sign::Verifier;
 use openssl::x509::X509;
 use std::fs::File;
 use std::io::{Read, Seek};
@@ -223,39 +220,14 @@
     }
 }
 
-fn verify_signed_data(data: &Bytes, signature: &Signature, key: &PKey<pkey::Public>) -> Result<()> {
-    let (pkey_id, padding, digest) = match signature.signature_algorithm_id {
-        SIGNATURE_RSA_PSS_WITH_SHA256 => {
-            (pkey::Id::RSA, Padding::PKCS1_PSS, MessageDigest::sha256())
-        }
-        SIGNATURE_RSA_PSS_WITH_SHA512 => {
-            (pkey::Id::RSA, Padding::PKCS1_PSS, MessageDigest::sha512())
-        }
-        SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256 | SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 => {
-            (pkey::Id::RSA, Padding::PKCS1, MessageDigest::sha256())
-        }
-        SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512 => {
-            (pkey::Id::RSA, Padding::PKCS1, MessageDigest::sha512())
-        }
-        SIGNATURE_ECDSA_WITH_SHA256 | SIGNATURE_VERITY_ECDSA_WITH_SHA256 => {
-            (pkey::Id::EC, Padding::NONE, MessageDigest::sha256())
-        }
-        // TODO(b/190343842) not implemented signature algorithm
-        SIGNATURE_ECDSA_WITH_SHA512
-        | SIGNATURE_DSA_WITH_SHA256
-        | SIGNATURE_VERITY_DSA_WITH_SHA256 => {
-            bail!(
-                "TODO(b/190343842) not implemented signature algorithm: {:#x}",
-                signature.signature_algorithm_id
-            );
-        }
-        _ => bail!("Unsupported signature algorithm: {:#x}", signature.signature_algorithm_id),
-    };
-    ensure!(key.id() == pkey_id, "Public key has the wrong ID");
-    let mut verifier = Verifier::new(digest, key)?;
-    if pkey_id == pkey::Id::RSA {
-        verifier.set_rsa_padding(padding)?;
-    }
+fn verify_signed_data(
+    data: &Bytes,
+    signature: &Signature,
+    public_key: &PKey<pkey::Public>,
+) -> Result<()> {
+    let mut verifier = SignatureAlgorithmID::from_u32(signature.signature_algorithm_id)
+        .context("Unsupported algorithm")?
+        .new_verifier(public_key)?;
     verifier.update(data)?;
     let verified = verifier.verify(&signature.signature)?;
     ensure!(verified, "Signature is invalid ");
diff --git a/libs/apkverify/tests/apkverify_test.rs b/libs/apkverify/tests/apkverify_test.rs
index a674ad7..0b33208 100644
--- a/libs/apkverify/tests/apkverify_test.rs
+++ b/libs/apkverify/tests/apkverify_test.rs
@@ -43,10 +43,7 @@
     for key_name in KEY_NAMES_DSA.iter() {
         let res = verify(format!("tests/data/v3-only-with-dsa-sha256-{}.apk", key_name));
         assert!(res.is_err());
-        assert_contains(
-            &res.unwrap_err().to_string(),
-            "TODO(b/190343842) not implemented signature algorithm",
-        );
+        assert_contains(&res.unwrap_err().to_string(), "not implemented");
     }
 }
 
@@ -63,10 +60,7 @@
     for key_name in KEY_NAMES_ECDSA.iter() {
         let res = verify(format!("tests/data/v3-only-with-ecdsa-sha512-{}.apk", key_name));
         assert!(res.is_err());
-        assert_contains(
-            &res.unwrap_err().to_string(),
-            "TODO(b/190343842) not implemented signature algorithm",
-        );
+        assert_contains(&res.unwrap_err().to_string(), "not implemented");
     }
 }
 
@@ -101,8 +95,7 @@
         assert!(res.is_err());
         let error_msg = &res.unwrap_err().to_string();
         assert!(
-            error_msg.contains("Signature is invalid")
-                || error_msg.contains("TODO(b/190343842) not implemented signature algorithm")
+            error_msg.contains("Signature is invalid") || error_msg.contains("not implemented")
         );
     }
 }
@@ -118,10 +111,7 @@
         let res = verify(path);
         assert!(res.is_err());
         let error_msg = &res.unwrap_err().to_string();
-        assert!(
-            error_msg.contains("Digest mismatch")
-                || error_msg.contains("TODO(b/190343842) not implemented signature algorithm")
-        );
+        assert!(error_msg.contains("Digest mismatch") || error_msg.contains("not implemented"));
     }
 }