[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 {