Merge "pvm_exec: Set up Android logger"
diff --git a/apkverify/src/bytes_ext.rs b/apkverify/src/bytes_ext.rs
index 1b8d6b6..22a3085 100644
--- a/apkverify/src/bytes_ext.rs
+++ b/apkverify/src/bytes_ext.rs
@@ -98,7 +98,9 @@
 
 #[cfg(test)]
 mod tests {
+    use super::*;
     use bytes::{BufMut, BytesMut};
+
     #[test]
     fn test_read_length_prefixed_slice() {
         let data = b"hello world";
@@ -106,7 +108,7 @@
         b.put_u32_le(data.len() as u32);
         b.put_slice(data);
         let mut slice = b.freeze();
-        let res = super::read_length_prefixed_slice(&mut slice);
+        let res = read_length_prefixed_slice(&mut slice);
         assert!(res.is_ok());
         assert_eq!(data, res.ok().unwrap().as_ref());
     }
diff --git a/apkverify/src/lib.rs b/apkverify/src/lib.rs
index 869431e..f75913c 100644
--- a/apkverify/src/lib.rs
+++ b/apkverify/src/lib.rs
@@ -18,7 +18,8 @@
 
 mod bytes_ext;
 mod sigutil;
-mod testing;
+#[allow(dead_code)]
+pub mod testing;
 mod v3;
 mod ziputil;
 
diff --git a/apkverify/src/sigutil.rs b/apkverify/src/sigutil.rs
index 06645fe..fc92898 100644
--- a/apkverify/src/sigutil.rs
+++ b/apkverify/src/sigutil.rs
@@ -18,7 +18,7 @@
 
 use anyhow::{anyhow, bail, Result};
 use byteorder::{LittleEndian, ReadBytesExt};
-use bytes::{Buf, BufMut, Bytes};
+use bytes::{Buf, BufMut, Bytes, BytesMut};
 use ring::digest;
 use std::cmp::min;
 use std::io::{Cursor, Read, Seek, SeekFrom, Take};
@@ -61,11 +61,11 @@
 
 impl<R: Read + Seek> ApkSections<R> {
     pub fn new(reader: R) -> Result<ApkSections<R>> {
-        let (mut f, zip_sections) = zip_sections(reader)?;
+        let (mut reader, zip_sections) = zip_sections(reader)?;
         let (signing_block_offset, signing_block_size) =
-            find_signing_block(&mut f, zip_sections.central_directory_offset)?;
+            find_signing_block(&mut reader, zip_sections.central_directory_offset)?;
         Ok(ApkSections {
-            inner: f,
+            inner: reader,
             signing_block_offset,
             signing_block_size,
             central_directory_offset: zip_sections.central_directory_offset,
@@ -93,7 +93,7 @@
     pub fn compute_digest(&mut self, signature_algorithm_id: u32) -> Result<Vec<u8>> {
         let digester = Digester::new(signature_algorithm_id)?;
 
-        let mut digests_of_chunks = bytes::BytesMut::new();
+        let mut digests_of_chunks = BytesMut::new();
         let mut chunk_count = 0u32;
         let mut chunk = vec![0u8; CHUNK_SIZE_BYTES as usize];
         for data in &[
@@ -118,6 +118,7 @@
     fn zip_entries(&mut self) -> Result<Take<Box<dyn Read + '_>>> {
         scoped_read(&mut self.inner, 0, self.signing_block_offset as u64)
     }
+
     fn central_directory(&mut self) -> Result<Take<Box<dyn Read + '_>>> {
         scoped_read(
             &mut self.inner,
@@ -125,6 +126,7 @@
             self.central_directory_size as u64,
         )
     }
+
     fn eocd_for_verification(&mut self) -> Result<Take<Box<dyn Read + '_>>> {
         let mut eocd = self.bytes(self.eocd_offset, self.eocd_size)?;
         // Protection of section 4 (ZIP End of Central Directory) is complicated by the section
@@ -136,6 +138,7 @@
         set_central_directory_offset(&mut eocd, self.signing_block_offset)?;
         Ok(Read::take(Box::new(Cursor::new(eocd)), self.eocd_size as u64))
     }
+
     fn bytes(&mut self, offset: u32, size: u32) -> Result<Vec<u8>> {
         self.inner.seek(SeekFrom::Start(offset as u64))?;
         let mut buf = vec![0u8; size as usize];
@@ -159,6 +162,7 @@
 
 const CHUNK_HEADER_TOP: &[u8] = &[0x5a];
 const CHUNK_HEADER_MID: &[u8] = &[0xa5];
+
 impl Digester {
     fn new(signature_algorithm_id: u32) -> Result<Digester> {
         let digest_algorithm_id = to_content_digest_algorithm(signature_algorithm_id)?;
@@ -173,6 +177,7 @@
         };
         Ok(Digester { algorithm })
     }
+
     // 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);
diff --git a/apkverify/src/testing.rs b/apkverify/src/testing.rs
index 777afb8..301a9c3 100644
--- a/apkverify/src/testing.rs
+++ b/apkverify/src/testing.rs
@@ -16,19 +16,7 @@
 
 //! A collection of utilities for testing
 
-/// Asserts if `haystack.contains(needed)`
-#[macro_export]
-macro_rules! assert_contains {
-    ($haystack:expr,$needle:expr $(,)?) => {
-        match (&$haystack, &$needle) {
-            (haystack_value, needle_value) => {
-                assert!(
-                    haystack_value.contains(needle_value),
-                    "{} is not found in {}",
-                    needle_value,
-                    haystack_value
-                );
-            }
-        }
-    };
+/// Asserts if `haystack.contains(needle)`
+pub fn assert_contains(haystack: &str, needle: &str) {
+    assert!(haystack.contains(needle), "{} is not found in {}", needle, haystack);
 }
diff --git a/apkverify/src/v3.rs b/apkverify/src/v3.rs
index d1f59c6..2f9ce94 100644
--- a/apkverify/src/v3.rs
+++ b/apkverify/src/v3.rs
@@ -21,11 +21,15 @@
 
 use anyhow::{anyhow, bail, 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 std::fs::File;
 use std::io::{Read, Seek};
 use std::ops::Range;
 use std::path::Path;
-use x509_parser::{prelude::FromDer, x509};
+use x509_parser::{parse_x509_certificate, prelude::FromDer, x509::SubjectPublicKeyInfo};
 
 use crate::bytes_ext::{BytesExt, LengthPrefixed, ReadFromBytes};
 use crate::sigutil::*;
@@ -45,7 +49,7 @@
     min_sdk: u32,
     max_sdk: u32,
     signatures: LengthPrefixed<Vec<LengthPrefixed<Signature>>>,
-    public_key: LengthPrefixed<SubjectPublicKeyInfo>,
+    public_key: LengthPrefixed<Bytes>,
 }
 
 impl Signer {
@@ -79,7 +83,6 @@
     digest: LengthPrefixed<Bytes>,
 }
 
-type SubjectPublicKeyInfo = Bytes;
 type X509Certificate = Bytes;
 type AdditionalAttributes = Bytes;
 
@@ -128,7 +131,7 @@
 
         // 2. Verify the corresponding signature from signatures against signed data using public key.
         //    (It is now safe to parse signed data.)
-        let (_, key_info) = x509::SubjectPublicKeyInfo::from_der(self.public_key.as_ref())?;
+        let (_, key_info) = 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.
@@ -172,7 +175,7 @@
         // 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())?;
+        let (_, cert) = parse_x509_certificate(cert.as_ref())?;
         if cert.tbs_certificate.subject_pki != key_info {
             bail!("Public key mismatch between certificate and signature record");
         }
@@ -185,32 +188,28 @@
 fn verify_signed_data(
     data: &Bytes,
     signature: &Signature,
-    key_info: &x509::SubjectPublicKeyInfo,
+    key_info: &SubjectPublicKeyInfo,
 ) -> Result<()> {
-    use ring::signature;
-    let verification_alg: &dyn signature::VerificationAlgorithm =
-        match signature.signature_algorithm_id {
-            SIGNATURE_RSA_PSS_WITH_SHA256 => &signature::RSA_PSS_2048_8192_SHA256,
-            SIGNATURE_RSA_PSS_WITH_SHA512 => &signature::RSA_PSS_2048_8192_SHA512,
-            SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256 | SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 => {
-                &signature::RSA_PKCS1_2048_8192_SHA256
-            }
-            SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512 => &signature::RSA_PKCS1_2048_8192_SHA512,
-            SIGNATURE_ECDSA_WITH_SHA256 | SIGNATURE_VERITY_ECDSA_WITH_SHA256 => {
-                &signature::ECDSA_P256_SHA256_ASN1
-            }
-            // TODO(b/190343842) not implemented signature algorithm
-            SIGNATURE_ECDSA_WITH_SHA512
-            | SIGNATURE_DSA_WITH_SHA256
-            | SIGNATURE_VERITY_DSA_WITH_SHA256 => {
-                bail!(
-                    "TODO(b/190343842) not implemented signature algorithm: {:#x}",
-                    signature.signature_algorithm_id
-                );
-            }
-            _ => bail!("Unsupported signature algorithm: {:#x}", signature.signature_algorithm_id),
-        };
-    let key = signature::UnparsedPublicKey::new(verification_alg, &key_info.subject_public_key);
+    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
+        }
+        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,
+        // TODO(b/190343842) not implemented signature algorithm
+        SIGNATURE_ECDSA_WITH_SHA512
+        | SIGNATURE_DSA_WITH_SHA256
+        | SIGNATURE_VERITY_DSA_WITH_SHA256 => {
+            bail!(
+                "TODO(b/190343842) not implemented signature algorithm: {:#x}",
+                signature.signature_algorithm_id
+            );
+        }
+        _ => 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())?;
     Ok(())
 }
diff --git a/apkverify/src/ziputil.rs b/apkverify/src/ziputil.rs
index bfb1c01..f18a38a 100644
--- a/apkverify/src/ziputil.rs
+++ b/apkverify/src/ziputil.rs
@@ -93,7 +93,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::assert_contains;
+    use crate::testing::assert_contains;
     use std::io::{Cursor, Write};
     use zip::{write::FileOptions, ZipWriter};
 
@@ -125,6 +125,6 @@
         // ZipArchive::new() succeeds, but we should reject
         let res = zip_sections(Cursor::new([pre_eocd, cd, eocd].concat()));
         assert!(res.is_err());
-        assert_contains!(res.err().unwrap().to_string(), "Invalid ZIP: offset should be 0");
+        assert_contains(&res.err().unwrap().to_string(), "Invalid ZIP: offset should be 0");
     }
 }
diff --git a/apkverify/tests/apkverify_test.rs b/apkverify/tests/apkverify_test.rs
index 3366524..ade4468 100644
--- a/apkverify/tests/apkverify_test.rs
+++ b/apkverify/tests/apkverify_test.rs
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-use apkverify::{assert_contains, verify};
+use apkverify::{testing::assert_contains, verify};
 use std::matches;
 
 #[test]
@@ -26,14 +26,14 @@
 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.unwrap_err().to_string(), "Digest mismatch");
 }
 
 #[test]
