[apkverify] Refactor signer and apk section extraction for reuse

Bug: 247689066
Test: libapkverify.integration_test
Change-Id: I6ae2d89a72d588a05fe5c19bc2afd4d7c8c2e39b
diff --git a/libs/apkverify/src/bytes_ext.rs b/libs/apkverify/src/bytes_ext.rs
index 8fb36ee..8a7badf 100644
--- a/libs/apkverify/src/bytes_ext.rs
+++ b/libs/apkverify/src/bytes_ext.rs
@@ -32,6 +32,13 @@
     }
 }
 
+impl<T> LengthPrefixed<T> {
+    /// Consumes the `LengthPrefixed` instance, returning the wrapped value.
+    pub fn into_inner(self) -> T {
+        self.inner
+    }
+}
+
 pub trait BytesExt {
     fn read<T: ReadFromBytes>(&mut self) -> Result<T>;
 }
diff --git a/libs/apkverify/src/lib.rs b/libs/apkverify/src/lib.rs
index 084a910..92de9b0 100644
--- a/libs/apkverify/src/lib.rs
+++ b/libs/apkverify/src/lib.rs
@@ -24,6 +24,5 @@
 mod v3;
 mod ziputil;
 
-// TODO(b/197052981) fallback to v2 when v3 not found
 pub use algorithms::SignatureAlgorithmID;
 pub use v3::{get_public_key_der, pick_v4_apk_digest, verify};
diff --git a/libs/apkverify/src/v3.rs b/libs/apkverify/src/v3.rs
index 05694ff..f58cb1f 100644
--- a/libs/apkverify/src/v3.rs
+++ b/libs/apkverify/src/v3.rs
@@ -86,52 +86,42 @@
 /// associated with the signer in DER format.
 pub fn verify<P: AsRef<Path>>(apk_path: P) -> Result<Box<[u8]>> {
     let apk = File::open(apk_path.as_ref())?;
-    let mut sections = ApkSections::new(apk)?;
-    find_signer_and_then(&mut sections, |(signer, sections)| signer.verify(sections))
-}
-
-/// Finds the supported signer and execute a function on it.
-fn find_signer_and_then<R, U, F>(sections: &mut ApkSections<R>, f: F) -> Result<U>
-where
-    R: Read + Seek,
-    F: FnOnce((&Signer, &mut ApkSections<R>)) -> Result<U>,
-{
-    let mut block = sections.find_signature(APK_SIGNATURE_SCHEME_V3_BLOCK_ID)?;
-    // parse v3 scheme block
-    let signers = block.read::<Signers>()?;
-
-    // find supported by platform
-    let supported = signers.iter().filter(|s| s.sdk_range().contains(&SDK_INT)).collect::<Vec<_>>();
-
-    // there should be exactly one
-    ensure!(
-        supported.len() == 1,
-        "APK Signature Scheme V3 only supports one signer: {} signers found.",
-        supported.len()
-    );
-
-    // Call the supplied function
-    f((supported[0], sections))
+    let (signer, mut sections) = extract_signer_and_apk_sections(apk)?;
+    signer.verify(&mut sections)
 }
 
 /// Gets the public key (in DER format) that was used to sign the given APK/APEX file
 pub fn get_public_key_der<P: AsRef<Path>>(apk_path: P) -> Result<Box<[u8]>> {
     let apk = File::open(apk_path.as_ref())?;
-    let mut sections = ApkSections::new(apk)?;
-    find_signer_and_then(&mut sections, |(signer, _)| {
-        Ok(signer.public_key.public_key_to_der()?.into_boxed_slice())
-    })
+    let (signer, _) = extract_signer_and_apk_sections(apk)?;
+    Ok(signer.public_key.public_key_to_der()?.into_boxed_slice())
 }
 
 /// Gets the v4 [apk_digest].
 ///
 /// [apk_digest]: https://source.android.com/docs/security/apksigning/v4#apk-digest
 pub fn pick_v4_apk_digest<R: Read + Seek>(apk: R) -> Result<(SignatureAlgorithmID, Box<[u8]>)> {
+    let (signer, _) = extract_signer_and_apk_sections(apk)?;
+    signer.pick_v4_apk_digest()
+}
+
+fn extract_signer_and_apk_sections<R: Read + Seek>(apk: R) -> Result<(Signer, ApkSections<R>)> {
     let mut sections = ApkSections::new(apk)?;
-    let mut block = sections.find_signature(APK_SIGNATURE_SCHEME_V3_BLOCK_ID)?;
-    let signers = block.read::<Signers>()?;
-    ensure!(signers.len() == 1, "should only have one signer");
-    signers[0].pick_v4_apk_digest()
+    let mut block = sections.find_signature(APK_SIGNATURE_SCHEME_V3_BLOCK_ID).context(
+        "Fallback to v2 when v3 block not found is not yet implemented. See b/197052981.",
+    )?;
+    let mut supported = block
+        .read::<Signers>()?
+        .into_inner()
+        .into_iter()
+        .filter(|s| s.sdk_range().contains(&SDK_INT))
+        .collect::<Vec<_>>();
+    ensure!(
+        supported.len() == 1,
+        "APK Signature Scheme V3 only supports one signer: {} signers found.",
+        supported.len()
+    );
+    Ok((supported.pop().unwrap().into_inner(), sections))
 }
 
 impl Signer {