Merge "Remove functionality to migrate keys across app UID"
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 2027af4..74aa4bd 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -89,6 +89,19 @@
     ],
 }
 
+rust_library {
+    name: "libkeystore2_with_test_utils",
+    defaults: ["libkeystore2_defaults"],
+    features: [
+        "keystore2_blob_test_utils",
+    ],
+    rustlibs: [
+        "liblibsqlite3_sys",
+        "librusqlite",
+        "libkeystore2_test_utils",
+    ],
+}
+
 rust_test {
     name: "keystore2_test_utils_test",
     srcs: ["test_utils/lib.rs"],
@@ -119,10 +132,12 @@
         "liblibsqlite3_sys",
         "libnix",
         "librusqlite",
+        "libkeystore2_with_test_utils",
     ],
     // The test should always include watchdog.
     features: [
         "watchdog",
+        "keystore2_blob_test_utils",
     ],
 }
 
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index 3db1a9f..192f445 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -80,7 +80,6 @@
     case Tag::CERTIFICATE_SUBJECT:
     case Tag::CERTIFICATE_NOT_BEFORE:
     case Tag::CERTIFICATE_NOT_AFTER:
-    case Tag::INCLUDE_UNIQUE_ID:
     case Tag::DEVICE_UNIQUE_ATTESTATION:
         return true;
     default:
diff --git a/keystore2/src/legacy_blob.rs b/keystore2/src/legacy_blob.rs
index cbc680d..d75bfd2 100644
--- a/keystore2/src/legacy_blob.rs
+++ b/keystore2/src/legacy_blob.rs
@@ -1387,25 +1387,24 @@
     }
 }
 