-fn test_verify_v3_cert_and_publick_key_mismatch() {
+fn test_verify_v3_cert_and_public_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");
+    assert_contains(&res.unwrap_err().to_string(), "Public key mismatch");
 }
 
 #[test]
@@ -42,7 +42,7 @@
     let res = verify("tests/data/v2-only-truncated-cd.apk");
     // TODO(jooyung): consider making a helper for err assertion
     assert!(matches!(
-        res.err().unwrap().root_cause().downcast_ref::<ZipError>().unwrap(),
+        res.unwrap_err().root_cause().downcast_ref::<ZipError>().unwrap(),
         ZipError::InvalidArchive(_),
     ));
 }
diff --git a/authfs/fd_server/src/fsverity.rs b/authfs/fd_server/src/fsverity.rs
index e89bbd0..576f9dd 100644
--- a/authfs/fd_server/src/fsverity.rs
+++ b/authfs/fd_server/src/fsverity.rs
@@ -47,16 +47,7 @@
         buf_ptr: buf.as_mut_ptr() as u64,
         __reserved: 0,
     };
-    Ok(unsafe { read_verity_metadata(fd, &mut arg) }.map_err(|e| {
-        if let nix::Error::Sys(errno) = e {
-            io::Error::from_raw_os_error(errno as i32)
-        } else {
-            // Document of nix::sys::ioctl indicates the macro-generated function always returns an
-            // nix::errno::Errno, which can be converted nix::Error::Sys above. As the result, this
-            // branch is unreachable.
-            unreachable!();
-        }
-    })? as usize)
+    Ok(unsafe { read_verity_metadata(fd, &mut arg) }? as usize)
 }
 
 /// Read the raw Merkle tree from the fd, if it exists. The API semantics is similar to a regular
