apkverify: verify cert/public key match
Bug: 190343842
Test: atest libapkverify.integration_test
Change-Id: If7da64ea6ff3f5fc25d204cbcf30d22122ee45c7
diff --git a/apkverify/src/v3.rs b/apkverify/src/v3.rs
index 0ef035c..5ec3d07 100644
--- a/apkverify/src/v3.rs
+++ b/apkverify/src/v3.rs
@@ -19,12 +19,13 @@
// TODO(jooyung) remove this
#![allow(dead_code)]
-use anyhow::{anyhow, bail, Result};
+use anyhow::{anyhow, bail, Context, Result};
use bytes::Bytes;
use std::fs::File;
use std::io::{Read, Seek};
use std::ops::Range;
use std::path::Path;
+use x509_parser::x509;
use crate::bytes_ext::{BytesExt, LengthPrefixed, ReadFromBytes};
use crate::sigutil::*;
@@ -127,7 +128,8 @@
// 2. Verify the corresponding signature from signatures against signed data using public key.
// (It is now safe to parse signed data.)
- verify_signed_data(&self.signed_data, strongest, &self.public_key)?;
+ let (_, key_info) = x509::SubjectPublicKeyInfo::from_der(self.public_key.as_ref())?;
+ verify_signed_data(&self.signed_data, strongest, &key_info)?;
// It is now safe to parse signed data.
let signed_data: SignedData = self.signed_data.slice(..).read()?;
@@ -161,13 +163,20 @@
// 6. Verify that the computed digest is identical to the corresponding digest from digests.
if computed != digest.digest.as_ref() {
bail!(
- "digest mismatch: computed={:?} vs expected={:?}",
+ "Digest mismatch: computed={:?} vs expected={:?}",
to_hex_string(&computed),
to_hex_string(&digest.digest),
);
}
- // TODO(jooyung) 7. Verify that SubjectPublicKeyInfo of the first certificate of certificates is identical to public key.
+ // 7. Verify that SubjectPublicKeyInfo of the first certificate of certificates is identical
+ // to public key.
+ let cert = signed_data.certificates.first().context("No certificates listed")?;
+ let (_, cert) = x509_parser::parse_x509_certificate(cert.as_ref())?;
+ if cert.tbs_certificate.subject_pki != key_info {
+ bail!("Public key mismatch between certificate and signature record");
+ }
+
// TODO(jooyung) 8. If the proof-of-rotation attribute exists for the signer verify that the struct is valid and this signer is the last certificate in the list.
Ok(())
}
@@ -176,10 +185,9 @@
fn verify_signed_data(
data: &Bytes,
signature: &Signature,
- public_key: &SubjectPublicKeyInfo,
+ key_info: &x509::SubjectPublicKeyInfo,
) -> Result<()> {
use ring::signature;
- let (_, key_info) = x509_parser::x509::SubjectPublicKeyInfo::from_der(public_key.as_ref())?;
let verification_alg: &dyn signature::VerificationAlgorithm =
match signature.signature_algorithm_id {
SIGNATURE_RSA_PSS_WITH_SHA256 => &signature::RSA_PSS_2048_8192_SHA256,
@@ -202,7 +210,7 @@
}
_ => bail!("Unsupported signature algorithm: {:#x}", signature.signature_algorithm_id),
};
- let key = signature::UnparsedPublicKey::new(verification_alg, key_info.subject_public_key.data);
+ let key = signature::UnparsedPublicKey::new(verification_alg, &key_info.subject_public_key);
key.verify(data.as_ref(), signature.signature.as_ref())?;
Ok(())
}
diff --git a/apkverify/tests/apkverify_test.rs b/apkverify/tests/apkverify_test.rs
index b40c435..cad5ef2 100644
--- a/apkverify/tests/apkverify_test.rs
+++ b/apkverify/tests/apkverify_test.rs
@@ -40,5 +40,12 @@
fn test_verify_v3_digest_mismatch() {
let res = verify("tests/data/v3-only-with-rsa-pkcs1-sha512-8192-digest-mismatch.apk");
assert!(res.is_err());
- assert_contains!(res.err().unwrap().to_string(), "digest mismatch");
+ assert_contains!(res.err().unwrap().to_string(), "Digest mismatch");
+}
+
+#[test]
+fn test_verify_v3_cert_and_publick_key_mismatch() {
+ let res = verify("tests/data/v3-only-cert-and-public-key-mismatch.apk");
+ assert!(res.is_err());
+ assert_contains!(res.err().unwrap().to_string(), "Public key mismatch");
}
diff --git a/apkverify/tests/data/README.md b/apkverify/tests/data/README.md
index 581a522..953ecdb 100644
--- a/apkverify/tests/data/README.md
+++ b/apkverify/tests/data/README.md
@@ -12,4 +12,5 @@
```
Some test APKs are copied from tools/apksig/src/test/resources/com/android/apksig/.
+- v3-only-cert-and-public-key-mismatch.apk
- v3-only-with-rsa-pkcs1-sha512-8192-digest-mismatch.apk
diff --git a/apkverify/tests/data/v3-only-cert-and-public-key-mismatch.apk b/apkverify/tests/data/v3-only-cert-and-public-key-mismatch.apk
new file mode 100644
index 0000000..2291e7e
--- /dev/null
+++ b/apkverify/tests/data/v3-only-cert-and-public-key-mismatch.apk
Binary files differ