-#[cfg(test)]
-mod test {
+/// This module implements utility apis for creating legacy blob files.
+#[cfg(feature = "keystore2_blob_test_utils")]
+pub mod test_utils {
     #![allow(dead_code)]
-    use super::*;
-    use keystore2_crypto::{aes_gcm_decrypt, aes_gcm_encrypt};
-    use rand::Rng;
-    use std::string::FromUtf8Error;
-    mod legacy_blob_test_vectors;
+
+    /// test vectors for legacy key blobs
+    pub mod legacy_blob_test_vectors;
+
     use crate::legacy_blob::blob_types::{
         GENERIC, KEY_CHARACTERISTICS, KEY_CHARACTERISTICS_CACHE, KM_BLOB, SUPER_KEY,
         SUPER_KEY_AES256,
     };
-    use crate::legacy_blob::test::legacy_blob_test_vectors::*;
+    use crate::legacy_blob::*;
     use anyhow::{anyhow, Result};
-    use keystore2_test_utils::TempDir;
+    use keystore2_crypto::{aes_gcm_decrypt, aes_gcm_encrypt};
     use std::convert::TryInto;
     use std::fs::OpenOptions;
     use std::io::Write;
-    use std::ops::Deref;
 
     /// This function takes a blob and synchronizes the encrypted/super encrypted flags
     /// with the blob type for the pairs Generic/EncryptedGeneric,
@@ -1414,7 +1413,7 @@
     /// or flags::ENCRYPTED is set, the payload is encrypted and the corresponding
     /// encrypted variant is returned, and vice versa. All other variants remain untouched
     /// even if flags and BlobValue variant are inconsistent.
-    fn prepare_blob(blob: Blob, key: &[u8]) -> Result<Blob> {
+    pub fn prepare_blob(blob: Blob, key: &[u8]) -> Result<Blob> {
         match blob {
             Blob { value: BlobValue::Generic(data), flags } if blob.is_encrypted() => {
                 let (ciphertext, iv, tag) = aes_gcm_encrypt(&data, key).unwrap();
@@ -1453,7 +1452,8 @@
         }
     }
 
-    struct LegacyBlobHeader {
+    /// Legacy blob header structure.
+    pub struct LegacyBlobHeader {
         version: u8,
         blob_type: u8,
         flags: u8,
@@ -1467,7 +1467,7 @@
     /// version 3. Note that the flags field and the values field may be
     /// inconsistent and could be sanitized by this function. It is intentionally
     /// not done to enable tests to construct malformed blobs.
-    fn write_legacy_blob(out: &mut dyn Write, blob: Blob) -> Result<usize> {
+    pub fn write_legacy_blob(out: &mut dyn Write, blob: Blob) -> Result<usize> {
         let (header, data, salt) = match blob {
             Blob { value: BlobValue::Generic(data), flags } => (
                 LegacyBlobHeader {
@@ -1581,7 +1581,9 @@
         write_legacy_blob_helper(out, &header, &data, salt.as_deref())
     }
 
-    fn write_legacy_blob_helper(
+    /// This function takes LegacyBlobHeader, blob payload and writes it to out as a legacy blob file
+    /// version 3.
+    pub fn write_legacy_blob_helper(
         out: &mut dyn Write,
         header: &LegacyBlobHeader,
         data: &[u8],
@@ -1622,10 +1624,51 @@
         Ok(40 + data.len() + info.map(|v| v.len()).unwrap_or(0))
     }
 
-    fn make_encrypted_characteristics_file<P: AsRef<Path>>(path: P, key: &[u8]) -> Result<()> {
+    /// Create encrypted characteristics file using given key.
+    pub fn make_encrypted_characteristics_file<P: AsRef<Path>>(
+        path: P,
+        key: &[u8],
+        data: &[u8],
+    ) -> Result<()> {
+        let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
+        let blob =
+            Blob { value: BlobValue::Characteristics(data.to_vec()), flags: flags::ENCRYPTED };
+        let blob = prepare_blob(blob, key).unwrap();
+        write_legacy_blob(&mut file, blob).unwrap();
+        Ok(())
+    }
+
+    /// Create encrypted user certificate file using given key.
+    pub fn make_encrypted_usr_cert_file<P: AsRef<Path>>(
+        path: P,
+        key: &[u8],
+        data: &[u8],
+    ) -> Result<()> {
+        let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
+        let blob = Blob { value: BlobValue::Generic(data.to_vec()), flags: flags::ENCRYPTED };
+        let blob = prepare_blob(blob, key).unwrap();
+        write_legacy_blob(&mut file, blob).unwrap();
+        Ok(())
+    }
+
+    /// Create encrypted CA certificate file using given key.
+    pub fn make_encrypted_ca_cert_file<P: AsRef<Path>>(
+        path: P,
+        key: &[u8],
+        data: &[u8],
+    ) -> Result<()> {
+        let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
+        let blob = Blob { value: BlobValue::Generic(data.to_vec()), flags: flags::ENCRYPTED };
+        let blob = prepare_blob(blob, key).unwrap();
+        write_legacy_blob(&mut file, blob).unwrap();
+        Ok(())
+    }
+
+    /// Create encrypted user key file using given key.
+    pub fn make_encrypted_key_file<P: AsRef<Path>>(path: P, key: &[u8], data: &[u8]) -> Result<()> {
         let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
         let blob = Blob {
-            value: BlobValue::Characteristics(KEY_PARAMETERS.to_vec()),
+            value: BlobValue::Decrypted(ZVec::try_from(data).unwrap()),
             flags: flags::ENCRYPTED,
         };
         let blob = prepare_blob(blob, key).unwrap();
@@ -1633,27 +1676,29 @@
         Ok(())
     }
 
-    fn make_encrypted_usr_cert_file<P: AsRef<Path>>(path: P, key: &[u8]) -> Result<()> {
+    /// Create user or ca cert blob file.
+    pub fn make_cert_blob_file<P: AsRef<Path>>(path: P, data: &[u8]) -> Result<()> {
         let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
-        let blob = Blob {
-            value: BlobValue::Generic(LOADED_CERT_AUTHBOUND.to_vec()),
-            flags: flags::ENCRYPTED,
-        };
-        let blob = prepare_blob(blob, key).unwrap();
+        let blob = Blob { value: BlobValue::Generic(data.to_vec()), flags: 0 };
+        let blob = prepare_blob(blob, &[]).unwrap();
         write_legacy_blob(&mut file, blob).unwrap();
         Ok(())
     }
+}
 
-    fn make_encrypted_ca_cert_file<P: AsRef<Path>>(path: P, key: &[u8]) -> Result<()> {
-        let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
-        let blob = Blob {
-            value: BlobValue::Generic(LOADED_CACERT_AUTHBOUND.to_vec()),
-            flags: flags::ENCRYPTED,
-        };
-        let blob = prepare_blob(blob, key).unwrap();
-        write_legacy_blob(&mut file, blob).unwrap();
-        Ok(())
-    }
+#[cfg(test)]
+mod test {
+    #![allow(dead_code)]
+    use super::*;
+    use crate::legacy_blob::test_utils::legacy_blob_test_vectors::*;
+    use crate::legacy_blob::test_utils::*;
+    use anyhow::{anyhow, Result};
+    use keystore2_crypto::aes_gcm_decrypt;
+    use keystore2_test_utils::TempDir;
+    use rand::Rng;
+    use std::convert::TryInto;
+    use std::ops::Deref;
+    use std::string::FromUtf8Error;
 
     #[test]
     fn decode_encode_alias_test() {
@@ -1962,6 +2007,7 @@
         make_encrypted_characteristics_file(
             &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
             &super_key,
+            KEY_PARAMETERS,
         )
         .unwrap();
         std::fs::write(
@@ -2053,11 +2099,13 @@
         make_encrypted_usr_cert_file(
             &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
             &super_key,
+            LOADED_CERT_AUTHBOUND,
         )
         .unwrap();
         make_encrypted_ca_cert_file(
             &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
             &super_key,
+            LOADED_CACERT_AUTHBOUND,
         )
         .unwrap();
 
@@ -2139,11 +2187,13 @@
         make_encrypted_usr_cert_file(
             &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
             &super_key,
+            LOADED_CERT_AUTHBOUND,
         )
         .unwrap();
         make_encrypted_ca_cert_file(
             &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
             &super_key,
+            LOADED_CACERT_AUTHBOUND,
         )
         .unwrap();
 
diff --git a/keystore2/src/legacy_blob/test/legacy_blob_test_vectors.rs b/keystore2/src/legacy_blob/test_utils/legacy_blob_test_vectors.rs
similarity index 98%
rename from keystore2/src/legacy_blob/test/legacy_blob_test_vectors.rs
rename to keystore2/src/legacy_blob/test_utils/legacy_blob_test_vectors.rs
index 2049ac2..3eecee0 100644
--- a/keystore2/src/legacy_blob/test/legacy_blob_test_vectors.rs
+++ b/keystore2/src/legacy_blob/test_utils/legacy_blob_test_vectors.rs
@@ -20,6 +20,7 @@
     KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
 };
 
+/// Holds Blob structure.
 pub static BLOB: &[u8] = &[
     3, // version
     1, // type
@@ -31,6 +32,7 @@
     0xde, 0xed, 0xbe, 0xef, // payload
 ];
 
+/// Creates LegacyKeyCharacteristics with security level KEYSTORE.
 pub fn structured_test_params() -> LegacyKeyCharacteristics {
     LegacyKeyCharacteristics::File(vec![
         KeyParameter::new(KeyParameterValue::KeyPurpose(KeyPurpose::SIGN), SecurityLevel::KEYSTORE),
@@ -61,6 +63,7 @@
     ])
 }
 
+/// Creates LegacyKeyCharacteristics with security level TRUSTED_ENVIRONMENT.
 pub fn structured_test_params_cache() -> LegacyKeyCharacteristics {
     LegacyKeyCharacteristics::Cache(vec![
         KeyParameter::new(
@@ -117,7 +120,7 @@
     ])
 }
 
-// One encoded list of key parameters.
+/// One encoded list of key parameters.
 pub static KEY_PARAMETERS: &[u8] = &[
     0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x20,
     0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x20,
@@ -130,6 +133,7 @@
     0x30, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
 ];
 
+/// Real legacy blob.
 pub static REAL_LEGACY_BLOB: &[u8] = &[
     0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -161,6 +165,7 @@
     0xda, 0x40, 0x2b, 0x75, 0xd0, 0xd2, 0x81, 0x7f, 0xe2, 0x2b, 0xef, 0x64,
 ];
 
+/// Real legacy blob payload.
 pub static REAL_LEGACY_BLOB_PAYLOAD: &[u8] = &[
     0x6c, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x25, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x72, 0x00, 0x00,
     0x00, 0x06, 0x00, 0x80, 0x00, 0x43, 0x00, 0x20, 0x85, 0x42, 0x9e, 0xe9, 0x34, 0x85, 0x2a, 0x00,
@@ -190,11 +195,13 @@
     0xe2, 0x2b, 0xef, 0x64,
 ];
 
+/// AES key blob.
 pub static AES_KEY: &[u8] = &[
     0x48, 0xe4, 0xb5, 0xff, 0xcd, 0x9c, 0x41, 0x1e, 0x20, 0x41, 0xf2, 0x65, 0xa0, 0x4f, 0xf6, 0x57,
     0xc6, 0x58, 0xca, 0xbf, 0x28, 0xa3, 0x01, 0x98, 0x01, 0x76, 0x10, 0xc0, 0x30, 0x4e, 0x35, 0x6e,
 ];
 
+/// AES-GCM encrypted blob.
 pub static AES_GCM_ENCRYPTED_BLOB: &[u8] = &[
     0x03, 0x04, 0x04, 0x00, 0xbd, 0xdb, 0x8d, 0x69, 0x72, 0x56, 0xf0, 0xf5, 0xa4, 0x02, 0x88, 0x7f,
     0x00, 0x00, 0x00, 0x00, 0x50, 0xd9, 0x97, 0x95, 0x37, 0x6e, 0x28, 0x6a, 0x28, 0x9d, 0x51, 0xb9,
@@ -227,6 +234,7 @@
     0x2e, 0x0c, 0xc7, 0xbf, 0x29, 0x1e, 0x31, 0xdc, 0x0e, 0x85, 0x96, 0x7b,
 ];
 
+/// Decrypted payload.
 pub static DECRYPTED_PAYLOAD: &[u8] = &[
     0x7c, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x25, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x72, 0x00, 0x00,
     0x00, 0x06, 0x00, 0x80, 0x00, 0x43, 0x00, 0x20, 0xa4, 0xee, 0xdc, 0x1f, 0x9e, 0xba, 0x42, 0xd6,
@@ -257,6 +265,7 @@
     0xf6, 0x0b, 0x81, 0x07,
 ];
 
+/// Password blob.
 pub static PASSWORD: &[u8] = &[
     0x42, 0x39, 0x30, 0x37, 0x44, 0x37, 0x32, 0x37, 0x39, 0x39, 0x43, 0x42, 0x39, 0x41, 0x42, 0x30,
     0x34, 0x31, 0x30, 0x38, 0x46, 0x44, 0x33, 0x45, 0x39, 0x42, 0x32, 0x38, 0x36, 0x35, 0x41, 0x36,
@@ -264,6 +273,7 @@
     0x32, 0x45, 0x31, 0x35, 0x43, 0x43, 0x46, 0x32, 0x39, 0x36, 0x33, 0x34, 0x31, 0x32, 0x41, 0x39,
 ];
 
+/// Super key blob.
 pub static SUPERKEY: &[u8] = &[
     0x03, 0x07, 0x01, 0x10, 0x9a, 0x81, 0x56, 0x7d, 0xf5, 0x86, 0x7c, 0x62, 0xd7, 0xf9, 0x26, 0x06,
     0x00, 0x00, 0x00, 0x00, 0xde, 0x2a, 0xcb, 0xac, 0x98, 0x57, 0x2b, 0xe5, 0x57, 0x18, 0x78, 0x57,
@@ -273,23 +283,28 @@
     0x94, 0xb6, 0x67, 0x7b, 0x39, 0x85, 0x28, 0x11,
 ];
 
+/// Super key IV.
 pub static SUPERKEY_IV: &[u8] = &[
     0x9a, 0x81, 0x56, 0x7d, 0xf5, 0x86, 0x7c, 0x62, 0xd7, 0xf9, 0x26, 0x06, 0x00, 0x00, 0x00, 0x00,
 ];
 
+/// Super key tag.
 pub static SUPERKEY_TAG: &[u8] = &[
     0xde, 0x2a, 0xcb, 0xac, 0x98, 0x57, 0x2b, 0xe5, 0x57, 0x18, 0x78, 0x57, 0x6e, 0x10, 0x09, 0x84,
 ];
 
+/// Super key salt.
 pub static SUPERKEY_SALT: &[u8] = &[
     0x04, 0x5b, 0xb4, 0x8a, 0x09, 0x22, 0x13, 0x0c, 0x94, 0xb6, 0x67, 0x7b, 0x39, 0x85, 0x28, 0x11,
 ];
 
+/// Super key payload.
 pub static SUPERKEY_PAYLOAD: &[u8] = &[
     0xac, 0x6d, 0x13, 0xe6, 0xad, 0x2c, 0x89, 0x53, 0x1a, 0x99, 0xa5, 0x6c, 0x88, 0xe9, 0xeb, 0x5c,
     0xef, 0x68, 0x5e, 0x5b, 0x53, 0xa8, 0xe7, 0xa2, 0x76, 0x04, 0x2a, 0x48, 0xd1, 0xa7, 0x59, 0xd1,
 ];
 
+/// user key blob.
 pub static USRPKEY_AUTHBOUND: &[u8] = &[
     0x03, 0x04, 0x04, 0x00, 0x1c, 0x34, 0x87, 0x6f, 0xc8, 0x35, 0x0d, 0x34, 0x88, 0x59, 0xbc, 0xf5,
     0x00, 0x00, 0x00, 0x00, 0x62, 0xe3, 0x38, 0x2d, 0xd0, 0x58, 0x40, 0xc1, 0xb0, 0xf2, 0x4a, 0xdd,
@@ -330,14 +345,17 @@
     0x83, 0x42, 0xdd, 0x4e, 0x6d,
 ];
 
+/// Authbound IV.
 pub static USRPKEY_AUTHBOUND_IV: &[u8] = &[
     0x1c, 0x34, 0x87, 0x6f, 0xc8, 0x35, 0x0d, 0x34, 0x88, 0x59, 0xbc, 0xf5, 0x00, 0x00, 0x00, 0x00,
 ];
 
+/// Authbond IV Tag.
 pub static USRPKEY_AUTHBOUND_TAG: &[u8] = &[
     0x62, 0xe3, 0x38, 0x2d, 0xd0, 0x58, 0x40, 0xc1, 0xb0, 0xf2, 0x4a, 0xdd, 0xf7, 0x81, 0x67, 0x0b,
 ];
 
+/// Encrypted use key payload.
 pub static USRPKEY_AUTHBOUND_ENC_PAYLOAD: &[u8] = &[
     0x05, 0xb2, 0x5a, 0x1d, 0x1b, 0x25, 0x19, 0x48, 0xbf, 0x76, 0x0b, 0x37, 0x8c, 0x60, 0x52, 0xea,
     0x30, 0x2a, 0x2c, 0x89, 0x99, 0x95, 0x57, 0x5c, 0xec, 0x62, 0x3c, 0x08, 0x1a, 0xc6, 0x65, 0xf9,
@@ -375,6 +393,7 @@
     0x73, 0x08, 0x50, 0xb2, 0x19, 0xe8, 0x23, 0x1b, 0x83, 0x42, 0xdd, 0x4e, 0x6d,
 ];
 
+/// User key characterstics blob.
 pub static USRPKEY_AUTHBOUND_CHR: &[u8] = &[
     0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -390,6 +409,8 @@
     0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xbd, 0x02, 0x00, 0x60,
     0x10, 0x9d, 0x8b, 0x31, 0x76, 0x01, 0x00, 0x00, 0xf5, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
 ];
+
+/// User certificate blob.
 pub static USRCERT_AUTHBOUND: &[u8] = &[
     0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -436,6 +457,8 @@
     0x39, 0x58, 0xe9, 0x89, 0x1a, 0x14, 0x41, 0x8d, 0xe0, 0xdc, 0x3d, 0x88, 0xf4, 0x2c, 0x7c, 0xda,
     0xa1, 0x84, 0xfa, 0x7f, 0xf9, 0x07, 0x97, 0xfb, 0xb5, 0xb7, 0x28, 0x28, 0x00, 0x7c, 0xa7,
 ];
+
+/// CA certificate blob.
 pub static CACERT_AUTHBOUND: &[u8] = &[
     0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -624,6 +647,7 @@
     0xab, 0xae, 0x24, 0xe2, 0x44, 0x35, 0x16, 0x8d, 0x55, 0x3c, 0xe4,
 ];
 
+/// User non-authbond-key blob.
 pub static USRPKEY_NON_AUTHBOUND: &[u8] = &[
     0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -663,6 +687,8 @@
     0x46, 0xf0, 0xee, 0x50, 0x73, 0x6a, 0x7b, 0xa3, 0xe9, 0xb1, 0x08, 0x81, 0x00, 0xdf, 0x0e, 0xc9,
     0xc3, 0x2c, 0x13, 0x64, 0xa1,
 ];
+
+/// User non-authbond-key characteristics blob.
 pub static USRPKEY_NON_AUTHBOUND_CHR: &[u8] = &[
     0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -678,6 +704,7 @@
     0x60, 0x60, 0x60, 0x8c, 0x31, 0x76, 0x01, 0x00, 0x00, 0xf5, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00,
     0x00,
 ];
+/// User non-authbond-key certificate blob.
 pub static USRCERT_NON_AUTHBOUND: &[u8] = &[
     0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -725,6 +752,7 @@
     0xd8, 0xd5, 0xd1, 0x64, 0x4c, 0x05, 0xdd, 0x13, 0x0e, 0xa4, 0xf3, 0x38, 0xbf, 0x18, 0xd5,
 ];
 
+/// User non-authbond-key ca-certs blob.
 pub static CACERT_NON_AUTHBOUND: &[u8] = &[
     0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -913,6 +941,7 @@
     0xab, 0xae, 0x24, 0xe2, 0x44, 0x35, 0x16, 0x8d, 0x55, 0x3c, 0xe4,
 ];
 
+/// User decrypted authbond-key blob.
 pub static _DECRYPTED_USRPKEY_AUTHBOUND: &[u8] = &[
     0x44, 0x4b, 0x4d, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
     0xc6, 0x15, 0x3a, 0x08, 0x1e, 0x43, 0xba, 0x7a, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
@@ -950,6 +979,7 @@
     0x60, 0x5e, 0xcd, 0xce, 0x3a, 0xd8, 0x09, 0xeb, 0x9d, 0x40, 0xdb, 0x58, 0x53,
 ];
 
+/// User loaded authbond certs blob.
 pub static LOADED_CERT_AUTHBOUND: &[u8] = &[
     0x30, 0x82, 0x02, 0x93, 0x30, 0x82, 0x02, 0x3A, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01,
     0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x29, 0x31, 0x19,
@@ -994,6 +1024,8 @@
     0xE0, 0xDC, 0x3D, 0x88, 0xF4, 0x2C, 0x7C, 0xDA, 0xA1, 0x84, 0xFA, 0x7F, 0xF9, 0x07, 0x97, 0xFB,
     0xB5, 0xB7, 0x28, 0x28, 0x00, 0x7C, 0xA7,
 ];
+
+/// User loaded authbond ca-certs blob.
 pub static LOADED_CACERT_AUTHBOUND: &[u8] = &[
     0x30, 0x82, 0x02, 0x26, 0x30, 0x82, 0x01, 0xAB, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0A, 0x05,
     0x84, 0x20, 0x26, 0x90, 0x76, 0x23, 0x58, 0x71, 0x77, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48,
@@ -1180,6 +1212,7 @@
     0x55, 0x3C, 0xE4,
 ];
 
+/// User loaded non-authbond user key blob.
 pub static LOADED_USRPKEY_NON_AUTHBOUND: &[u8] = &[
     0x44, 0x4b, 0x4d, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
     0x8a, 0xc1, 0x08, 0x13, 0x7c, 0x47, 0xba, 0x09, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
@@ -1217,6 +1250,7 @@
     0xe9, 0xb1, 0x08, 0x81, 0x00, 0xdf, 0x0e, 0xc9, 0xc3, 0x2c, 0x13, 0x64, 0xa1,
 ];
 
+/// User loaded non-authbond certificate blob.
 pub static LOADED_CERT_NON_AUTHBOUND: &[u8] = &[
     0x30, 0x82, 0x02, 0x93, 0x30, 0x82, 0x02, 0x39, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01,
     0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x29, 0x31, 0x19,
@@ -1262,6 +1296,7 @@
     0x0e, 0xa4, 0xf3, 0x38, 0xbf, 0x18, 0xd5,
 ];
 
+/// User loaded non-authbond ca-certificates blob.
 pub static LOADED_CACERT_NON_AUTHBOUND: &[u8] = &[
     0x30, 0x82, 0x02, 0x26, 0x30, 0x82, 0x01, 0xab, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x05,
     0x84, 0x20, 0x26, 0x90, 0x76, 0x23, 0x58, 0x71, 0x77, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
diff --git a/keystore2/test_utils/run_as.rs b/keystore2/test_utils/run_as.rs
index d42303d..2485ab5 100644
--- a/keystore2/test_utils/run_as.rs
+++ b/keystore2/test_utils/run_as.rs
@@ -30,9 +30,11 @@
 use nix::sys::wait::{waitpid, WaitStatus};
 use nix::unistd::{
     close, fork, pipe as nix_pipe, read as nix_read, setgid, setuid, write as nix_write,
-    ForkResult, Gid, Uid,
+    ForkResult, Gid, Pid, Uid,
 };
 use serde::{de::DeserializeOwned, Serialize};
+use std::io::{Read, Write};
+use std::marker::PhantomData;
 use std::os::unix::io::RawFd;
 
 fn transition(se_context: selinux::Context, uid: Uid, gid: Gid) {
@@ -48,17 +50,10 @@
 /// reads from the pipe into an expending vector, until no more data can be read.
 struct PipeReader(RawFd);
 
-impl PipeReader {
-    pub fn read_all(&self) -> Result<Vec<u8>, nix::Error> {
-        let mut buffer = [0u8; 128];
-        let mut result = Vec::<u8>::new();
-        loop {
-            let bytes = nix_read(self.0, &mut buffer)?;
-            if bytes == 0 {
-                return Ok(result);
-            }
-            result.extend_from_slice(&buffer[0..bytes]);
-        }
+impl Read for PipeReader {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        let bytes = nix_read(self.0, buf)?;
+        Ok(bytes)
     }
 }
 
@@ -73,46 +68,264 @@
 /// writes the given buffer into the pipe, returning the number of bytes written.
 struct PipeWriter(RawFd);
 
-impl PipeWriter {
-    pub fn write(&self, data: &[u8]) -> Result<usize, nix::Error> {
-        nix_write(self.0, data)
-    }
-}
-
 impl Drop for PipeWriter {
     fn drop(&mut self) {
         close(self.0).expect("Failed to close writer pipe fd.");
     }
 }
 
+impl Write for PipeWriter {
+    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+        let written = nix_write(self.0, buf)?;
+        Ok(written)
+    }
+
+    fn flush(&mut self) -> std::io::Result<()> {
+        // Flush is a NO-OP.
+        Ok(())
+    }
+}
+
+/// Denotes the sender side of a serializing channel.
+pub struct ChannelWriter<T: Serialize + DeserializeOwned>(PipeWriter, PhantomData<T>);
+
+impl<T: Serialize + DeserializeOwned> ChannelWriter<T> {
+    /// Sends a serializable object to a the corresponding ChannelReader.
+    /// Sending is always non blocking. Panics if any error occurs during io or serialization.
+    pub fn send(&mut self, value: &T) {
+        let serialized = serde_cbor::to_vec(value)
+            .expect("In ChannelWriter::send: Failed to serialize to vector.");
+        let size = serialized.len().to_be_bytes();
+        match self.0.write(&size).expect("In ChannelWriter::send: Failed to write serialized size.")
+        {
+            w if w != std::mem::size_of::<usize>() => {
+                panic!(
+                    "In ChannelWriter::send: Failed to write serialized size. (written: {}).",
+                    w
+                );
+            }
+            _ => {}
+        };
+        match self
+            .0
+            .write(&serialized)
+            .expect("In ChannelWriter::send: Failed to write serialized data.")
+        {
+            w if w != serialized.len() => {
+                panic!(
+                    "In ChannelWriter::send: Failed to write serialized data. (written: {}).",
+                    w
+                );
+            }
+            _ => {}
+        };
+    }
+}
+
+/// Represents the receiving and of a serializing channel.
+pub struct ChannelReader<T>(PipeReader, PhantomData<T>);
+
+impl<T: Serialize + DeserializeOwned> ChannelReader<T> {
+    /// Receives a serializable object from the corresponding ChannelWriter.
+    /// Receiving blocks until an object of type T has been read from the channel.
+    /// Panics if an error occurs during io or deserialization.
+    pub fn recv(&mut self) -> T {
+        let mut size_buffer = [0u8; std::mem::size_of::<usize>()];
+        match self.0.read(&mut size_buffer).expect("In ChannelReader::recv: Failed to read size.") {
+            r if r != size_buffer.len() => {
+                panic!("In ChannelReader::recv: Failed to read size. Insufficient data: {}", r);
+            }
+            _ => {}
+        };
+        let size = usize::from_be_bytes(size_buffer);
+        let mut data_buffer = vec![0u8; size];
+        match self
+            .0
+            .read(&mut data_buffer)
+            .expect("In ChannelReader::recv: Failed to read serialized data.")
+        {
+            r if r != data_buffer.len() => {
+                panic!(
+                    "In ChannelReader::recv: Failed to read serialized data. Insufficient data: {}",
+                    r
+                );
+            }
+            _ => {}
+        };
+
+        serde_cbor::from_slice(&data_buffer)
+            .expect("In ChannelReader::recv: Failed to deserialize data.")
+    }
+}
+
 fn pipe() -> Result<(PipeReader, PipeWriter), nix::Error> {
     let (read_fd, write_fd) = nix_pipe()?;
     Ok((PipeReader(read_fd), PipeWriter(write_fd)))
 }
 
+fn pipe_channel<T>() -> Result<(ChannelReader<T>, ChannelWriter<T>), nix::Error>
+where
+    T: Serialize + DeserializeOwned,
+{
+    let (reader, writer) = pipe()?;
+    Ok((
+        ChannelReader::<T>(reader, Default::default()),
+        ChannelWriter::<T>(writer, Default::default()),
+    ))
+}
+
+/// Handle for handling child processes.
+pub struct ChildHandle<R: Serialize + DeserializeOwned, M: Serialize + DeserializeOwned> {
+    pid: Pid,
+    result_reader: ChannelReader<R>,
+    cmd_writer: ChannelWriter<M>,
+    response_reader: ChannelReader<M>,
+    exit_status: Option<WaitStatus>,
+}
+
+impl<R: Serialize + DeserializeOwned, M: Serialize + DeserializeOwned> ChildHandle<R, M> {
+    /// Send a command message to the child.
+    pub fn send(&mut self, data: &M) {
+        self.cmd_writer.send(data)
+    }
+
+    /// Receive a response from the child.
+    pub fn recv(&mut self) -> M {
+        self.response_reader.recv()
+    }
+
+    /// Get child result. Panics if the child did not exit with status 0 or if a serialization
+    /// error occurred.
+    pub fn get_result(mut self) -> R {
+        let status =
+            waitpid(self.pid, None).expect("ChildHandle::wait: Failed while waiting for child.");
+        match status {
+            WaitStatus::Exited(pid, 0) => {
+                // Child exited successfully.
+                // Read the result from the pipe.
+                self.exit_status = Some(WaitStatus::Exited(pid, 0));
+                self.result_reader.recv()
+            }
+            WaitStatus::Exited(pid, c) => {
+                panic!("Child did not exit as expected: {:?}", WaitStatus::Exited(pid, c));
+            }
+            status => {
+                panic!("Child did not exit at all: {:?}", status);
+            }
+        }
+    }
+}
+
+impl<R: Serialize + DeserializeOwned, M: Serialize + DeserializeOwned> Drop for ChildHandle<R, M> {
+    fn drop(&mut self) {
+        if self.exit_status.is_none() {
+            panic!("Child result not checked.")
+        }
+    }
+}
+
+/// Run the given closure in a new process running with the new identity given as
+/// `uid`, `gid`, and `se_context`. Parent process will run without waiting for child status.
+///
+/// # Safety
+/// run_as_child runs the given closure in the client branch of fork. And it uses non
+/// async signal safe API. This means that calling this function in a multi threaded program
+/// yields undefined behavior in the child. As of this writing, it is safe to call this function
+/// from a Rust device test, because every test itself is spawned as a separate process.
+///
+/// # Safety Binder
+/// It is okay for the closure to use binder services, however, this does not work
+/// if the parent initialized libbinder already. So do not use binder outside of the closure
+/// in your test.
+pub unsafe fn run_as_child<F, R, M>(
+    se_context: &str,
+    uid: Uid,
+    gid: Gid,
+    f: F,
+) -> Result<ChildHandle<R, M>, nix::Error>
+where
+    R: Serialize + DeserializeOwned,
+    M: Serialize + DeserializeOwned,
+    F: 'static + Send + FnOnce(&mut ChannelReader<M>, &mut ChannelWriter<M>) -> R,
+{
+    let se_context =
+        selinux::Context::new(se_context).expect("Unable to construct selinux::Context.");
+    let (result_reader, mut result_writer) = pipe_channel().expect("Failed to create pipe.");
+    let (mut cmd_reader, cmd_writer) = pipe_channel().expect("Failed to create cmd pipe.");
+    let (response_reader, mut response_writer) =
+        pipe_channel().expect("Failed to create cmd pipe.");
+
+    match fork() {
+        Ok(ForkResult::Parent { child, .. }) => {
+            drop(response_writer);
+            drop(cmd_reader);
+            drop(result_writer);
+
+            Ok(ChildHandle::<R, M> {
+                pid: child,
+                result_reader,
+                response_reader,
+                cmd_writer,
+                exit_status: None,
+            })
+        }
+        Ok(ForkResult::Child) => {
+            drop(cmd_writer);
+            drop(response_reader);
+            drop(result_reader);
+
+            // This will panic on error or insufficient privileges.
+            transition(se_context, uid, gid);
+
+            // Run the closure.
+            let result = f(&mut cmd_reader, &mut response_writer);
+
+            // Serialize the result of the closure.
+            result_writer.send(&result);
+
+            // Set exit status to `0`.
+            std::process::exit(0);
+        }
+        Err(errno) => {
+            panic!("Failed to fork: {:?}", errno);
+        }
+    }
+}
+
 /// Run the given closure in a new process running with the new identity given as
 /// `uid`, `gid`, and `se_context`.
-pub fn run_as<F, R>(se_context: &str, uid: Uid, gid: Gid, f: F) -> R
+///
+/// # Safety
+/// run_as runs the given closure in the client branch of fork. And it uses non
+/// async signal safe API. This means that calling this function in a multi threaded program
+/// yields undefined behavior in the child. As of this writing, it is safe to call this function
+/// from a Rust device test, because every test itself is spawned as a separate process.
+///
+/// # Safety Binder
+/// It is okay for the closure to use binder services, however, this does not work
+/// if the parent initialized libbinder already. So do not use binder outside of the closure
+/// in your test.
+pub unsafe fn run_as<F, R>(se_context: &str, uid: Uid, gid: Gid, f: F) -> R
 where
     R: Serialize + DeserializeOwned,
     F: 'static + Send + FnOnce() -> R,
 {
     let se_context =
         selinux::Context::new(se_context).expect("Unable to construct selinux::Context.");
-    let (reader, writer) = pipe().expect("Failed to create pipe.");
+    let (mut reader, mut writer) = pipe_channel::<R>().expect("Failed to create pipe.");
 
-    match unsafe { fork() } {
+    match fork() {
         Ok(ForkResult::Parent { child, .. }) => {
             drop(writer);
             let status = waitpid(child, None).expect("Failed while waiting for child.");
             if let WaitStatus::Exited(_, 0) = status {
                 // Child exited successfully.
                 // Read the result from the pipe.
-                let serialized_result =
-                    reader.read_all().expect("Failed to read result from child.");
+                // let serialized_result =
+                //     reader.read_all().expect("Failed to read result from child.");
 
                 // Deserialize the result and return it.
-                serde_cbor::from_slice(&serialized_result).expect("Failed to deserialize result.")
+                reader.recv()
             } else {
                 panic!("Child did not exit as expected {:?}", status);
             }
@@ -125,10 +338,7 @@
             let result = f();
 
             // Serialize the result of the closure.
-            let vec = serde_cbor::to_vec(&result).expect("Result serialization failed");
-
-            // Send the result to the parent using the pipe.
-            writer.write(&vec).expect("Failed to send serialized result to parent.");
+            writer.send(&result);
 
             // Set exit status to `0`.
             std::process::exit(0);
@@ -151,9 +361,13 @@
     #[test]
     #[should_panic]
     fn test_run_as_panics_on_closure_panic() {
-        run_as(selinux::getcon().unwrap().to_str().unwrap(), getuid(), getgid(), || {
-            panic!("Closure must panic.")
-        });
+        // Safety: run_as must be called from a single threaded process.
+        // This device test is run as a separate single threaded process.
+        unsafe {
+            run_as(selinux::getcon().unwrap().to_str().unwrap(), getuid(), getgid(), || {
+                panic!("Closure must panic.")
+            })
+        };
     }
 
     static TARGET_UID: Uid = Uid::from_raw(10020);
@@ -163,11 +377,15 @@
     /// Tests that the closure is running as the target identity.
     #[test]
     fn test_transition_to_untrusted_app() {
-        run_as(TARGET_CTX, TARGET_UID, TARGET_GID, || {
-            assert_eq!(TARGET_UID, getuid());
-            assert_eq!(TARGET_GID, getgid());
-            assert_eq!(TARGET_CTX, selinux::getcon().unwrap().to_str().unwrap());
-        });
+        // Safety: run_as must be called from a single threaded process.
+        // This device test is run as a separate single threaded process.
+        unsafe {
+            run_as(TARGET_CTX, TARGET_UID, TARGET_GID, || {
+                assert_eq!(TARGET_UID, getuid());
+                assert_eq!(TARGET_GID, getgid());
+                assert_eq!(TARGET_CTX, selinux::getcon().unwrap().to_str().unwrap());
+            })
+        };
     }
 
     #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
@@ -185,7 +403,72 @@
             c: "supercalifragilisticexpialidocious".to_owned(),
         };
         let test_result_clone = test_result.clone();
-        let result = run_as(TARGET_CTX, TARGET_UID, TARGET_GID, || test_result_clone);
+        // Safety: run_as must be called from a single threaded process.
+        // This device test is run as a separate single threaded process.
+        let result = unsafe { run_as(TARGET_CTX, TARGET_UID, TARGET_GID, || test_result_clone) };
         assert_eq!(test_result, result);
     }
+
+    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+    enum PingPong {
+        Ping,
+        Pong,
+    }
+
+    /// Tests that closure is running under given user identity and communicates with calling
+    /// process using pipe.
+    #[test]
+    fn test_run_as_child() {
+        let test_result = SomeResult {
+            a: 5,
+            b: 0xffffffffffffffff,
+            c: "supercalifragilisticexpialidocious".to_owned(),
+        };
+        let test_result_clone = test_result.clone();
+
+        // Safety: run_as_child must be called from a single threaded process.
+        // This device test is run as a separate single threaded process.
+        let mut child_handle: ChildHandle<SomeResult, PingPong> = unsafe {
+            run_as_child(TARGET_CTX, TARGET_UID, TARGET_GID, |cmd_reader, response_writer| {
+                assert_eq!(TARGET_UID, getuid());
+                assert_eq!(TARGET_GID, getgid());
+                assert_eq!(TARGET_CTX, selinux::getcon().unwrap().to_str().unwrap());
+
+                let ping: PingPong = cmd_reader.recv();
+                assert_eq!(ping, PingPong::Ping);
+
+                response_writer.send(&PingPong::Pong);
+
+                let ping: PingPong = cmd_reader.recv();
+                assert_eq!(ping, PingPong::Ping);
+                let pong: PingPong = cmd_reader.recv();
+                assert_eq!(pong, PingPong::Pong);
+
+                response_writer.send(&PingPong::Pong);
+                response_writer.send(&PingPong::Ping);
+
+                test_result_clone
+            })
+            .unwrap()
+        };
+
+        // Send one ping.
+        child_handle.send(&PingPong::Ping);
+
+        // Expect one pong.
+        let pong = child_handle.recv();
+        assert_eq!(pong, PingPong::Pong);
+
+        // Send ping and pong.
+        child_handle.send(&PingPong::Ping);
+        child_handle.send(&PingPong::Pong);
+
+        // Expect pong and ping.
+        let pong = child_handle.recv();
+        assert_eq!(pong, PingPong::Pong);
+        let ping = child_handle.recv();
+        assert_eq!(ping, PingPong::Ping);
+
+        assert_eq!(child_handle.get_result(), test_result);
+    }
 }