Merge changes from topic "idsig"
* changes:
idsig: Include the APK digest
apkverify: Add function to pick v4 apk digest
apkverify: Rank based on v4 preferences
diff --git a/libs/apkverify/Android.bp b/libs/apkverify/Android.bp
index 2445dd5..d45a77f 100644
--- a/libs/apkverify/Android.bp
+++ b/libs/apkverify/Android.bp
@@ -24,6 +24,7 @@
defaults: ["libapkverify.defaults"],
// TODO(b/204562227): move to host_supported to the defaults to include tests
host_supported: true,
+ apex_available: ["com.android.virt"],
}
rust_test {
diff --git a/libs/apkverify/src/lib.rs b/libs/apkverify/src/lib.rs
index 290a79a..c5aa9e5 100644
--- a/libs/apkverify/src/lib.rs
+++ b/libs/apkverify/src/lib.rs
@@ -24,4 +24,4 @@
mod ziputil;
// TODO(jooyung) fallback to v2 when v3 not found
-pub use v3::{get_public_key_der, verify};
+pub use v3::{get_public_key_der, pick_v4_apk_digest, verify};
diff --git a/libs/apkverify/src/sigutil.rs b/libs/apkverify/src/sigutil.rs
index 009154f..2b2f9da 100644
--- a/libs/apkverify/src/sigutil.rs
+++ b/libs/apkverify/src/sigutil.rs
@@ -282,6 +282,7 @@
}
}
+/// Rank the signature algorithm according to the preferences of the v4 signing scheme.
pub fn rank_signature_algorithm(algo: u32) -> Result<u32> {
rank_content_digest_algorithm(to_content_digest_algorithm(algo)?)
}
diff --git a/libs/apkverify/src/v3.rs b/libs/apkverify/src/v3.rs
index 16530be..96ca7bc 100644
--- a/libs/apkverify/src/v3.rs
+++ b/libs/apkverify/src/v3.rs
@@ -128,16 +128,43 @@
})
}
+/// Gets the APK digest.
+pub fn pick_v4_apk_digest<R: Read + Seek>(apk: R) -> Result<(u32, Box<[u8]>)> {
+ let mut sections = ApkSections::new(apk)?;
+ let mut block = sections.find_signature(APK_SIGNATURE_SCHEME_V3_BLOCK_ID)?;
+ let signers = block.read::<Signers>()?;
+ if signers.len() != 1 {
+ bail!("should only have one signer");
+ }
+ signers[0].pick_v4_apk_digest()
+}
+
impl Signer {
- fn verify<R: Read + Seek>(&self, sections: &mut ApkSections<R>) -> Result<Box<[u8]>> {
- // 1. Choose the strongest supported signature algorithm ID from signatures. The strength
- // ordering is up to each implementation/platform version.
- let strongest: &Signature = self
+ /// Select the signature that uses the strongest algorithm according to the preferences of the
+ /// v4 signing scheme.
+ fn strongest_signature(&self) -> Result<&Signature> {
+ Ok(self
.signatures
.iter()
.filter(|sig| is_supported_signature_algorithm(sig.signature_algorithm_id))
.max_by_key(|sig| rank_signature_algorithm(sig.signature_algorithm_id).unwrap())
- .ok_or_else(|| anyhow!("No supported signatures found"))?;
+ .ok_or_else(|| anyhow!("No supported signatures found"))?)
+ }
+
+ fn pick_v4_apk_digest(&self) -> Result<(u32, Box<[u8]>)> {
+ let strongest = self.strongest_signature()?;
+ 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)
+ .ok_or_else(|| anyhow!("Digest not found"))?;
+ Ok((digest.signature_algorithm_id, digest.digest.as_ref().to_vec().into_boxed_slice()))
+ }
+
+ fn verify<R: Read + Seek>(&self, sections: &mut ApkSections<R>) -> Result<Box<[u8]>> {
+ // 1. Choose the strongest supported signature algorithm ID from signatures.
+ let strongest = self.strongest_signature()?;
// 2. Verify the corresponding signature from signatures against signed data using public key.
// (It is now safe to parse signed data.)
diff --git a/libs/idsig/Android.bp b/libs/idsig/Android.bp
index 2e9c663..25eeae4 100644
--- a/libs/idsig/Android.bp
+++ b/libs/idsig/Android.bp
@@ -10,6 +10,7 @@
prefer_rlib: true,
rustlibs: [
"libanyhow",
+ "libapkverify",
"libbyteorder",
"libnum_traits",
"libopenssl",
diff --git a/libs/idsig/src/apksigv4.rs b/libs/idsig/src/apksigv4.rs
index 3004ed1..db8a8c6 100644
--- a/libs/idsig/src/apksigv4.rs
+++ b/libs/idsig/src/apksigv4.rs
@@ -15,6 +15,7 @@
*/
use anyhow::{anyhow, bail, Context, Result};
+use apkverify::pick_v4_apk_digest;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive, ToPrimitive};
@@ -190,9 +191,12 @@
ret.hashing_info.raw_root_hash = hash_tree.root_hash.into_boxed_slice();
ret.hashing_info.log2_blocksize = log2(block_size);
- // TODO(jiyong): fill the signing_info struct by reading the APK file. The information,
- // especially `apk_digest` is needed to check if `V4Signature` is outdated, in which case
- // it needs to be created from the updated APK.
+ apk.seek(SeekFrom::Start(start))?;
+ let (signature_algorithm_id, apk_digest) = pick_v4_apk_digest(apk)?;
+ ret.signing_info.signature_algorithm_id =
+ SignatureAlgorithmId::from(signature_algorithm_id)?;
+ ret.signing_info.apk_digest = apk_digest;
+ // TODO(jiyong): add a signature to the signing_info struct
Ok(ret)
}