Merge "Migrate pkvm_perf_test.py test_compilation_in_android function to AOSP"
diff --git a/libs/apexutil/src/lib.rs b/libs/apexutil/src/lib.rs
index 63b09de..1183aea 100644
--- a/libs/apexutil/src/lib.rs
+++ b/libs/apexutil/src/lib.rs
@@ -93,6 +93,19 @@
     Err(ApexParseError::DescriptorNotHashtree)
 }
 
+/// Gets the hash of the payload's verified VBMeta image data.
+pub fn get_payload_vbmeta_image_hash(path: &str) -> Result<Vec<u8>, ApexVerificationError> {
+    let apex_file = File::open(path).map_err(ApexParseError::Io)?;
+    let (_, offset, size) = get_public_key_and_image_info(&apex_file)?;
+    let vbmeta = VbMetaImage::verify_reader_region(apex_file, offset, size)?;
+    Ok(vbmeta.hash().ok_or(ApexVerificationError::ApexPubkeyMistmatch)?.to_vec())
+}
+
+/// Converts the buffer to a Hex String
+pub fn to_hex_string(buf: &[u8]) -> String {
+    buf.iter().map(|b| format!("{:02x}", b)).collect()
+}
+
 fn get_public_key_and_image_info(apex_file: &File) -> Result<(Vec<u8>, u64, u64), ApexParseError> {
     let mut z = ZipArchive::new(apex_file).map_err(|err| match err {
         ZipError::Io(err) => ApexParseError::Io(err),
@@ -130,9 +143,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    fn to_hex_string(buf: &[u8]) -> String {
-        buf.iter().map(|b| format!("{:02x}", b)).collect()
-    }
+
     #[test]
     fn test_open_apex() {
         let res = verify("tests/data/test.apex").unwrap();
@@ -141,4 +152,13 @@
             "fe11ab17da0a3a738b54bdc3a13f6139cbdf91ec32f001f8d4bbbf8938e04e39"
         );
     }
+
+    #[test]
+    fn test_payload_vbmeta_image_hash() {
+        let result = get_payload_vbmeta_image_hash("tests/data/test.apex").unwrap();
+        assert_eq!(
+            to_hex_string(&result),
+            "296e32a76544de9da01713e471403ab4667705ad527bb4f1fac0cf61e7ce122d"
+        );
+    }
 }
diff --git a/libs/apkverify/Android.bp b/libs/apkverify/Android.bp
index d45a77f..2d58bb0 100644
--- a/libs/apkverify/Android.bp
+++ b/libs/apkverify/Android.bp
@@ -14,7 +14,6 @@
         "libbytes",
         "liblog_rust",
         "libopenssl",
-        "libx509_parser",
         "libzip",
     ],
 }
diff --git a/libs/apkverify/src/v3.rs b/libs/apkverify/src/v3.rs
index 96ca7bc..0c20a2e 100644
--- a/libs/apkverify/src/v3.rs
+++ b/libs/apkverify/src/v3.rs
@@ -25,11 +25,11 @@
 use openssl::pkey::{self, PKey};
 use openssl::rsa::Padding;
 use openssl::sign::Verifier;
+use openssl::x509::X509;
 use std::fs::File;
 use std::io::{Read, Seek};
 use std::ops::Range;
 use std::path::Path;
-use x509_parser::{parse_x509_certificate, prelude::FromDer, x509::SubjectPublicKeyInfo};
 
 use crate::bytes_ext::{BytesExt, LengthPrefixed, ReadFromBytes};
 use crate::sigutil::*;
@@ -168,8 +168,8 @@
 
         // 2. Verify the corresponding signature from signatures against signed data using public key.
         //    (It is now safe to parse signed data.)
-        let (_, key_info) = SubjectPublicKeyInfo::from_der(self.public_key.as_ref())?;
-        verify_signed_data(&self.signed_data, strongest, &key_info)?;
+        let public_key = PKey::public_key_from_der(self.public_key.as_ref())?;
+        verify_signed_data(&self.signed_data, strongest, &public_key)?;
 
         // It is now safe to parse signed data.
         let signed_data: SignedData = self.signed_data.slice(..).read()?;
@@ -209,11 +209,11 @@
             );
         }
 
-        // 7. Verify that SubjectPublicKeyInfo of the first certificate of certificates is identical
+        // 7. Verify that public key of the first certificate of certificates is identical
         //    to public key.
         let cert = signed_data.certificates.first().context("No certificates listed")?;
