Merge "Revert "Verify that the VM-generated BCC is valid""
diff --git a/libs/apkverify/Android.bp b/libs/apkverify/Android.bp
index df1cac6..4c0e1f8 100644
--- a/libs/apkverify/Android.bp
+++ b/libs/apkverify/Android.bp
@@ -13,7 +13,7 @@
"libbyteorder",
"libbytes",
"liblog_rust",
- "libring",
+ "libopenssl",
"libx509_parser",
"libzip",
],
diff --git a/libs/apkverify/src/lib.rs b/libs/apkverify/src/lib.rs
index 71ea857..290a79a 100644
--- a/libs/apkverify/src/lib.rs
+++ b/libs/apkverify/src/lib.rs
@@ -23,17 +23,5 @@
mod v3;
mod ziputil;
-use anyhow::Result;
-use std::path::Path;
-
-/// Verifies APK/APEX signing with v2/v3 scheme. On success, the public key (in DER format) is
-/// returned.
-pub fn verify<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
- // TODO(jooyung) fallback to v2 when v3 not found
- v3::verify(path)
-}
-
-/// 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>>(path: P) -> Result<Box<[u8]>> {
- v3::get_public_key_der(path)
-}
+// TODO(jooyung) fallback to v2 when v3 not found
+pub use v3::{get_public_key_der, verify};
diff --git a/libs/apkverify/src/sigutil.rs b/libs/apkverify/src/sigutil.rs
index 23dd91e..009154f 100644
--- a/libs/apkverify/src/sigutil.rs
+++ b/libs/apkverify/src/sigutil.rs
@@ -19,7 +19,7 @@
use anyhow::{anyhow, bail, Result};
use byteorder::{LittleEndian, ReadBytesExt};
use bytes::{Buf, BufMut, Bytes, BytesMut};
-use ring::digest;
+use openssl::hash::{DigestBytes, Hasher, MessageDigest};
use std::cmp::min;
use std::io::{Cursor, Read, Seek, SeekFrom, Take};
@@ -107,12 +107,12 @@
let slice = &mut chunk[..(chunk_size as usize)];
data.read_exact(slice)?;
digests_of_chunks.put_slice(
- digester.digest(slice, CHUNK_HEADER_MID, chunk_size as u32).as_ref(),
+ digester.digest(slice, CHUNK_HEADER_MID, chunk_size as u32)?.as_ref(),
);
chunk_count += 1;
}
}
- Ok(digester.digest(&digests_of_chunks, CHUNK_HEADER_TOP, chunk_count).as_ref().into())
+ Ok(digester.digest(&digests_of_chunks, CHUNK_HEADER_TOP, chunk_count)?.as_ref().into())
}
fn zip_entries(&mut self) -> Result<Take<Box<dyn Read + '_>>> {
@@ -157,7 +157,7 @@
}
struct Digester {
- algorithm: &'static digest::Algorithm,
+ algorithm: MessageDigest,
}
const CHUNK_HEADER_TOP: &[u8] = &[0x5a];
@@ -167,8 +167,8 @@
fn new(signature_algorithm_id: u32) -> Result<Digester> {
let digest_algorithm_id = to_content_digest_algorithm(signature_algorithm_id)?;
let algorithm = match digest_algorithm_id {
- CONTENT_DIGEST_CHUNKED_SHA256 => &digest::SHA256,
- CONTENT_DIGEST_CHUNKED_SHA512 => &digest::SHA512,
+ CONTENT_DIGEST_CHUNKED_SHA256 => MessageDigest::sha256(),
+ CONTENT_DIGEST_CHUNKED_SHA512 => MessageDigest::sha512(),
// TODO(jooyung): implement
CONTENT_DIGEST_VERITY_CHUNKED_SHA256 => {
bail!("TODO(b/190343842): CONTENT_DIGEST_VERITY_CHUNKED_SHA256: not implemented")
@@ -179,12 +179,12 @@
}
// v2/v3 digests are computed after prepending "header" byte and "size" info.
- fn digest(&self, data: &[u8], header: &[u8], size: u32) -> digest::Digest {
- let mut ctx = digest::Context::new(self.algorithm);
- ctx.update(header);
- ctx.update(&size.to_le_bytes());
- ctx.update(data);
- ctx.finish()
+ fn digest(&self, data: &[u8], header: &[u8], size: u32) -> Result<DigestBytes> {
+ let mut ctx = Hasher::new(self.algorithm)?;
+ ctx.update(header)?;
+ ctx.update(&size.to_le_bytes())?;
+ ctx.update(data)?;
+ Ok(ctx.finish()?)
}
}
diff --git a/libs/apkverify/src/v3.rs b/libs/apkverify/src/v3.rs
index 797911b..16530be 100644
--- a/libs/apkverify/src/v3.rs
+++ b/libs/apkverify/src/v3.rs
@@ -19,12 +19,12 @@
// TODO(jooyung) remove this
#![allow(dead_code)]
-use anyhow::{anyhow, bail, Context, Result};
+use anyhow::{anyhow, bail, ensure, Context, Result};
use bytes::Bytes;
-use ring::signature::{
- UnparsedPublicKey, VerificationAlgorithm, ECDSA_P256_SHA256_ASN1, RSA_PKCS1_2048_8192_SHA256,
- RSA_PKCS1_2048_8192_SHA512, RSA_PSS_2048_8192_SHA256, RSA_PSS_2048_8192_SHA512,
-};
+use openssl::hash::MessageDigest;
+use openssl::pkey::{self, PKey};
+use openssl::rsa::Padding;
+use openssl::sign::Verifier;
use std::fs::File;
use std::io::{Read, Seek};
use std::ops::Range;
@@ -87,7 +87,7 @@
type AdditionalAttributes = Bytes;
/// Verifies APK Signature Scheme v3 signatures of the provided APK and returns the public key
-/// associated with the signer.
+/// associated with the signer in DER format.
pub fn verify<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
let f = File::open(path.as_ref())?;
let mut sections = ApkSections::new(f)?;
@@ -200,14 +200,22 @@
signature: &Signature,
key_info: &SubjectPublicKeyInfo,
) -> Result<()> {
- let verification_alg: &dyn VerificationAlgorithm = match signature.signature_algorithm_id {
- SIGNATURE_RSA_PSS_WITH_SHA256 => &RSA_PSS_2048_8192_SHA256,
- SIGNATURE_RSA_PSS_WITH_SHA512 => &RSA_PSS_2048_8192_SHA512,
- SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256 | SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 => {
- &RSA_PKCS1_2048_8192_SHA256
+ let (pkey_id, padding, digest) = match signature.signature_algorithm_id {
+ SIGNATURE_RSA_PSS_WITH_SHA256 => {
+ (pkey::Id::RSA, Padding::PKCS1_PSS, MessageDigest::sha256())
}
- SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512 => &RSA_PKCS1_2048_8192_SHA512,
- SIGNATURE_ECDSA_WITH_SHA256 | SIGNATURE_VERITY_ECDSA_WITH_SHA256 => &ECDSA_P256_SHA256_ASN1,
+ SIGNATURE_RSA_PSS_WITH_SHA512 => {
+ (pkey::Id::RSA, Padding::PKCS1_PSS, MessageDigest::sha512())
+ }
+ SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256 | SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 => {
+ (pkey::Id::RSA, Padding::PKCS1, MessageDigest::sha256())
+ }
+ SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512 => {
+ (pkey::Id::RSA, Padding::PKCS1, MessageDigest::sha512())
+ }
+ SIGNATURE_ECDSA_WITH_SHA256 | SIGNATURE_VERITY_ECDSA_WITH_SHA256 => {
+ (pkey::Id::EC, Padding::NONE, MessageDigest::sha256())
+ }
// TODO(b/190343842) not implemented signature algorithm
SIGNATURE_ECDSA_WITH_SHA512
| SIGNATURE_DSA_WITH_SHA256
@@ -219,8 +227,15 @@
}
_ => bail!("Unsupported signature algorithm: {:#x}", signature.signature_algorithm_id),
};
- let key = UnparsedPublicKey::new(verification_alg, &key_info.subject_public_key);
- key.verify(data.as_ref(), signature.signature.as_ref())?;
+ let key = PKey::public_key_from_der(key_info.raw)?;
+ ensure!(key.id() == pkey_id, "Public key has the wrong ID");
+ let mut verifier = Verifier::new(digest, &key)?;
+ if pkey_id == pkey::Id::RSA {
+ verifier.set_rsa_padding(padding)?;
+ }
+ verifier.update(data)?;
+ let verified = verifier.verify(&signature.signature)?;
+ ensure!(verified, "Signature is invalid ");
Ok(())
}
diff --git a/libs/apkverify/tests/apkverify_test.rs b/libs/apkverify/tests/apkverify_test.rs
index ade4468..22faba4 100644
--- a/libs/apkverify/tests/apkverify_test.rs
+++ b/libs/apkverify/tests/apkverify_test.rs
@@ -23,6 +23,11 @@
}
#[test]
+fn test_verify_v3_ecdsa_sha256_p256() {
+ assert!(verify("tests/data/v3-only-with-ecdsa-sha256-p256.apk").is_ok());
+}
+
+#[test]
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());
diff --git a/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p256.apk b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p256.apk
new file mode 100644
index 0000000..5ef4fec
--- /dev/null
+++ b/libs/apkverify/tests/data/v3-only-with-ecdsa-sha256-p256.apk
Binary files differ