diff --git a/compos/apk/test.keystore b/compos/apk/test.keystore
index 2f024d8..2946641 100644
--- a/compos/apk/test.keystore
+++ b/compos/apk/test.keystore
Binary files differ
diff --git a/idsig/Android.bp b/idsig/Android.bp
index 90525ff..94aaca0 100644
--- a/idsig/Android.bp
+++ b/idsig/Android.bp
@@ -10,6 +10,7 @@
     prefer_rlib: true,
     rustlibs: [
         "libanyhow",
+        "libbyteorder",
         "libring",
         "libnum_traits",
     ],
diff --git a/idsig/Cargo.toml b/idsig/Cargo.toml
index 91b2842..49ae18d 100644
--- a/idsig/Cargo.toml
+++ b/idsig/Cargo.toml
@@ -6,6 +6,7 @@
 
 [dependencies]
 anyhow = "1.0"
+byteorder = "1.1"
 ring = "0.16"
 num-derive = "0.3"
 num-traits = "0.2"
diff --git a/idsig/src/apksigv4.rs b/idsig/src/apksigv4.rs
index 6f4603d..a5578d8 100644
--- a/idsig/src/apksigv4.rs
+++ b/idsig/src/apksigv4.rs
@@ -14,17 +14,20 @@
  * limitations under the License.
  */
 