-        let (_, cert) = parse_x509_certificate(cert.as_ref())?;
-        if cert.tbs_certificate.subject_pki != key_info {
+        let cert = X509::from_der(cert.as_ref())?;
+        if !cert.public_key()?.public_eq(&public_key) {
             bail!("Public key mismatch between certificate and signature record");
         }
 
@@ -222,11 +222,7 @@
     }
 }
 
-fn verify_signed_data(
-    data: &Bytes,
-    signature: &Signature,
-    key_info: &SubjectPublicKeyInfo,
-) -> Result<()> {
+fn verify_signed_data(data: &Bytes, signature: &Signature, key: &PKey<pkey::Public>) -> Result<()> {
     let (pkey_id, padding, digest) = match signature.signature_algorithm_id {
         SIGNATURE_RSA_PSS_WITH_SHA256 => {
             (pkey::Id::RSA, Padding::PKCS1_PSS, MessageDigest::sha256())
@@ -254,9 +250,8 @@
         }
         _ => bail!("Unsupported signature algorithm: {:#x}", signature.signature_algorithm_id),
     };
-    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)?;
+    let mut verifier = Verifier::new(digest, key)?;
     if pkey_id == pkey::Id::RSA {
         verifier.set_rsa_padding(padding)?;
     }
diff --git a/libs/vbmeta/src/lib.rs b/libs/vbmeta/src/lib.rs
index 2d3463c..887844c 100644
--- a/libs/vbmeta/src/lib.rs
+++ b/libs/vbmeta/src/lib.rs
@@ -138,6 +138,18 @@
         Some(&self.data[begin..end])
     }
 
+    /// Get the hash of the verified data in the VBMeta image from the authentication block. If the
+    /// image was not signed, there might not be a hash and, if there is, it's not known to be
+    /// correct.
+    pub fn hash(&self) -> Option<&[u8]> {
+        if self.header.algorithm_type == AvbAlgorithmType_AVB_ALGORITHM_TYPE_NONE {
+            return None;
+        }
+        let begin = size_of::<AvbVBMetaImageHeader>() + self.header.hash_offset as usize;
+        let end = begin + self.header.hash_size as usize;
+        Some(&self.data[begin..end])
+    }
+
     /// Get the descriptors of the VBMeta image.
     pub fn descriptors(&self) -> Result<Descriptors<'_>, VbMetaImageParseError> {
         Descriptors::from_image(&self.data)
diff --git a/microdroid/kdump/kexec.c b/microdroid/kdump/kexec.c
index 65ea0ea..8d88951 100644
--- a/microdroid/kdump/kexec.c
+++ b/microdroid/kdump/kexec.c
@@ -27,6 +27,17 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#if defined(__aarch64__)
+#define EARLYCON "earlycon=uart8250,mmio,0x3f8"
+#elif defined(__x86_64__)
+#define EARLYCON "earlycon=uart8250,io,0x3f8"
+#endif
+
+static const char *KERNEL = "/system/etc/microdroid_crashdump_kernel";
+static const char *INITRD = "/system/etc/microdroid_crashdump_initrd.img";
+static const char *CMDLINE = "1 panic=-1 rdinit=/bin/crashdump nr_cpus=1 reset_devices "
+                             "console=hvc0 " EARLYCON;
+
 static int open_checked(const char* path) {
     int fd = open(path, O_RDONLY);
     if (fd == -1) {
@@ -36,20 +47,11 @@
     return fd;
 }
 
-int main(int argc, const char* argv[]) {
-    if (argc != 4) {
-        fprintf(stderr, "Usage: %s <kernel> <initrd> <commandline>\n", argv[0]);
-        return 1;
-    }
+int main() {
+    unsigned long cmdline_len = strlen(CMDLINE) + 1; // include null terminator, otherwise EINVAL
 
-    // TODO(b/238272206): consider harding these
-    const char* kernel = argv[1];
-    const char* initrd = argv[2];
-    const char* cmdline = argv[3];
-    unsigned long cmdline_len = strlen(cmdline) + 1; // include null terminator, otherwise EINVAL
-
-    if (syscall(SYS_kexec_file_load, open_checked(kernel), open_checked(initrd), cmdline_len,
-                cmdline, KEXEC_FILE_ON_CRASH) == -1) {
+    if (syscall(SYS_kexec_file_load, open_checked(KERNEL), open_checked(INITRD), cmdline_len,
+                CMDLINE, KEXEC_FILE_ON_CRASH) == -1) {
         fprintf(stderr, "Failed to load panic kernel: %s\n", strerror(errno));
         return 1;
     }