Merge "[apkverify] Skip DSA SHA256 during apk verification"
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 80ef687..5272834 100644
--- a/libs/apkverify/src/v3.rs
+++ b/libs/apkverify/src/v3.rs
@@ -65,6 +65,14 @@
fn sdk_range(&self) -> Range<u32> {
self.min_sdk..self.max_sdk
}
+
+ fn find_digest_by_algorithm(&self, algorithm_id: SignatureAlgorithmID) -> Result<&Digest> {
+ Ok(self
+ .digests
+ .iter()
+ .find(|&dig| dig.signature_algorithm_id == Some(algorithm_id))
+ .context(format!("Digest not found for algorithm: {:?}", algorithm_id))?)
+ }
}
#[derive(Debug)]
@@ -86,52 +94,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 {
@@ -147,17 +145,13 @@
}
fn pick_v4_apk_digest(&self) -> Result<(SignatureAlgorithmID, Box<[u8]>)> {
- let strongest = self.strongest_signature()?;
+ let strongest_algorithm_id = self
+ .strongest_signature()?
+ .signature_algorithm_id
+ .context("Strongest signature should contain a valid signature algorithm.")?;
let signed_data: SignedData = self.signed_data.slice(..).read()?;
- let digest = signed_data
- .digests
- .iter()
- .find(|&dig| dig.signature_algorithm_id == strongest.signature_algorithm_id)
- .context("Digest not found")?;
- Ok((
- digest.signature_algorithm_id.context("Unsupported algorithm")?,
- digest.digest.as_ref().to_vec().into_boxed_slice(),
- ))
+ let digest = signed_data.find_digest_by_algorithm(strongest_algorithm_id)?;
+ Ok((strongest_algorithm_id, digest.digest.as_ref().to_vec().into_boxed_slice()))
}
/// Verifies the strongest signature from signatures against signed data using public key.
@@ -200,13 +194,10 @@
// 5. Compute the digest of APK contents using the same digest algorithm as the digest
// algorithm used by the signature algorithm.
- let digest = verified_signed_data
- .digests
- .iter()
- .find(|&dig| dig.signature_algorithm_id == strongest.signature_algorithm_id)
- .unwrap(); // ok to unwrap since we check if two lists are the same above
- let computed = sections
- .compute_digest(digest.signature_algorithm_id.context("Unsupported algorithm")?)?;
+ let digest = verified_signed_data.find_digest_by_algorithm(
+ strongest.signature_algorithm_id.context("Unsupported algorithm")?,
+ )?;
+ let computed = sections.compute_digest(digest.signature_algorithm_id.unwrap())?;
// 6. Verify that the computed digest is identical to the corresponding digest from digests.
ensure!(