-use anyhow::{anyhow, Context, Result};
-use num_derive::FromPrimitive;
-use num_traits::FromPrimitive;
-use std::io::{Read, Seek};
+use anyhow::{anyhow, bail, Context, Result};
+use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
+use num_derive::{FromPrimitive, ToPrimitive};
+use num_traits::{FromPrimitive, ToPrimitive};
+use std::io::{copy, Cursor, Read, Seek, SeekFrom, Write};
 
-// `apksigv4` module provides routines to decode the idsig file as defined in [APK signature
-// scheme v4] (https://source.android.com/security/apksigning/v4).
+use crate::hashtree::*;
+
+// `apksigv4` module provides routines to decode and encode the idsig file as defined in [APK
+// signature scheme v4] (https://source.android.com/security/apksigning/v4).
 
 /// `V4Signature` provides access to the various fields in an idsig file.
-#[derive(Debug)]
-pub struct V4Signature {
+#[derive(Default)]
+pub struct V4Signature<R: Read + Seek> {
     /// Version of the header. Should be 2.
     pub version: Version,
     /// Provides access to the information about how the APK is hashed.
@@ -35,10 +38,13 @@
     pub merkle_tree_size: u32,
     /// Offset of the merkle tree in the idsig file
     pub merkle_tree_offset: u64,
+
+    // Provides access to the underlying data
+    data: R,
 }
 
 /// `HashingInfo` provides information about how the APK is hashed.
-#[derive(Debug)]
+#[derive(Default)]
 pub struct HashingInfo {
     /// Hash algorithm used when creating the merkle tree for the APK.
     pub hash_algorithm: HashAlgorithm,
@@ -51,7 +57,7 @@
 }
 
 /// `SigningInfo` provides information that can be used to verify the idsig file.
-#[derive(Debug)]
+#[derive(Default)]
 pub struct SigningInfo {
     /// Digest of the APK that this idsig file is for.
     pub apk_digest: Box<[u8]>,
@@ -68,7 +74,7 @@
 }
 
 /// Version of the idsig file format
-#[derive(Debug, PartialEq, FromPrimitive)]
+#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
 #[repr(u32)]
 pub enum Version {
     /// Version 2, the only supported version.
@@ -81,8 +87,14 @@
     }
 }
 
+impl Default for Version {
+    fn default() -> Self {
+        Version::V2
+    }
+}
+
 /// Hash algorithm that can be used for idsig file.
-#[derive(Debug, PartialEq, FromPrimitive)]
+#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
 #[repr(u32)]
 pub enum HashAlgorithm {
     /// SHA2-256
@@ -95,8 +107,14 @@
     }
 }
 
+impl Default for HashAlgorithm {
+    fn default() -> Self {
+        HashAlgorithm::SHA256
+    }
+}
+
 /// Signature algorithm that can be used for idsig file
-#[derive(Debug, PartialEq, FromPrimitive)]
+#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
 #[allow(non_camel_case_types)]
 #[repr(u32)]
 pub enum SignatureAlgorithmId {
@@ -123,67 +141,186 @@
     }
 }
 
-impl V4Signature {
-    /// Reads a stream from `r` and then parses it into a `V4Signature` struct.
-    pub fn from<T: Read + Seek>(mut r: T) -> Result<V4Signature> {
+impl Default for SignatureAlgorithmId {
+    fn default() -> Self {
+        SignatureAlgorithmId::DSA_SHA2_256
+    }
+}
+
+impl<R: Read + Seek> V4Signature<R> {
+    /// Consumes a stream for an idsig file into a `V4Signature` struct.
+    pub fn from(mut r: R) -> Result<V4Signature<R>> {
         Ok(V4Signature {
-            version: Version::from(read_le_u32(&mut r)?)?,
+            version: Version::from(r.read_u32::<LittleEndian>()?)?,
             hashing_info: HashingInfo::from(&mut r)?,
             signing_info: SigningInfo::from(&mut r)?,
-            merkle_tree_size: read_le_u32(&mut r)?,
+            merkle_tree_size: r.read_u32::<LittleEndian>()?,
             merkle_tree_offset: r.stream_position()?,
+            data: r,
         })
     }
+
+    /// Read a stream for an APK file and creates a corresponding `V4Signature` struct that digests
+    /// the APK file. Note that the signing is not done.
+    pub fn create(
+        mut apk: &mut R,
+        block_size: usize,
+        salt: &[u8],
+        algorithm: HashAlgorithm,
+    ) -> Result<V4Signature<Cursor<Vec<u8>>>> {
+        // Determine the size of the apk
+        let start = apk.stream_position()?;
+        let size = apk.seek(SeekFrom::End(0))? as usize;
+        apk.seek(SeekFrom::Start(start))?;
+
+        // Create hash tree (and root hash)
+        let algorithm = match algorithm {
+            HashAlgorithm::SHA256 => &ring::digest::SHA256,
+        };
+        let hash_tree = HashTree::from(&mut apk, size, salt, block_size, algorithm)?;
+
+        let mut ret = V4Signature {
+            version: Version::default(),
+            hashing_info: HashingInfo::default(),
+            signing_info: SigningInfo::default(),
+            merkle_tree_size: hash_tree.tree.len() as u32,
+            merkle_tree_offset: 0, // merkle tree starts from the beginning of `data`
+            data: Cursor::new(hash_tree.tree),
+        };
+        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.
+
+        Ok(ret)
+    }
+
+    /// Writes the data into a writer
+    pub fn write_into<W: Write + Seek>(&mut self, mut w: &mut W) -> Result<()> {
+        // Writes the header part
+        w.write_u32::<LittleEndian>(self.version.to_u32().unwrap())?;
+        self.hashing_info.write_into(&mut w)?;
+        self.signing_info.write_into(&mut w)?;
+        w.write_u32::<LittleEndian>(self.merkle_tree_size)?;
+
+        // Writes the merkle tree
+        self.data.seek(SeekFrom::Start(self.merkle_tree_offset))?;
+        let copied_size = copy(&mut self.data, &mut w)?;
+        if copied_size != self.merkle_tree_size as u64 {
+            bail!(
+                "merkle tree is {} bytes, but only {} bytes are written.",
+                self.merkle_tree_size,
+                copied_size
+            );
+        }
+        Ok(())
+    }
+
+    /// Returns the bytes that represents the merkle tree
+    pub fn merkle_tree(&mut self) -> Result<Vec<u8>> {
+        self.data.seek(SeekFrom::Start(self.merkle_tree_offset))?;
+        let mut out = Vec::new();
+        self.data.read_to_end(&mut out)?;
+        Ok(out)
+    }
 }
 
 impl HashingInfo {
     fn from(mut r: &mut dyn Read) -> Result<HashingInfo> {
-        read_le_u32(&mut r)?;
+        // Size of the entire hashing_info struct. We don't need this because each variable-sized
+        // fields in the struct are also length encoded.
+        r.read_u32::<LittleEndian>()?;
         Ok(HashingInfo {
-            hash_algorithm: HashAlgorithm::from(read_le_u32(&mut r)?)?,
-            log2_blocksize: read_u8(&mut r)?,
+            hash_algorithm: HashAlgorithm::from(r.read_u32::<LittleEndian>()?)?,
+            log2_blocksize: r.read_u8()?,
             salt: read_sized_array(&mut r)?,
             raw_root_hash: read_sized_array(&mut r)?,
         })
     }
+
+    fn write_into<W: Write + Seek>(&self, mut w: &mut W) -> Result<()> {
+        let start = w.stream_position()?;
+        // Size of the entire hashing_info struct. Since we don't know the size yet, fill the place
+        // with 0. The exact size will then be written below.
+        w.write_u32::<LittleEndian>(0)?;
+
+        w.write_u32::<LittleEndian>(self.hash_algorithm.to_u32().unwrap())?;
+        w.write_u8(self.log2_blocksize)?;
+        write_sized_array(&mut w, &self.salt)?;
+        write_sized_array(&mut w, &self.raw_root_hash)?;
+
+        // Determine the size of hashing_info, and write it in front of the struct where the value
+        // was initialized to zero.
+        let end = w.stream_position()?;
+        let size = end - start - std::mem::size_of::<u32>() as u64;
+        w.seek(SeekFrom::Start(start))?;
+        w.write_u32::<LittleEndian>(size as u32)?;
+        w.seek(SeekFrom::Start(end))?;
+        Ok(())
+    }
 }
 
 impl SigningInfo {
     fn from(mut r: &mut dyn Read) -> Result<SigningInfo> {
-        read_le_u32(&mut r)?;
+        // Size of the entire signing_info struct. We don't need this because each variable-sized
+        // fields in the struct are also length encoded.
+        r.read_u32::<LittleEndian>()?;
         Ok(SigningInfo {
             apk_digest: read_sized_array(&mut r)?,
             x509_certificate: read_sized_array(&mut r)?,
             additional_data: read_sized_array(&mut r)?,
             public_key: read_sized_array(&mut r)?,
-            signature_algorithm_id: SignatureAlgorithmId::from(read_le_u32(&mut r)?)?,
+            signature_algorithm_id: SignatureAlgorithmId::from(r.read_u32::<LittleEndian>()?)?,
             signature: read_sized_array(&mut r)?,
         })
     }
-}
 
-fn read_u8(r: &mut dyn Read) -> Result<u8> {
-    let mut byte = [0; 1];
-    r.read_exact(&mut byte)?;
-    Ok(byte[0])
-}
+    fn write_into<W: Write + Seek>(&self, mut w: &mut W) -> Result<()> {
+        let start = w.stream_position()?;
+        // Size of the entire signing_info struct. Since we don't know the size yet, fill the place
+        // with 0. The exact size will then be written below.
+        w.write_u32::<LittleEndian>(0)?;
 
-fn read_le_u32(r: &mut dyn Read) -> Result<u32> {
-    let mut bytes = [0; 4];
-    r.read_exact(&mut bytes)?;
-    Ok(u32::from_le_bytes(bytes))
+        write_sized_array(&mut w, &self.apk_digest)?;
+        write_sized_array(&mut w, &self.x509_certificate)?;
+        write_sized_array(&mut w, &self.additional_data)?;
+        write_sized_array(&mut w, &self.public_key)?;
+        w.write_u32::<LittleEndian>(self.signature_algorithm_id.to_u32().unwrap())?;
+        write_sized_array(&mut w, &self.signature)?;
+
+        // Determine the size of signing_info, and write it in front of the struct where the value
+        // was initialized to zero.
+        let end = w.stream_position()?;
+        let size = end - start - std::mem::size_of::<u32>() as u64;
+        w.seek(SeekFrom::Start(start))?;
+        w.write_u32::<LittleEndian>(size as u32)?;
+        w.seek(SeekFrom::Start(end))?;
+        Ok(())
+    }
 }
 
 fn read_sized_array(r: &mut dyn Read) -> Result<Box<[u8]>> {
-    let size = read_le_u32(r)?;
+    let size = r.read_u32::<LittleEndian>()?;
     let mut data = vec![0; size as usize];
     r.read_exact(&mut data)?;
     Ok(data.into_boxed_slice())
 }
 
+fn write_sized_array(w: &mut dyn Write, data: &[u8]) -> Result<()> {
+    w.write_u32::<LittleEndian>(data.len() as u32)?;
+    Ok(w.write_all(data)?)
+}
+
+fn log2(n: usize) -> u8 {
+    let num_bits = std::mem::size_of::<usize>() * 8;
+    (num_bits as u32 - n.leading_zeros() - 1) as u8
+}
+
 #[cfg(test)]
 mod tests {
-    use crate::apksigv4::*;
+    use super::*;
     use std::io::Cursor;
 
     fn hexstring_from(s: &[u8]) -> String {
@@ -222,4 +359,41 @@
         assert_eq!(36864, parsed.merkle_tree_size);
         assert_eq!(2251, parsed.merkle_tree_offset);
     }
+
+    /// Parse an idsig file into V4Signature and write it. The written date must be the same as
+    /// the input file.
+    #[test]
+    fn parse_and_compose() {
+        let input = Cursor::new(include_bytes!("../testdata/test.apk.idsig"));
+        let mut parsed = V4Signature::from(input.clone()).unwrap();
+
+        let mut output = Cursor::new(Vec::new());
+        parsed.write_into(&mut output).unwrap();
+
+        assert_eq!(input.get_ref().as_ref(), output.get_ref().as_slice());
+    }
+
+    /// Create V4Signature by hashing an APK. Merkle tree and the root hash should be the same
+    /// as those in the idsig file created by the signapk tool.
+    #[test]
+    fn digest_from_apk() {
+        let mut input = Cursor::new(include_bytes!("../testdata/test.apk"));
+        let mut created =
+            V4Signature::create(&mut input, 4096, &[], HashAlgorithm::SHA256).unwrap();
+
+        let golden = Cursor::new(include_bytes!("../testdata/test.apk.idsig"));
+        let mut golden = V4Signature::from(golden).unwrap();
+
+        // Compare the root hash
+        assert_eq!(
+            created.hashing_info.raw_root_hash.as_ref(),
+            golden.hashing_info.raw_root_hash.as_ref()
+        );
+
+        // Compare the merkle tree
+        assert_eq!(
+            created.merkle_tree().unwrap().as_slice(),
+            golden.merkle_tree().unwrap().as_slice()
+        );
+    }
 }
diff --git a/idsig/src/hashtree.rs b/idsig/src/hashtree.rs
index a4727a9..1ce2879 100644
--- a/idsig/src/hashtree.rs
+++ b/idsig/src/hashtree.rs
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-use ring::digest::{self, Algorithm, Digest};
+pub use ring::digest::{Algorithm, Digest};
+
+use ring::digest;
 use std::io::{Cursor, Read, Result, Write};
 
 /// `HashTree` is a merkle tree (and its root hash) that is compatible with fs-verity.
@@ -62,7 +64,7 @@
 /// blocksize-byte blocks (zero-padding the ends as needed) and these blocks are hashed,
 /// producing the second level of hashes. This proceeds up the tree until only a single block
 /// remains.
-fn generate_hash_tree<R: Read>(
+pub fn generate_hash_tree<R: Read>(
     input: &mut R,
     input_size: usize,
     salt: &[u8],
@@ -191,7 +193,7 @@
 
 #[cfg(test)]
 mod tests {
-    use crate::hashtree::*;
+    use super::*;
     use ring::digest;
     use std::fs::{self, File};
 
diff --git a/idsig/testdata/test.apk b/idsig/testdata/test.apk
new file mode 100644
index 0000000..cbee532
--- /dev/null
+++ b/idsig/testdata/test.apk
Binary files differ
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index fa456e8..d7e256b 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -40,8 +40,8 @@
     let metadata = metadata::load()?;
 
     if let Err(err) = verify_payloads() {
-        error!("failed to verify payload: {}", err);
-        // TODO(jooyung): should stop the boot process if verification fails
+        error!("failed to verify payload: {:#?}", err);
+        return Err(err);
     }
 
     if !metadata.payload_config_path.is_empty() {
diff --git a/tests/testapk/test.keystore b/tests/testapk/test.keystore
index 2f024d8..2946641 100644
--- a/tests/testapk/test.keystore
+++ b/tests/testapk/test.keystore
Binary files differ