Merge "identity: Add multi-document presentation support."
diff --git a/diced/Android.bp b/diced/Android.bp
new file mode 100644
index 0000000..db0268c
--- /dev/null
+++ b/diced/Android.bp
@@ -0,0 +1,209 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "system_security_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_security_license"],
+}
+
+rust_library {
+ name: "libdiced_utils",
+ crate_name: "diced_utils",
+ srcs: ["src/utils.rs"],
+ vendor_available: true,
+
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "libanyhow",
+ "libdiced_open_dice_cbor",
+ "libkeystore2_crypto_rust",
+ ],
+}
+
+rust_test {
+ name: "diced_utils_test",
+ crate_name: "diced_utils_test",
+ srcs: ["src/utils.rs"],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "libanyhow",
+ "libdiced_open_dice_cbor",
+ "libkeystore2_crypto_rust",
+ ],
+}
+
+rust_library {
+ name: "libdiced_sample_inputs",
+ crate_name: "diced_sample_inputs",
+ srcs: ["src/sample_inputs.rs"],
+ vendor_available: true,
+
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "libanyhow",
+ "libdiced_open_dice_cbor",
+ "libdiced_utils",
+ "libkeystore2_crypto_rust",
+ ],
+}
+
+rust_test {
+ name: "diced_sample_inputs_test",
+ crate_name: "diced_sample_inputs_test",
+ srcs: ["src/sample_inputs.rs"],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "libanyhow",
+ "libdiced_open_dice_cbor",
+ "libdiced_utils",
+ "libkeystore2_crypto_rust",
+ ],
+}
+
+rust_library {
+ name: "libdiced",
+ crate_name: "diced",
+ srcs: ["src/lib.rs"],
+
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "android.security.dice-rust",
+ "libdiced_open_dice_cbor",
+ "libanyhow",
+ "libbinder_rs",
+ "libdiced_utils",
+ "libkeystore2_crypto_rust",
+ "libkeystore2_selinux",
+ "liblibc",
+ "liblog_rust",
+ "libthiserror",
+ ],
+}
+
+rust_library {
+ name: "libdiced_vendor",
+ crate_name: "diced",
+ srcs: ["src/lib_vendor.rs"],
+
+ vendor_available: true,
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "libdiced_open_dice_cbor",
+ "libanyhow",
+ "libbinder_rs",
+ "libdiced_utils",
+ "libkeystore2_crypto_rust",
+ "liblibc",
+ "liblog_rust",
+ "libnix",
+ "libserde",
+ "libserde_cbor",
+ "libthiserror",
+ ],
+}
+
+rust_binary {
+ name: "diced",
+ srcs: ["src/diced_main.rs"],
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "libandroid_logger",
+ "libbinder_rs",
+ "libdiced",
+ "libdiced_open_dice_cbor",
+ "libdiced_sample_inputs",
+ "libdiced_utils",
+ "liblog_rust",
+ ],
+ init_rc: ["diced.rc"],
+}
+
+rust_test {
+ name: "diced_test",
+ crate_name: "diced_test",
+ srcs: ["src/lib.rs"],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "android.security.dice-rust",
+ "libanyhow",
+ "libbinder_rs",
+ "libdiced_open_dice_cbor",
+ "libdiced_utils",
+ "libkeystore2_crypto_rust",
+ "libkeystore2_selinux",
+ "libkeystore2_vintf_rust",
+ "liblibc",
+ "liblog_rust",
+ "libnix",
+ "libserde",
+ "libserde_cbor",
+ "libthiserror",
+ ],
+}
+
+rust_test {
+ name: "diced_vendor_test",
+ crate_name: "diced_vendor_test",
+ srcs: ["src/lib_vendor.rs"],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "libanyhow",
+ "libdiced_open_dice_cbor",
+ "libdiced_sample_inputs",
+ "libdiced_utils",
+ "libbinder_rs",
+ "libkeystore2_crypto_rust",
+ "liblibc",
+ "liblog_rust",
+ "libnix",
+ "libserde",
+ "libserde_cbor",
+ "libthiserror",
+ ],
+}
+
+rust_test {
+ name: "diced_client_test",
+ srcs: [
+ "src/diced_client_test.rs",
+ ],
+ require_root: true,
+ auto_gen_config: true,
+ test_suites: [
+ "general-tests",
+ ],
+
+ rustlibs: [
+ "android.hardware.security.dice-V1-rust",
+ "android.security.dice-rust",
+ "libanyhow",
+ "libbinder_rs",
+ "libdiced_open_dice_cbor",
+ "libdiced_sample_inputs",
+ "libdiced_utils",
+ "libnix",
+ ],
+}
diff --git a/diced/diced.rc b/diced/diced.rc
new file mode 100644
index 0000000..8c43fa5
--- /dev/null
+++ b/diced/diced.rc
@@ -0,0 +1,13 @@
+# Start the Diced service.
+#
+# See system/core/init/README.md for information on the init.rc language.
+
+service diced /system/bin/diced
+ class main
+ user diced
+ group diced
+ # The diced service must not be allowed to restart.
+ # If it crashes for any reason security critical state is lost.
+ # The only remedy is to restart the device.
+ oneshot
+ writepid /dev/cpuset/foreground/tasks
diff --git a/diced/open_dice_cbor/Android.bp b/diced/open_dice_cbor/Android.bp
index 0d05ce0..3e67045 100644
--- a/diced/open_dice_cbor/Android.bp
+++ b/diced/open_dice_cbor/Android.bp
@@ -32,4 +32,24 @@
"libopen_dice_bcc",
"libopen_dice_cbor",
],
+ vendor_available: true,
+}
+
+rust_test {
+ name: "diced_open_dice_cbor_test",
+ crate_name: "diced_open_dice_cbor_test",
+ srcs: ["lib.rs"],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ rustlibs: [
+ "libdiced_sample_inputs",
+ "libkeystore2_crypto_rust",
+ "libopen_dice_bcc_bindgen",
+ "libopen_dice_cbor_bindgen",
+ "libthiserror",
+ ],
+ static_libs: [
+ "libopen_dice_bcc",
+ "libopen_dice_cbor",
+ ],
}
diff --git a/diced/open_dice_cbor/lib.rs b/diced/open_dice_cbor/lib.rs
index 1b07e61..7122ca5 100644
--- a/diced/open_dice_cbor/lib.rs
+++ b/diced/open_dice_cbor/lib.rs
@@ -790,3 +790,248 @@
})
}
}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use diced_sample_inputs::make_sample_bcc_and_cdis;
+ use std::convert::TryInto;
+
+ static SEED_TEST_VECTOR: &[u8] = &[
+ 0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba,
+ 0xaa, 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5,
+ 0x3a, 0x08, 0x84, 0x8a, 0x98, 0x85, 0x6d, 0xf5, 0x69, 0x21, 0x03, 0xcd, 0x09, 0xc3, 0x28,
+ 0xd6, 0x06, 0xa7, 0x57, 0xbd, 0x48, 0x4b, 0x0f, 0x79, 0x0f, 0xf8, 0x2f, 0xf0, 0x0a, 0x41,
+ 0x94, 0xd8, 0x8c, 0xa8,
+ ];
+
+ static CDI_ATTEST_TEST_VECTOR: &[u8] = &[
+ 0xfa, 0x3c, 0x2f, 0x58, 0x37, 0xf5, 0x8e, 0x96, 0x16, 0x09, 0xf5, 0x22, 0xa1, 0xf1, 0xba,
+ 0xaa, 0x19, 0x95, 0x01, 0x79, 0x2e, 0x60, 0x56, 0xaf, 0xf6, 0x41, 0xe7, 0xff, 0x48, 0xf5,
+ 0x3a, 0x08,
+ ];
+ static CDI_PRIVATE_KEY_SEED_TEST_VECTOR: &[u8] = &[
+ 0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe,
+ 0x0d, 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72,
+ 0x02, 0x6e,
+ ];
+
+ static PUB_KEY_TEST_VECTOR: &[u8] = &[
+ 0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b, 0xfc, 0x23,
+ 0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52, 0xf1, 0x61,
+ 0x06, 0x37,
+ ];
+ static PRIV_KEY_TEST_VECTOR: &[u8] = &[
+ 0x5f, 0xcc, 0x8e, 0x1a, 0xd1, 0xc2, 0xb3, 0xe9, 0xfb, 0xe1, 0x68, 0xf0, 0xf6, 0x98, 0xfe,
+ 0x0d, 0xee, 0xd4, 0xb5, 0x18, 0xcb, 0x59, 0x70, 0x2d, 0xee, 0x06, 0xe5, 0x70, 0xf1, 0x72,
+ 0x02, 0x6e, 0x47, 0x42, 0x4b, 0xbd, 0xd7, 0x23, 0xb4, 0xcd, 0xca, 0xe2, 0x8e, 0xdc, 0x6b,
+ 0xfc, 0x23, 0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52,
+ 0xf1, 0x61, 0x06, 0x37,
+ ];
+
+ static SIGNATURE_TEST_VECTOR: &[u8] = &[
+ 0x44, 0xae, 0xcc, 0xe2, 0xb9, 0x96, 0x18, 0x39, 0x0e, 0x61, 0x0f, 0x53, 0x07, 0xbf, 0xf2,
+ 0x32, 0x3d, 0x44, 0xd4, 0xf2, 0x07, 0x23, 0x30, 0x85, 0x32, 0x18, 0xd2, 0x69, 0xb8, 0x29,
+ 0x3c, 0x26, 0xe6, 0x0d, 0x9c, 0xa5, 0xc2, 0x73, 0xcd, 0x8c, 0xb8, 0x3c, 0x3e, 0x5b, 0xfd,
+ 0x62, 0x8d, 0xf6, 0xc4, 0x27, 0xa6, 0xe9, 0x11, 0x06, 0x5a, 0xb2, 0x2b, 0x64, 0xf7, 0xfc,
+ 0xbb, 0xab, 0x4a, 0x0e,
+ ];
+
+ #[test]
+ fn hash_derive_sign_verify() {
+ let mut ctx = OpenDiceCborContext::new();
+ let seed = ctx.hash("MySeedString".as_bytes()).unwrap();
+ assert_eq!(seed, SEED_TEST_VECTOR);
+ let cdi_attest = &seed[..CDI_SIZE];
+ assert_eq!(cdi_attest, CDI_ATTEST_TEST_VECTOR);
+ let cdi_private_key_seed =
+ ctx.derive_cdi_private_key_seed(cdi_attest.try_into().unwrap()).unwrap();
+ assert_eq!(&cdi_private_key_seed[..], CDI_PRIVATE_KEY_SEED_TEST_VECTOR);
+ let (pub_key, priv_key) =
+ ctx.keypair_from_seed(cdi_private_key_seed[..].try_into().unwrap()).unwrap();
+ assert_eq!(&pub_key, PUB_KEY_TEST_VECTOR);
+ assert_eq!(&priv_key[..], PRIV_KEY_TEST_VECTOR);
+ let mut signature =
+ ctx.sign("MyMessage".as_bytes(), priv_key[..].try_into().unwrap()).unwrap();
+ assert_eq!(&signature, SIGNATURE_TEST_VECTOR);
+ assert!(ctx
+ .verify(
+ "MyMessage".as_bytes(),
+ signature[..].try_into().unwrap(),
+ pub_key[..].try_into().unwrap()
+ )
+ .is_ok());
+ assert!(ctx
+ .verify(
+ "MyMessage_fail".as_bytes(),
+ signature[..].try_into().unwrap(),
+ pub_key[..].try_into().unwrap()
+ )
+ .is_err());
+ signature[0] += 1;
+ assert!(ctx
+ .verify(
+ "MyMessage".as_bytes(),
+ signature[..].try_into().unwrap(),
+ pub_key[..].try_into().unwrap()
+ )
+ .is_err());
+ }
+
+ static SAMPLE_CDI_ATTEST_TEST_VECTOR: &[u8] = &[
+ 0x3e, 0x57, 0x65, 0x5d, 0x48, 0x02, 0xbd, 0x5c, 0x66, 0xcc, 0x1f, 0x0f, 0xbe, 0x5e, 0x32,
+ 0xb6, 0x9e, 0x3d, 0x04, 0xaf, 0x00, 0x15, 0xbc, 0xdd, 0x1f, 0xbc, 0x59, 0xe4, 0xc3, 0x87,
+ 0x95, 0x5e,
+ ];
+
+ static SAMPLE_CDI_SEAL_TEST_VECTOR: &[u8] = &[
+ 0x36, 0x1b, 0xd2, 0xb3, 0xc4, 0xda, 0x77, 0xb2, 0x9c, 0xba, 0x39, 0x53, 0x82, 0x93, 0xd9,
+ 0xb8, 0x9f, 0x73, 0x2d, 0x27, 0x06, 0x15, 0xa8, 0xcb, 0x6d, 0x1d, 0xf2, 0xb1, 0x54, 0xbb,
+ 0x62, 0xf1,
+ ];
+
+ static SAMPLE_BCC_TEST_VECTOR: &[u8] = &[
+ 0x84, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x3e, 0x85,
+ 0xe5, 0x72, 0x75, 0x55, 0xe5, 0x1e, 0xe7, 0xf3, 0x35, 0x94, 0x8e, 0xbb, 0xbd, 0x74, 0x1e,
+ 0x1d, 0xca, 0x49, 0x9c, 0x97, 0x39, 0x77, 0x06, 0xd3, 0xc8, 0x6e, 0x8b, 0xd7, 0x33, 0xf9,
+ 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28, 0x34, 0x32,
+ 0x64, 0x38, 0x38, 0x36, 0x34, 0x66, 0x39, 0x37, 0x62, 0x36, 0x35, 0x34, 0x37, 0x61, 0x35,
+ 0x30, 0x63, 0x31, 0x65, 0x30, 0x61, 0x37, 0x34, 0x39, 0x66, 0x38, 0x65, 0x66, 0x38, 0x62,
+ 0x38, 0x31, 0x65, 0x63, 0x36, 0x32, 0x61, 0x66, 0x02, 0x78, 0x28, 0x31, 0x66, 0x36, 0x39,
+ 0x36, 0x66, 0x30, 0x37, 0x32, 0x35, 0x32, 0x66, 0x32, 0x39, 0x65, 0x39, 0x33, 0x66, 0x65,
+ 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65, 0x33, 0x32, 0x63, 0x64, 0x38, 0x31, 0x64, 0x63,
+ 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x16, 0x48,
+ 0xf2, 0x55, 0x53, 0x23, 0xdd, 0x15, 0x2e, 0x83, 0x38, 0xc3, 0x64, 0x38, 0x63, 0x26, 0x0f,
+ 0xcf, 0x5b, 0xd1, 0x3a, 0xd3, 0x40, 0x3e, 0x23, 0xf8, 0x34, 0x4c, 0x6d, 0xa2, 0xbe, 0x25,
+ 0x1c, 0xb0, 0x29, 0xe8, 0xc3, 0xfb, 0xb8, 0x80, 0xdc, 0xb1, 0xd2, 0xb3, 0x91, 0x4d, 0xd3,
+ 0xfb, 0x01, 0x0f, 0xe4, 0xe9, 0x46, 0xa2, 0xc0, 0x26, 0x57, 0x5a, 0xba, 0x30, 0xf7, 0x15,
+ 0x98, 0x14, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x63,
+ 0x41, 0x42, 0x4c, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6,
+ 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x47, 0xae, 0x42, 0x27, 0x4c, 0xcb, 0x65, 0x4d,
+ 0xee, 0x74, 0x2d, 0x05, 0x78, 0x2a, 0x08, 0x2a, 0xa5, 0xf0, 0xcf, 0xea, 0x3e, 0x60, 0xee,
+ 0x97, 0x11, 0x4b, 0x5b, 0xe6, 0x05, 0x0c, 0xe8, 0x90, 0xf5, 0x22, 0xc4, 0xc6, 0x67, 0x7a,
+ 0x22, 0x27, 0x17, 0xb3, 0x79, 0xcc, 0x37, 0x64, 0x5e, 0x19, 0x4f, 0x96, 0x37, 0x67, 0x3c,
+ 0xd0, 0xc5, 0xed, 0x0f, 0xdd, 0xe7, 0x2e, 0x4f, 0x70, 0x97, 0x30, 0x3a, 0x00, 0x47, 0x44,
+ 0x54, 0x58, 0x40, 0xf9, 0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd, 0xe3, 0x97,
+ 0x4a, 0xcb, 0x3c, 0xe7, 0x6b, 0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59, 0x15,
+ 0xb1, 0x23, 0xe6, 0xc8, 0xdf, 0xfb, 0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b,
+ 0x37, 0x0e, 0x12, 0x12, 0xb2, 0xfd, 0xc1, 0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6, 0x29,
+ 0x1b, 0x99, 0xea, 0xae, 0xfd, 0xaa, 0x0d, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a,
+ 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20,
+ 0x06, 0x21, 0x58, 0x20, 0xb1, 0x02, 0xcc, 0x2c, 0xb2, 0x6a, 0x3b, 0xe9, 0xc1, 0xd3, 0x95,
+ 0x10, 0xa0, 0xe1, 0xff, 0x51, 0xde, 0x57, 0xd5, 0x65, 0x28, 0xfd, 0x7f, 0xeb, 0xd4, 0xca,
+ 0x15, 0xf3, 0xca, 0xdf, 0x37, 0x88, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40,
+ 0x58, 0xd8, 0x03, 0x24, 0x53, 0x60, 0x57, 0xa9, 0x09, 0xfa, 0xab, 0xdc, 0x57, 0x1e, 0xf0,
+ 0xe5, 0x1e, 0x51, 0x6f, 0x9e, 0xa3, 0x42, 0xe6, 0x6a, 0x8c, 0xaa, 0xad, 0x08, 0x48, 0xde,
+ 0x7f, 0x4f, 0x6e, 0x2f, 0x7f, 0x39, 0x6c, 0xa1, 0xf8, 0x42, 0x71, 0xfe, 0x17, 0x3d, 0xca,
+ 0x31, 0x83, 0x92, 0xed, 0xbb, 0x40, 0xb8, 0x10, 0xe0, 0xf2, 0x5a, 0x99, 0x53, 0x38, 0x46,
+ 0x33, 0x97, 0x78, 0x05, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01,
+ 0x78, 0x28, 0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35, 0x32, 0x66, 0x32,
+ 0x39, 0x65, 0x39, 0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65, 0x33, 0x32,
+ 0x63, 0x64, 0x38, 0x31, 0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x02, 0x78, 0x28,
+ 0x32, 0x35, 0x39, 0x34, 0x38, 0x39, 0x65, 0x36, 0x39, 0x37, 0x34, 0x38, 0x37, 0x30, 0x35,
+ 0x64, 0x65, 0x33, 0x65, 0x32, 0x66, 0x34, 0x34, 0x32, 0x36, 0x37, 0x65, 0x61, 0x34, 0x39,
+ 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x50,
+ 0x58, 0x40, 0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa, 0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83,
+ 0x7f, 0x46, 0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14, 0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56,
+ 0xb3, 0xbf, 0x2f, 0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4, 0xd2, 0xa9, 0x6b, 0x18, 0x28,
+ 0xe8, 0x29, 0x20, 0x49, 0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54, 0xe9, 0x71, 0xd2, 0x7e,
+ 0xa4, 0xfe, 0x58, 0x7f, 0xd3, 0xc7, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56, 0xa3, 0x3a, 0x00,
+ 0x01, 0x11, 0x71, 0x63, 0x41, 0x56, 0x42, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00,
+ 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x93, 0x17, 0xe1, 0x11,
+ 0x27, 0x59, 0xd0, 0xef, 0x75, 0x0b, 0x2b, 0x1c, 0x0f, 0x5f, 0x52, 0xc3, 0x29, 0x23, 0xb5,
+ 0x2a, 0xe6, 0x12, 0x72, 0x6f, 0x39, 0x86, 0x65, 0x2d, 0xf2, 0xe4, 0xe7, 0xd0, 0xaf, 0x0e,
+ 0xa7, 0x99, 0x16, 0x89, 0x97, 0x21, 0xf7, 0xdc, 0x89, 0xdc, 0xde, 0xbb, 0x94, 0x88, 0x1f,
+ 0xda, 0xe2, 0xf3, 0xe0, 0x54, 0xf9, 0x0e, 0x29, 0xb1, 0xbd, 0xe1, 0x0c, 0x0b, 0xd7, 0xf6,
+ 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55,
+ 0x6f, 0xac, 0x56, 0xd9, 0x02, 0x35, 0x2b, 0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86,
+ 0xf5, 0xd4, 0xc2, 0xf1, 0xf9, 0x35, 0x7d, 0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8,
+ 0x1c, 0x12, 0x78, 0x5c, 0x9c, 0x3e, 0xf6, 0x66, 0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f,
+ 0xc9, 0x72, 0xee, 0x73, 0x43, 0x02, 0x8a, 0xef, 0xbc, 0x05, 0x98, 0x3a, 0x00, 0x47, 0x44,
+ 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27,
+ 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x96, 0x6d, 0x96, 0x42, 0xda, 0x64, 0x51,
+ 0xad, 0xfa, 0x00, 0xbc, 0xbc, 0x95, 0x8a, 0xb0, 0xb9, 0x76, 0x01, 0xe6, 0xbd, 0xc0, 0x26,
+ 0x79, 0x26, 0xfc, 0x0f, 0x1d, 0x87, 0x65, 0xf1, 0xf3, 0x99, 0x3a, 0x00, 0x47, 0x44, 0x58,
+ 0x41, 0x20, 0x58, 0x40, 0x10, 0x7f, 0x77, 0xad, 0x70, 0xbd, 0x52, 0x81, 0x28, 0x8d, 0x24,
+ 0x81, 0xb4, 0x3f, 0x21, 0x68, 0x9f, 0xc3, 0x80, 0x68, 0x86, 0x55, 0xfb, 0x2e, 0x6d, 0x96,
+ 0xe1, 0xe1, 0xb7, 0x28, 0x8d, 0x63, 0x85, 0xba, 0x2a, 0x01, 0x33, 0x87, 0x60, 0x63, 0xbb,
+ 0x16, 0x3f, 0x2f, 0x3d, 0xf4, 0x2d, 0x48, 0x5b, 0x87, 0xed, 0xda, 0x34, 0xeb, 0x9c, 0x4d,
+ 0x14, 0xac, 0x65, 0xf4, 0xfa, 0xef, 0x45, 0x0b, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59,
+ 0x01, 0x8f, 0xa9, 0x01, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38, 0x39, 0x65, 0x36, 0x39,
+ 0x37, 0x34, 0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66, 0x34, 0x34, 0x32,
+ 0x36, 0x37, 0x65, 0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32,
+ 0x35, 0x02, 0x78, 0x28, 0x35, 0x64, 0x34, 0x65, 0x64, 0x37, 0x66, 0x34, 0x31, 0x37, 0x61,
+ 0x39, 0x35, 0x34, 0x61, 0x31, 0x38, 0x31, 0x34, 0x30, 0x37, 0x62, 0x35, 0x38, 0x38, 0x35,
+ 0x61, 0x66, 0x64, 0x37, 0x32, 0x61, 0x35, 0x62, 0x66, 0x34, 0x30, 0x64, 0x61, 0x36, 0x3a,
+ 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x47, 0x44, 0x53,
+ 0x58, 0x1a, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x67, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x0c, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00,
+ 0x47, 0x44, 0x52, 0x58, 0x40, 0x26, 0x1a, 0xbd, 0x26, 0xd8, 0x37, 0x8f, 0x4a, 0xf2, 0x9e,
+ 0x49, 0x4d, 0x93, 0x23, 0xc4, 0x6e, 0x02, 0xda, 0xe0, 0x00, 0x02, 0xe7, 0xed, 0x29, 0xdf,
+ 0x2b, 0xb3, 0x69, 0xf3, 0x55, 0x0e, 0x4c, 0x22, 0xdc, 0xcf, 0xf5, 0x92, 0xc9, 0xfa, 0x78,
+ 0x98, 0xf1, 0x0e, 0x55, 0x5f, 0xf4, 0x45, 0xed, 0xc0, 0x0a, 0x72, 0x2a, 0x7a, 0x3a, 0xd2,
+ 0xb1, 0xf7, 0x76, 0xfe, 0x2a, 0x6b, 0x7b, 0x2a, 0x53, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58,
+ 0x40, 0x04, 0x25, 0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30, 0x03,
+ 0xb8, 0xd6, 0xe1, 0x99, 0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c, 0x37, 0x68,
+ 0x4e, 0x1d, 0xc0, 0x24, 0x74, 0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1, 0x43, 0xd2, 0x9c,
+ 0xfc, 0x12, 0x9e, 0x77, 0x0a, 0xde, 0x29, 0x24, 0xff, 0x2e, 0xfa, 0xc7, 0x10, 0xd5, 0x73,
+ 0xd4, 0xc6, 0xdf, 0x62, 0x9f, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47,
+ 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21,
+ 0x58, 0x20, 0xdb, 0xe7, 0x5b, 0x3f, 0xa3, 0x42, 0xb0, 0x9c, 0xf8, 0x40, 0x8c, 0xb0, 0x9c,
+ 0xf0, 0x0a, 0xaf, 0xdf, 0x6f, 0xe5, 0x09, 0x21, 0x11, 0x92, 0xe1, 0xf8, 0xc5, 0x09, 0x02,
+ 0x3d, 0x1f, 0xb7, 0xc5, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0xc4, 0xc1,
+ 0xd7, 0x1c, 0x2d, 0x26, 0x89, 0x22, 0xcf, 0xa6, 0x99, 0x77, 0x30, 0x84, 0x86, 0x27, 0x59,
+ 0x8f, 0xd8, 0x08, 0x75, 0xe0, 0xb2, 0xef, 0xf9, 0xfa, 0xa5, 0x40, 0x8c, 0xd3, 0xeb, 0xbb,
+ 0xda, 0xf2, 0xc8, 0xae, 0x41, 0x22, 0x50, 0x9c, 0xe8, 0xb2, 0x9c, 0x9b, 0x3f, 0x8a, 0x78,
+ 0x76, 0xab, 0xd0, 0xbe, 0xfc, 0xe4, 0x79, 0xcb, 0x1b, 0x2b, 0xaa, 0x4d, 0xdd, 0x15, 0x61,
+ 0x42, 0x06,
+ ];
+
+ // This test invokes make_sample_bcc_and_cdis and compares the result bitwise to the target
+ // vectors. The function uses main_flow, bcc_main_flow, format_config_descriptor,
+ // derive_cdi_private_key_seed, and keypair_from_seed. This test is sensitive to errors
+ // and changes in any of those functions.
+ #[test]
+ fn main_flow_and_bcc_main_flow() {
+ let (cdi_attest, cdi_seal, bcc) = make_sample_bcc_and_cdis().unwrap();
+ assert_eq!(&cdi_attest[..], SAMPLE_CDI_ATTEST_TEST_VECTOR);
+ assert_eq!(&cdi_seal[..], SAMPLE_CDI_SEAL_TEST_VECTOR);
+ assert_eq!(&bcc[..], SAMPLE_BCC_TEST_VECTOR);
+ }
+
+ static DERIVED_KEY_TEST_VECTOR: &[u8] = &[
+ 0x0e, 0xd6, 0x07, 0x0e, 0x1c, 0x38, 0x2c, 0x76, 0x13, 0xc6, 0x76, 0x25, 0x7e, 0x07, 0x6f,
+ 0xdb, 0x1d, 0xb1, 0x0f, 0x3f, 0xed, 0xc5, 0x2b, 0x95, 0xd1, 0x32, 0xf1, 0x63, 0x2f, 0x2a,
+ 0x01, 0x5e,
+ ];
+
+ #[test]
+ fn kdf() {
+ let mut ctx = OpenDiceCborContext::new();
+ let derived_key = ctx
+ .kdf(
+ PRIVATE_KEY_SEED_SIZE,
+ "myKey".as_bytes(),
+ "mySalt".as_bytes(),
+ "myInfo".as_bytes(),
+ )
+ .unwrap();
+ assert_eq!(&derived_key[..], DERIVED_KEY_TEST_VECTOR);
+ }
+
+ static CERT_ID_TEST_VECTOR: &[u8] = &[
+ 0x7a, 0x36, 0x45, 0x2c, 0x02, 0xf6, 0x2b, 0xec, 0xf9, 0x80, 0x06, 0x75, 0x87, 0xa5, 0xc1,
+ 0x44, 0x0c, 0xd3, 0xc0, 0x6d,
+ ];
+
+ #[test]
+ fn derive_cdi_certificate_id() {
+ let mut ctx = OpenDiceCborContext::new();
+ let cert_id = ctx.derive_cdi_certificate_id("MyPubKey".as_bytes()).unwrap();
+ assert_eq!(&cert_id[..], CERT_ID_TEST_VECTOR);
+ }
+}
diff --git a/diced/src/diced_client_test.rs b/diced/src/diced_client_test.rs
new file mode 100644
index 0000000..3f5b68f
--- /dev/null
+++ b/diced/src/diced_client_test.rs
@@ -0,0 +1,196 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Config::Config as BinderConfig, InputValues::InputValues as BinderInputValues,
+ Mode::Mode as BinderMode,
+};
+use android_security_dice::aidl::android::security::dice::IDiceMaintenance::IDiceMaintenance;
+use android_security_dice::aidl::android::security::dice::IDiceNode::IDiceNode;
+use anyhow::Result;
+use binder::Strong;
+use diced_open_dice_cbor as dice;
+use nix::libc::uid_t;
+use std::convert::TryInto;
+
+static DICE_NODE_SERVICE_NAME: &str = "android.security.dice.IDiceNode";
+static DICE_MAINTENANCE_SERVICE_NAME: &str = "android.security.dice.IDiceMaintenance";
+
+fn get_dice_node() -> Strong<dyn IDiceNode> {
+ binder::get_interface(DICE_NODE_SERVICE_NAME).unwrap()
+}
+
+fn get_dice_maintenance() -> Strong<dyn IDiceMaintenance> {
+ binder::get_interface(DICE_MAINTENANCE_SERVICE_NAME).unwrap()
+}
+
+static TEST_MESSAGE: &[u8] = &[
+ // "My test message!"
+ 0x4d, 0x79, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x21,
+ 0x0a,
+];
+
+// This test calls derive with an empty argument vector and with a set of three input values.
+// It then performs the same three derivation steps on the result of the former and compares
+// the result to the result of the latter.
+fn equivalence_test() {
+ let node = get_dice_node();
+ let input_values = diced_sample_inputs::get_input_values_vector();
+ let former = node.derive(&[]).expect("Trying to call derive.");
+ let latter = node.derive(&input_values).expect("Trying to call derive with input values.");
+ let artifacts = diced_utils::ResidentArtifacts::new(
+ former.cdiAttest[..].try_into().unwrap(),
+ former.cdiSeal[..].try_into().unwrap(),
+ &former.bcc.data,
+ )
+ .unwrap();
+
+ let input_values: Vec<diced_utils::InputValues> =
+ input_values.iter().map(|v| v.try_into()).collect::<Result<_>>().unwrap();
+
+ let artifacts =
+ artifacts.execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues)).unwrap();
+ let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
+ let from_former = diced_utils::make_bcc_handover(
+ cdi_attest[..].try_into().unwrap(),
+ cdi_seal[..].try_into().unwrap(),
+ &bcc,
+ )
+ .unwrap();
+ // TODO when we have a parser/verifier, check equivalence rather
+ // than bit by bit equality.
+ assert_eq!(latter, from_former);
+}
+
+fn sign_and_verify() {
+ let node = get_dice_node();
+ let _signature = node.sign(&[], TEST_MESSAGE).expect("Trying to call sign.");
+
+ let _bcc = node.getAttestationChain(&[]).expect("Trying to call getAttestationChain.");
+ // TODO b/204938506 check the signature with the bcc when the verifier is available.
+}
+
+// This test calls derive with an empty argument vector, then demotes the itself using
+// a set of three input values, and then calls derive with empty argument vector again.
+// It then performs the same three derivation steps on the result of the former and compares
+// the result to the result of the latter.
+fn demote_test() {
+ let node = get_dice_node();
+ let input_values = diced_sample_inputs::get_input_values_vector();
+ let former = node.derive(&[]).expect("Trying to call derive.");
+ node.demote(&input_values).expect("Trying to call demote with input values.");
+
+ let latter = node.derive(&[]).expect("Trying to call derive after demote.");
+
+ let artifacts = diced_utils::ResidentArtifacts::new(
+ former.cdiAttest[..].try_into().unwrap(),
+ former.cdiSeal[..].try_into().unwrap(),
+ &former.bcc.data,
+ )
+ .unwrap();
+
+ let input_values: Vec<diced_utils::InputValues> =
+ input_values.iter().map(|v| v.try_into()).collect::<Result<_>>().unwrap();
+
+ let artifacts =
+ artifacts.execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues)).unwrap();
+ let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
+ let from_former = diced_utils::make_bcc_handover(
+ cdi_attest[..].try_into().unwrap(),
+ cdi_seal[..].try_into().unwrap(),
+ &bcc,
+ )
+ .unwrap();
+ // TODO b/204938506 when we have a parser/verifier, check equivalence rather
+ // than bit by bit equality.
+ assert_eq!(latter, from_former);
+}
+
+fn client_input_values(uid: uid_t) -> BinderInputValues {
+ BinderInputValues {
+ codeHash: vec![0; dice::HASH_SIZE],
+ config: BinderConfig {
+ desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
+ .unwrap(),
+ },
+ authorityHash: vec![0; dice::HASH_SIZE],
+ authorityDescriptor: None,
+ mode: BinderMode::NORMAL,
+ hidden: vec![0; dice::HIDDEN_SIZE],
+ }
+}
+
+// This test calls derive with an empty argument vector `former` which look like this:
+// <common root> | <caller>
+// It then demotes diced using a set of three input values prefixed with the uid based input
+// values that diced would add to any call. It then calls derive with empty argument vector
+// again which will add another step using the identity of the caller. If diced was demoted
+// correctly the chain of `latter` will
+// look as follows:
+// <common root> | <caller> | <the three sample inputs> | <caller>
+//
+// It then performs the same three derivation steps followed by a set of caller input values
+// on `former` and compares it to `latter`.
+fn demote_self_test() {
+ let maintenance = get_dice_maintenance();
+ let node = get_dice_node();
+ let input_values = diced_sample_inputs::get_input_values_vector();
+ let former = node.derive(&[]).expect("Trying to call derive.");
+
+ let client = client_input_values(nix::unistd::getuid().into());
+
+ let mut demote_vector = vec![client.clone()];
+ demote_vector.append(&mut input_values.clone());
+ maintenance.demoteSelf(&demote_vector).expect("Trying to call demote_self with input values.");
+
+ let latter = node.derive(&[]).expect("Trying to call derive after demote.");
+
+ let artifacts = diced_utils::ResidentArtifacts::new(
+ former.cdiAttest[..].try_into().unwrap(),
+ former.cdiSeal[..].try_into().unwrap(),
+ &former.bcc.data,
+ )
+ .unwrap();
+
+ let client = [client];
+ let input_values: Vec<diced_utils::InputValues> = input_values
+ .iter()
+ .chain(client.iter())
+ .map(|v| v.try_into())
+ .collect::<Result<_>>()
+ .unwrap();
+
+ let artifacts =
+ artifacts.execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues)).unwrap();
+ let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
+ let from_former = diced_utils::make_bcc_handover(
+ cdi_attest[..].try_into().unwrap(),
+ cdi_seal[..].try_into().unwrap(),
+ &bcc,
+ )
+ .unwrap();
+ // TODO b/204938506 when we have a parser/verifier, check equivalence rather
+ // than bit by bit equality.
+ assert_eq!(latter, from_former);
+}
+
+#[test]
+fn run_serialized_test() {
+ equivalence_test();
+ sign_and_verify();
+ // The demote self test must run before the demote test or the test fails.
+ // And since demotion is not reversible the test can only pass once per boot.
+ demote_self_test();
+ demote_test();
+}
diff --git a/diced/src/diced_main.rs b/diced/src/diced_main.rs
new file mode 100644
index 0000000..c2cf02c
--- /dev/null
+++ b/diced/src/diced_main.rs
@@ -0,0 +1,76 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Main entry point for diced, the friendly neighborhood DICE service.
+
+use binder::get_interface;
+use diced::{DiceMaintenance, DiceNode, DiceNodeImpl, ProxyNodeHal, ResidentNode};
+use std::convert::TryInto;
+use std::panic;
+use std::sync::Arc;
+
+static DICE_NODE_SERVICE_NAME: &str = "android.security.dice.IDiceNode";
+static DICE_MAINTENANCE_SERVICE_NAME: &str = "android.security.dice.IDiceMaintenance";
+static DICE_HAL_SERVICE_NAME: &str = "android.hardware.security.dice.IDiceDevice/default";
+
+fn main() {
+ android_logger::init_once(
+ android_logger::Config::default().with_tag("diced").with_min_level(log::Level::Debug),
+ );
+ // Redirect panic messages to logcat.
+ panic::set_hook(Box::new(|panic_info| {
+ log::error!("{}", panic_info);
+ }));
+
+ // Saying hi.
+ log::info!("Diced, your friendly neighborhood DICE service, is starting.");
+
+ let node_impl: Arc<dyn DiceNodeImpl + Send + Sync> = match get_interface(DICE_HAL_SERVICE_NAME)
+ {
+ Ok(dice_device) => {
+ Arc::new(ProxyNodeHal::new(dice_device).expect("Failed to construct a proxy node."))
+ }
+ Err(e) => {
+ log::warn!("Failed to connect to DICE HAL: {:?}", e);
+ log::warn!("Using sample dice artifacts.");
+ let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
+ .expect("Failed to create sample dice artifacts.");
+ Arc::new(
+ ResidentNode::new(
+ cdi_attest[..]
+ .try_into()
+ .expect("Failed to convert cdi_attest into array ref."),
+ cdi_seal[..].try_into().expect("Failed to convert cdi_seal into array ref."),
+ bcc,
+ )
+ .expect("Failed to construct a resident node."),
+ )
+ }
+ };
+
+ let node = DiceNode::new_as_binder(node_impl.clone())
+ .expect("Failed to create IDiceNode service instance.");
+
+ let maintenance = DiceMaintenance::new_as_binder(node_impl)
+ .expect("Failed to create IDiceMaintenance service instance.");
+
+ binder::add_service(DICE_NODE_SERVICE_NAME, node.as_binder())
+ .expect("Failed to register IDiceNode Service");
+
+ binder::add_service(DICE_MAINTENANCE_SERVICE_NAME, maintenance.as_binder())
+ .expect("Failed to register IDiceMaintenance Service");
+
+ log::info!("Joining thread pool now.");
+ binder::ProcessState::join_thread_pool();
+}
diff --git a/diced/src/error.rs b/diced/src/error.rs
new file mode 100644
index 0000000..92aa97c
--- /dev/null
+++ b/diced/src/error.rs
@@ -0,0 +1,125 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use android_security_dice::aidl::android::security::dice::ResponseCode::ResponseCode;
+use anyhow::Result;
+use binder::{
+ public_api::Result as BinderResult, ExceptionCode, Status as BinderStatus, StatusCode,
+};
+use keystore2_selinux as selinux;
+use std::ffi::CString;
+
+/// This is the main Diced error type. It wraps the Diced `ResponseCode` generated
+/// from AIDL in the `Rc` variant and Binder and BinderTransaction errors in the respective
+/// variants.
+#[allow(dead_code)] // Binder error forwarding will be needed when proxy nodes are implemented.
+#[derive(Debug, thiserror::Error, Eq, PartialEq, Clone)]
+pub enum Error {
+ /// Wraps a dice `ResponseCode` as defined by the android.security.dice AIDL interface
+ /// specification.
+ #[error("Error::Rc({0:?})")]
+ Rc(ResponseCode),
+ /// Wraps a Binder exception code other than a service specific exception.
+ #[error("Binder exception code {0:?}, {1:?}")]
+ Binder(ExceptionCode, i32),
+ /// Wraps a Binder status code.
+ #[error("Binder transaction error {0:?}")]
+ BinderTransaction(StatusCode),
+}
+
+/// This function should be used by dice service calls to translate error conditions
+/// into service specific exceptions.
+///
+/// All error conditions get logged by this function.
+///
+/// All `Error::Rc(x)` variants get mapped onto a service specific error code of x.
+/// `selinux::Error::PermissionDenied` is mapped on `ResponseCode::PERMISSION_DENIED`.
+///
+/// All non `Error` error conditions and the Error::Binder variant get mapped onto
+/// ResponseCode::SYSTEM_ERROR`.
+///
+/// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
+/// as argument to `handle_ok`. `handle_ok` must generate a `BinderResult<T>`, but it
+/// typically returns Ok(value).
+///
+/// # Examples
+///
+/// ```
+/// fn do_something() -> anyhow::Result<Vec<u8>> {
+/// Err(anyhow!(Error::Rc(ResponseCode::NOT_IMPLEMENTED)))
+/// }
+///
+/// map_or_log_err(do_something(), Ok)
+/// ```
+pub fn map_or_log_err<T, U, F>(result: Result<U>, handle_ok: F) -> BinderResult<T>
+where
+ F: FnOnce(U) -> BinderResult<T>,
+{
+ map_err_with(
+ result,
+ |e| {
+ log::error!("{:?}", e);
+ e
+ },
+ handle_ok,
+ )
+}
+
+/// This function behaves similar to map_or_log_error, but it does not log the errors, instead
+/// it calls map_err on the error before mapping it to a binder result allowing callers to
+/// log or transform the error before mapping it.
+fn map_err_with<T, U, F1, F2>(result: Result<U>, map_err: F1, handle_ok: F2) -> BinderResult<T>
+where
+ F1: FnOnce(anyhow::Error) -> anyhow::Error,
+ F2: FnOnce(U) -> BinderResult<T>,
+{
+ result.map_or_else(
+ |e| {
+ let e = map_err(e);
+ let msg = match CString::new(format!("{:?}", e)) {
+ Ok(msg) => Some(msg),
+ Err(_) => {
+ log::warn!(
+ "Cannot convert error message to CStr. It contained a nul byte.
+ Omitting message from service specific error."
+ );
+ None
+ }
+ };
+ let rc = get_error_code(&e);
+ Err(BinderStatus::new_service_specific_error(rc, msg.as_deref()))
+ },
+ handle_ok,
+ )
+}
+
+/// Extracts the error code from an `anyhow::Error` mapping any error that does not have a
+/// root cause of `Error::Rc` onto `ResponseCode::SYSTEM_ERROR` and to `e` with `Error::Rc(e)`
+/// otherwise.
+fn get_error_code(e: &anyhow::Error) -> i32 {
+ let root_cause = e.root_cause();
+ match root_cause.downcast_ref::<Error>() {
+ Some(Error::Rc(rcode)) => rcode.0,
+ // If an Error::Binder reaches this stage we report a system error.
+ // The exception code and possible service specific error will be
+ // printed in the error log above.
+ Some(Error::Binder(_, _)) | Some(Error::BinderTransaction(_)) => {
+ ResponseCode::SYSTEM_ERROR.0
+ }
+ None => match root_cause.downcast_ref::<selinux::Error>() {
+ Some(selinux::Error::PermissionDenied) => ResponseCode::PERMISSION_DENIED.0,
+ _ => ResponseCode::SYSTEM_ERROR.0,
+ },
+ }
+}
diff --git a/diced/src/error_vendor.rs b/diced/src/error_vendor.rs
new file mode 100644
index 0000000..10d50dd
--- /dev/null
+++ b/diced/src/error_vendor.rs
@@ -0,0 +1,121 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use android_hardware_security_dice::aidl::android::hardware::security::dice::ResponseCode::ResponseCode;
+use anyhow::Result;
+use binder::public_api::{
+ ExceptionCode, Result as BinderResult, Status as BinderStatus, StatusCode,
+};
+use std::ffi::CString;
+
+/// This is the error type for DICE HAL implementations. It wraps
+/// `android::hardware::security::dice::ResponseCode` generated
+/// from AIDL in the `Rc` variant and Binder and BinderTransaction errors in the respective
+/// variants.
+#[allow(dead_code)] // Binder error forwarding will be needed when proxy nodes are implemented.
+#[derive(Debug, thiserror::Error, Eq, PartialEq, Clone)]
+pub enum Error {
+ /// Wraps a dice `ResponseCode` as defined by the Keystore AIDL interface specification.
+ #[error("Error::Rc({0:?})")]
+ Rc(ResponseCode),
+ /// Wraps a Binder exception code other than a service specific exception.
+ #[error("Binder exception code {0:?}, {1:?}")]
+ Binder(ExceptionCode, i32),
+ /// Wraps a Binder status code.
+ #[error("Binder transaction error {0:?}")]
+ BinderTransaction(StatusCode),
+}
+
+/// This function should be used by dice service calls to translate error conditions
+/// into service specific exceptions.
+///
+/// All error conditions get logged by this function.
+///
+/// All `Error::Rc(x)` variants get mapped onto a service specific error code of x.
+/// `selinux::Error::PermissionDenied` is mapped on `ResponseCode::PERMISSION_DENIED`.
+///
+/// All non `Error` error conditions and the Error::Binder variant get mapped onto
+/// ResponseCode::SYSTEM_ERROR`.
+///
+/// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
+/// as argument to `handle_ok`. `handle_ok` must generate a `BinderResult<T>`, but it
+/// typically returns Ok(value).
+///
+/// # Examples
+///
+/// ```
+/// fn do_something() -> anyhow::Result<Vec<u8>> {
+/// Err(anyhow!(Error::Rc(ResponseCode::NOT_IMPLEMENTED)))
+/// }
+///
+/// map_or_log_err(do_something(), Ok)
+/// ```
+pub fn map_or_log_err<T, U, F>(result: Result<U>, handle_ok: F) -> BinderResult<T>
+where
+ F: FnOnce(U) -> BinderResult<T>,
+{
+ map_err_with(
+ result,
+ |e| {
+ log::error!("{:?}", e);
+ e
+ },
+ handle_ok,
+ )
+}
+
+/// This function behaves similar to map_or_log_error, but it does not log the errors, instead
+/// it calls map_err on the error before mapping it to a binder result allowing callers to
+/// log or transform the error before mapping it.
+fn map_err_with<T, U, F1, F2>(result: Result<U>, map_err: F1, handle_ok: F2) -> BinderResult<T>
+where
+ F1: FnOnce(anyhow::Error) -> anyhow::Error,
+ F2: FnOnce(U) -> BinderResult<T>,
+{
+ result.map_or_else(
+ |e| {
+ let e = map_err(e);
+ let msg = match CString::new(format!("{:?}", e)) {
+ Ok(msg) => Some(msg),
+ Err(_) => {
+ log::warn!(
+ "Cannot convert error message to CStr. It contained a nul byte.
+ Omitting message from service specific error."
+ );
+ None
+ }
+ };
+ let rc = get_error_code(&e);
+ Err(BinderStatus::new_service_specific_error(rc, msg.as_deref()))
+ },
+ handle_ok,
+ )
+}
+
+/// Extracts the error code from an `anyhow::Error` mapping any error that does not have a
+/// root cause of `Error::Rc` onto `ResponseCode::SYSTEM_ERROR` and to `e` with `Error::Rc(e)`
+/// otherwise.
+fn get_error_code(e: &anyhow::Error) -> i32 {
+ let root_cause = e.root_cause();
+ match root_cause.downcast_ref::<Error>() {
+ Some(Error::Rc(rcode)) => rcode.0,
+ // If an Error::Binder reaches this stage we report a system error.
+ // The exception code and possible service specific error will be
+ // printed in the error log above.
+ Some(Error::Binder(_, _)) | Some(Error::BinderTransaction(_)) => {
+ ResponseCode::SYSTEM_ERROR.0
+ }
+ None => ResponseCode::SYSTEM_ERROR.0,
+ }
+}
diff --git a/diced/src/hal_node.rs b/diced/src/hal_node.rs
new file mode 100644
index 0000000..fd5384f
--- /dev/null
+++ b/diced/src/hal_node.rs
@@ -0,0 +1,722 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! This module provides `ResidentHal`, an implementation of a IDiceDevice HAL Interface.
+//! While the name implies that the DICE secrets are memory resident, the residency
+//! is augmented by the implementation of the traits `DiceArtifacts` and
+//! `UpdatableDiceArtifacts`. The implementation outsources all operations that
+//! involve the DICE secrets to a short lived child process. By implementing
+//! `UpdatableDiceArtifacts` accordingly, integrators can limit the exposure of
+//! the resident DICE secrets to user space memory. E.g., an implementation might only
+//! hold a path to a securefs file allowing the child to read and update the kernel state
+//! through this path directly.
+//!
+//! ## Important Safety Note.
+//! The module is not safe to use in multi threaded processes. It uses fork and runs
+//! code that is not async signal safe in the child. Implementing a HAL service without
+//! starting a thread pool is safe, but no secondary thread must be created.
+
+use crate::error_vendor::map_or_log_err;
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Bcc::Bcc, BccHandover::BccHandover, IDiceDevice::BnDiceDevice, IDiceDevice::IDiceDevice,
+ InputValues::InputValues as BinderInputValues, Signature::Signature,
+};
+use anyhow::{Context, Result};
+use binder::public_api::{BinderFeatures, Result as BinderResult, Strong};
+use dice::{ContextImpl, OpenDiceCborContext};
+use diced_open_dice_cbor as dice;
+use diced_utils as utils;
+use nix::sys::wait::{waitpid, WaitStatus};
+use nix::unistd::{
+ close, fork, pipe as nix_pipe, read as nix_read, write as nix_write, ForkResult,
+};
+use serde::{de::DeserializeOwned, Deserialize, Serialize};
+use std::convert::TryInto;
+use std::io::{Read, Write};
+use std::os::unix::io::RawFd;
+use std::sync::{Arc, RwLock};
+use utils::ResidentArtifacts;
+pub use utils::{DiceArtifacts, UpdatableDiceArtifacts};
+
+/// PipeReader is a simple wrapper around raw pipe file descriptors.
+/// It takes ownership of the file descriptor and closes it on drop. It provides `read_all`, which
+/// reads from the pipe into an expending vector, until no more data can be read.
+struct PipeReader(RawFd);
+
+impl Read for PipeReader {
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ let bytes = nix_read(self.0, buf)?;
+ Ok(bytes)
+ }
+}
+
+impl Drop for PipeReader {
+ fn drop(&mut self) {
+ close(self.0).expect("Failed to close reader pipe fd.");
+ }
+}
+
+/// PipeWriter is a simple wrapper around raw pipe file descriptors.
+/// It takes ownership of the file descriptor and closes it on drop. It provides `write`, which
+/// writes the given buffer into the pipe, returning the number of bytes written.
+struct PipeWriter(RawFd);
+
+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(())
+ }
+}
+
+impl Drop for PipeWriter {
+ fn drop(&mut self) {
+ close(self.0).expect("Failed to close writer pipe fd.");
+ }
+}
+
+fn pipe() -> Result<(PipeReader, PipeWriter), nix::Error> {
+ let (read_fd, write_fd) = nix_pipe()?;
+ Ok((PipeReader(read_fd), PipeWriter(write_fd)))
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, thiserror::Error)]
+enum RunForkedError {
+ #[error("RunForkedError::String({0:?})")]
+ String(String),
+}
+
+/// Run the given closure in a new process.
+/// Safety: The function runs code that is not async-signal-safe in the child after forking.
+/// This means, that this function must not be called by a multi threaded process.
+fn run_forked<F, R>(f: F) -> Result<R>
+where
+ R: Serialize + DeserializeOwned,
+ F: FnOnce() -> Result<R>,
+{
+ let (reader, writer) = pipe().expect("Failed to create pipe.");
+
+ match unsafe { 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.
+ // Deserialize the result and return it.
+ let result: Result<R, RunForkedError> =
+ serde_cbor::from_reader(reader).expect("Failed to deserialize result.");
+
+ result.context("In run_forked:")
+ } else {
+ panic!("Child did not exit as expected {:?}", status);
+ }
+ }
+ Ok(ForkResult::Child) => {
+ // Run the closure.
+ let result = f()
+ .map_err(|err| RunForkedError::String(format! {"Nested anyhow error {:?}", err}));
+
+ // Serialize the result of the closure.
+ serde_cbor::to_writer(writer, &result).expect("Result serialization failed");
+
+ // Set exit status to `0`.
+ std::process::exit(0);
+ }
+ Err(errno) => {
+ panic!("Failed to fork: {:?}", errno);
+ }
+ }
+}
+
+/// A DiceHal backend implementation.
+/// All functions, except `demote`, derive effective dice artifacts starting from
+/// this node and iterating through `input_values` in ascending order.
+pub trait DiceHalImpl {
+ /// Signs the message using the effective dice artifacts and Ed25519Pure.
+ fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature>;
+ /// Returns the effective attestation chain.
+ fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc>;
+ /// Returns the effective dice artifacts.
+ fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover>;
+ /// This demotes the implementation itself. I.e. a resident node would replace its resident
+ /// artifacts with the effective artifacts derived using `input_values`. A proxy node would
+ /// simply call `demote` on its parent node. This is not reversible and changes
+ /// the effective dice artifacts of all clients.
+ fn demote(&self, input_values: &[BinderInputValues]) -> Result<()>;
+}
+
+/// The ResidentHal implements a IDiceDevice backend with memory resident DICE secrets.
+pub struct ResidentHal<T: UpdatableDiceArtifacts + Serialize + DeserializeOwned + Clone + Send> {
+ artifacts: RwLock<T>,
+}
+
+impl<T: UpdatableDiceArtifacts + Serialize + DeserializeOwned + Clone + Send> ResidentHal<T> {
+ /// Creates a new Resident node with the given dice secrets and certificate chain.
+ /// ## Safety
+ /// It is not safe to use implementations of ResidentHal in multi threaded environments.
+ /// If using this library to implement a HAL service make sure not to start a thread pool.
+ pub unsafe fn new(artifacts: T) -> Result<Self> {
+ Ok(ResidentHal { artifacts: RwLock::new(artifacts) })
+ }
+
+ fn with_effective_artifacts<R, F>(&self, input_values: &[BinderInputValues], f: F) -> Result<R>
+ where
+ R: Serialize + DeserializeOwned,
+ F: FnOnce(ResidentArtifacts) -> Result<R>,
+ {
+ let artifacts = self.artifacts.read().unwrap().clone();
+
+ // Safety: run_forked must not be be called by a multi threaded process.
+ // This requirement is propagated to the public interface of this module through
+ // `ResidentHal::new`
+ run_forked(move || {
+ let artifacts = artifacts.with_artifacts(|a| ResidentArtifacts::new_from(a))?;
+ let input_values: Vec<utils::InputValues> =
+ input_values.iter().map(|v| v.try_into()).collect::<Result<_>>()?;
+ let artifacts = artifacts
+ .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+ .context("In ResidentHal::get_effective_artifacts:")?;
+ f(artifacts)
+ })
+ }
+}
+
+impl<T: UpdatableDiceArtifacts + Serialize + DeserializeOwned + Clone + Send> DiceHalImpl
+ for ResidentHal<T>
+{
+ fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature> {
+ let signature: Vec<u8> = self
+ .with_effective_artifacts(input_values, |artifacts| {
+ let (cdi_attest, _, _) = artifacts.into_tuple();
+ let mut dice = OpenDiceCborContext::new();
+ let seed = dice
+ .derive_cdi_private_key_seed(cdi_attest[..].try_into().with_context(|| {
+ format!(
+ "In ResidentHal::sign: Failed to convert cdi_attest (length: {}).",
+ cdi_attest.len()
+ )
+ })?)
+ .context("In ResidentHal::sign: Failed to derive seed from cdi_attest.")?;
+ let (_public_key, private_key) = dice
+ .keypair_from_seed(seed[..].try_into().with_context(|| {
+ format!(
+ "In ResidentHal::sign: Failed to convert seed (length: {}).",
+ seed.len()
+ )
+ })?)
+ .context("In ResidentHal::sign: Failed to derive keypair from seed.")?;
+ dice.sign(
+ message,
+ private_key[..].try_into().with_context(|| {
+ format!(
+ "In ResidentHal::sign: Failed to convert private_key (length: {}).",
+ private_key.len()
+ )
+ })?,
+ )
+ .context("In ResidentHal::sign: Failed to sign.")
+ })
+ .context("In ResidentHal::sign:")?;
+ Ok(Signature { data: signature })
+ }
+
+ fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc> {
+ let bcc = self
+ .with_effective_artifacts(input_values, |artifacts| {
+ let (_, _, bcc) = artifacts.into_tuple();
+ Ok(bcc)
+ })
+ .context("In ResidentHal::get_attestation_chain: Failed to get effective_artifacts.")?;
+
+ Ok(Bcc { data: bcc })
+ }
+
+ fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover> {
+ let (cdi_attest, cdi_seal, bcc): (Vec<u8>, Vec<u8>, Vec<u8>) = self
+ .with_effective_artifacts(input_values, |artifacts| {
+ let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
+ Ok((cdi_attest[..].to_vec(), cdi_seal[..].to_vec(), bcc))
+ })?;
+
+ utils::make_bcc_handover(
+ &cdi_attest
+ .as_slice()
+ .try_into()
+ .context("In ResidentHal::derive: Trying to convert cdi_attest to sized array.")?,
+ &cdi_seal
+ .as_slice()
+ .try_into()
+ .context("In ResidentHal::derive: Trying to convert cdi_seal to sized array.")?,
+ &bcc,
+ )
+ .context("In ResidentHal::derive: Trying to construct BccHandover.")
+ }
+
+ fn demote(&self, input_values: &[BinderInputValues]) -> Result<()> {
+ let mut artifacts = self.artifacts.write().unwrap();
+
+ let artifacts_clone = (*artifacts).clone();
+
+ // Safety: run_forked may not be called from a multi threaded process.
+ // This requirement is propagated to the public interface of this module through
+ // `ResidentHal::new`
+ *artifacts = run_forked(|| {
+ let new_artifacts =
+ artifacts_clone.with_artifacts(|a| ResidentArtifacts::new_from(a))?;
+ let input_values: Vec<utils::InputValues> =
+ input_values.iter().map(|v| v.try_into()).collect::<Result<_>>()?;
+
+ let new_artifacts = new_artifacts
+ .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+ .context("In ResidentHal::get_effective_artifacts:")?;
+ artifacts_clone.update(&new_artifacts)
+ })?;
+
+ Ok(())
+ }
+}
+
+/// Implements android.hardware.security.dice.IDiceDevice. Forwards public API calls
+/// to the given DiceHalImpl backend.
+pub struct DiceDevice {
+ hal_impl: Arc<dyn DiceHalImpl + Sync + Send>,
+}
+
+impl DiceDevice {
+ /// Constructs an instance of DiceDevice, wraps it with a BnDiceDevice object and
+ /// returns a strong pointer to the binder. The result can be used to register
+ /// the service with service manager.
+ pub fn new_as_binder(
+ hal_impl: Arc<dyn DiceHalImpl + Sync + Send>,
+ ) -> Result<Strong<dyn IDiceDevice>> {
+ let result = BnDiceDevice::new_binder(DiceDevice { hal_impl }, BinderFeatures::default());
+ Ok(result)
+ }
+}
+
+impl binder::Interface for DiceDevice {}
+
+impl IDiceDevice for DiceDevice {
+ fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> BinderResult<Signature> {
+ map_or_log_err(self.hal_impl.sign(input_values, message), Ok)
+ }
+ fn getAttestationChain(&self, input_values: &[BinderInputValues]) -> BinderResult<Bcc> {
+ map_or_log_err(self.hal_impl.get_attestation_chain(input_values), Ok)
+ }
+ fn derive(&self, input_values: &[BinderInputValues]) -> BinderResult<BccHandover> {
+ map_or_log_err(self.hal_impl.derive(input_values), Ok)
+ }
+ fn demote(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
+ map_or_log_err(self.hal_impl.demote(input_values), Ok)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ BccHandover::BccHandover, Config::Config as BinderConfig,
+ InputValues::InputValues as BinderInputValues, Mode::Mode as BinderMode,
+ };
+ use anyhow::{Context, Result};
+ use diced_open_dice_cbor as dice;
+ use diced_sample_inputs;
+ use diced_utils as utils;
+
+ #[derive(Debug, Serialize, Deserialize, Clone)]
+ struct InsecureSerializableArtifacts {
+ cdi_attest: [u8; dice::CDI_SIZE],
+ cdi_seal: [u8; dice::CDI_SIZE],
+ bcc: Vec<u8>,
+ }
+
+ impl DiceArtifacts for InsecureSerializableArtifacts {
+ fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
+ &self.cdi_attest
+ }
+ fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
+ &self.cdi_seal
+ }
+ fn bcc(&self) -> Vec<u8> {
+ self.bcc.clone()
+ }
+ }
+
+ impl UpdatableDiceArtifacts for InsecureSerializableArtifacts {
+ fn with_artifacts<F, T>(&self, f: F) -> Result<T>
+ where
+ F: FnOnce(&dyn DiceArtifacts) -> Result<T>,
+ {
+ f(self)
+ }
+ fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self> {
+ Ok(Self {
+ cdi_attest: *new_artifacts.cdi_attest(),
+ cdi_seal: *new_artifacts.cdi_seal(),
+ bcc: new_artifacts.bcc(),
+ })
+ }
+ }
+
+ fn make_input_values(
+ code: &str,
+ config_name: &str,
+ authority: &str,
+ ) -> Result<BinderInputValues> {
+ let mut dice_ctx = dice::OpenDiceCborContext::new();
+ Ok(BinderInputValues {
+ codeHash: dice_ctx
+ .hash(code.as_bytes())
+ .context("In make_input_values: code hash failed.")?,
+ config: BinderConfig {
+ desc: dice::bcc::format_config_descriptor(Some(config_name), None, true)
+ .context("In make_input_values: Failed to format config descriptor.")?,
+ },
+ authorityHash: dice_ctx
+ .hash(authority.as_bytes())
+ .context("In make_input_values: authority hash failed.")?,
+ authorityDescriptor: None,
+ mode: BinderMode::NORMAL,
+ hidden: vec![0; dice::HIDDEN_SIZE],
+ })
+ }
+
+ /// Test the resident artifact batched derivation in process.
+ #[test]
+ fn derive_with_resident_artifacts() -> Result<()> {
+ let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()?;
+
+ let artifacts =
+ ResidentArtifacts::new(cdi_attest[..].try_into()?, cdi_seal[..].try_into()?, &bcc)?;
+
+ let input_values = &[
+ make_input_values("component 1 code", "component 1", "component 1 authority")?,
+ make_input_values("component 2 code", "component 2", "component 2 authority")?,
+ make_input_values("component 3 code", "component 3", "component 3 authority")?,
+ ];
+
+ let input_values: Vec<utils::InputValues> =
+ input_values.iter().map(|v| v.try_into()).collect::<Result<_>>()?;
+
+ let new_artifacts =
+ artifacts.execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))?;
+
+ let result = utils::make_bcc_handover(
+ new_artifacts.cdi_attest(),
+ new_artifacts.cdi_seal(),
+ &new_artifacts.bcc(),
+ )?;
+
+ assert_eq!(result, make_derive_test_vector());
+ Ok(())
+ }
+
+ /// Test the ResidentHal hal implementation which performs the derivation in a separate
+ /// process and returns the result through a pipe. This test compares the result against
+ /// the same test vector as the in process test above.
+ #[test]
+ fn derive_with_insecure_artifacts() -> Result<()> {
+ let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()?;
+
+ // Safety: ResidentHal can only be used in single threaded environments.
+ // On-device Rust tests run each test in a separate process.
+ let hal_impl = unsafe {
+ ResidentHal::new(InsecureSerializableArtifacts {
+ cdi_attest: cdi_attest[..].try_into()?,
+ cdi_seal: cdi_seal[..].try_into()?,
+ bcc,
+ })
+ }
+ .expect("Failed to create ResidentHal.");
+
+ let bcc_handover = hal_impl
+ .derive(&[
+ make_input_values("component 1 code", "component 1", "component 1 authority")?,
+ make_input_values("component 2 code", "component 2", "component 2 authority")?,
+ make_input_values("component 3 code", "component 3", "component 3 authority")?,
+ ])
+ .expect("Failed to derive artifacts.");
+
+ assert_eq!(bcc_handover, make_derive_test_vector());
+ Ok(())
+ }
+
+ /// Demoting the implementation two steps and then performing one step of child derivation
+ /// must yield the same outcome as three derivations with the same input values.
+ #[test]
+ fn demote() -> Result<()> {
+ let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()?;
+
+ // Safety: ResidentHal can only be used in single threaded environments.
+ // On-device Rust tests run each test in a separate process.
+ let hal_impl = unsafe {
+ ResidentHal::new(InsecureSerializableArtifacts {
+ cdi_attest: cdi_attest[..].try_into()?,
+ cdi_seal: cdi_seal[..].try_into()?,
+ bcc,
+ })
+ }
+ .expect("Failed to create ResidentHal.");
+
+ hal_impl
+ .demote(&[
+ make_input_values("component 1 code", "component 1", "component 1 authority")?,
+ make_input_values("component 2 code", "component 2", "component 2 authority")?,
+ ])
+ .expect("Failed to demote implementation.");
+
+ let bcc_handover = hal_impl
+ .derive(&[make_input_values(
+ "component 3 code",
+ "component 3",
+ "component 3 authority",
+ )?])
+ .expect("Failed to derive artifacts.");
+
+ assert_eq!(bcc_handover, make_derive_test_vector());
+ Ok(())
+ }
+
+ fn make_derive_test_vector() -> BccHandover {
+ utils::make_bcc_handover(
+ &[
+ // cdi_attest
+ 0x8f, 0xdf, 0x93, 0x67, 0xd7, 0x0e, 0xf8, 0xb8, 0xd2, 0x9c, 0x30, 0xeb, 0x4e, 0x9b,
+ 0x71, 0x5f, 0x9a, 0x5b, 0x67, 0xa6, 0x29, 0xe0, 0x00, 0x9b, 0x4d, 0xe6, 0x95, 0xcf,
+ 0xf9, 0xed, 0x5e, 0x9b,
+ ],
+ &[
+ // cdi_seal
+ 0x15, 0x3e, 0xd6, 0x30, 0x5a, 0x8d, 0x4b, 0x6f, 0x07, 0x3f, 0x5d, 0x89, 0xc5, 0x6e,
+ 0x30, 0xba, 0x05, 0x56, 0xfc, 0x66, 0xf4, 0xae, 0xce, 0x7f, 0x81, 0xb9, 0xc5, 0x21,
+ 0x9b, 0x49, 0x3d, 0xe1,
+ ],
+ &[
+ // bcc
+ 0x87, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x3e,
+ 0x85, 0xe5, 0x72, 0x75, 0x55, 0xe5, 0x1e, 0xe7, 0xf3, 0x35, 0x94, 0x8e, 0xbb, 0xbd,
+ 0x74, 0x1e, 0x1d, 0xca, 0x49, 0x9c, 0x97, 0x39, 0x77, 0x06, 0xd3, 0xc8, 0x6e, 0x8b,
+ 0xd7, 0x33, 0xf9, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01,
+ 0x78, 0x28, 0x34, 0x32, 0x64, 0x38, 0x38, 0x36, 0x34, 0x66, 0x39, 0x37, 0x62, 0x36,
+ 0x35, 0x34, 0x37, 0x61, 0x35, 0x30, 0x63, 0x31, 0x65, 0x30, 0x61, 0x37, 0x34, 0x39,
+ 0x66, 0x38, 0x65, 0x66, 0x38, 0x62, 0x38, 0x31, 0x65, 0x63, 0x36, 0x32, 0x61, 0x66,
+ 0x02, 0x78, 0x28, 0x31, 0x66, 0x36, 0x39, 0x36, 0x66, 0x30, 0x37, 0x32, 0x35, 0x32,
+ 0x66, 0x32, 0x39, 0x65, 0x39, 0x33, 0x66, 0x65, 0x34, 0x64, 0x65, 0x31, 0x39, 0x65,
+ 0x65, 0x33, 0x32, 0x63, 0x64, 0x38, 0x31, 0x64, 0x63, 0x34, 0x30, 0x34, 0x65, 0x37,
+ 0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x16, 0x48, 0xf2, 0x55, 0x53, 0x23,
+ 0xdd, 0x15, 0x2e, 0x83, 0x38, 0xc3, 0x64, 0x38, 0x63, 0x26, 0x0f, 0xcf, 0x5b, 0xd1,
+ 0x3a, 0xd3, 0x40, 0x3e, 0x23, 0xf8, 0x34, 0x4c, 0x6d, 0xa2, 0xbe, 0x25, 0x1c, 0xb0,
+ 0x29, 0xe8, 0xc3, 0xfb, 0xb8, 0x80, 0xdc, 0xb1, 0xd2, 0xb3, 0x91, 0x4d, 0xd3, 0xfb,
+ 0x01, 0x0f, 0xe4, 0xe9, 0x46, 0xa2, 0xc0, 0x26, 0x57, 0x5a, 0xba, 0x30, 0xf7, 0x15,
+ 0x98, 0x14, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x56, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71,
+ 0x63, 0x41, 0x42, 0x4c, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11,
+ 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0x47, 0xae, 0x42, 0x27, 0x4c,
+ 0xcb, 0x65, 0x4d, 0xee, 0x74, 0x2d, 0x05, 0x78, 0x2a, 0x08, 0x2a, 0xa5, 0xf0, 0xcf,
+ 0xea, 0x3e, 0x60, 0xee, 0x97, 0x11, 0x4b, 0x5b, 0xe6, 0x05, 0x0c, 0xe8, 0x90, 0xf5,
+ 0x22, 0xc4, 0xc6, 0x67, 0x7a, 0x22, 0x27, 0x17, 0xb3, 0x79, 0xcc, 0x37, 0x64, 0x5e,
+ 0x19, 0x4f, 0x96, 0x37, 0x67, 0x3c, 0xd0, 0xc5, 0xed, 0x0f, 0xdd, 0xe7, 0x2e, 0x4f,
+ 0x70, 0x97, 0x30, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xf9, 0x00, 0x9d, 0xc2,
+ 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd, 0xe3, 0x97, 0x4a, 0xcb, 0x3c, 0xe7, 0x6b, 0x24,
+ 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59, 0x15, 0xb1, 0x23, 0xe6, 0xc8, 0xdf,
+ 0xfb, 0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b, 0x37, 0x0e, 0x12, 0x12,
+ 0xb2, 0xfd, 0xc1, 0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6, 0x29, 0x1b, 0x99, 0xea,
+ 0xae, 0xfd, 0xaa, 0x0d, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47,
+ 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06,
+ 0x21, 0x58, 0x20, 0xb1, 0x02, 0xcc, 0x2c, 0xb2, 0x6a, 0x3b, 0xe9, 0xc1, 0xd3, 0x95,
+ 0x10, 0xa0, 0xe1, 0xff, 0x51, 0xde, 0x57, 0xd5, 0x65, 0x28, 0xfd, 0x7f, 0xeb, 0xd4,
+ 0xca, 0x15, 0xf3, 0xca, 0xdf, 0x37, 0x88, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20,
+ 0x58, 0x40, 0x58, 0xd8, 0x03, 0x24, 0x53, 0x60, 0x57, 0xa9, 0x09, 0xfa, 0xab, 0xdc,
+ 0x57, 0x1e, 0xf0, 0xe5, 0x1e, 0x51, 0x6f, 0x9e, 0xa3, 0x42, 0xe6, 0x6a, 0x8c, 0xaa,
+ 0xad, 0x08, 0x48, 0xde, 0x7f, 0x4f, 0x6e, 0x2f, 0x7f, 0x39, 0x6c, 0xa1, 0xf8, 0x42,
+ 0x71, 0xfe, 0x17, 0x3d, 0xca, 0x31, 0x83, 0x92, 0xed, 0xbb, 0x40, 0xb8, 0x10, 0xe0,
+ 0xf2, 0x5a, 0x99, 0x53, 0x38, 0x46, 0x33, 0x97, 0x78, 0x05, 0x84, 0x43, 0xa1, 0x01,
+ 0x27, 0xa0, 0x59, 0x01, 0x8a, 0xa9, 0x01, 0x78, 0x28, 0x31, 0x66, 0x36, 0x39, 0x36,
+ 0x66, 0x30, 0x37, 0x32, 0x35, 0x32, 0x66, 0x32, 0x39, 0x65, 0x39, 0x33, 0x66, 0x65,
+ 0x34, 0x64, 0x65, 0x31, 0x39, 0x65, 0x65, 0x33, 0x32, 0x63, 0x64, 0x38, 0x31, 0x64,
+ 0x63, 0x34, 0x30, 0x34, 0x65, 0x37, 0x36, 0x02, 0x78, 0x28, 0x32, 0x35, 0x39, 0x34,
+ 0x38, 0x39, 0x65, 0x36, 0x39, 0x37, 0x34, 0x38, 0x37, 0x30, 0x35, 0x64, 0x65, 0x33,
+ 0x65, 0x32, 0x66, 0x34, 0x34, 0x32, 0x36, 0x37, 0x65, 0x61, 0x34, 0x39, 0x33, 0x38,
+ 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58,
+ 0x40, 0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa, 0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83,
+ 0x7f, 0x46, 0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14, 0x1f, 0x6e, 0xb3, 0xa0, 0xd9,
+ 0x56, 0xb3, 0xbf, 0x2f, 0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4, 0xd2, 0xa9, 0x6b,
+ 0x18, 0x28, 0xe8, 0x29, 0x20, 0x49, 0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54, 0xe9,
+ 0x71, 0xd2, 0x7e, 0xa4, 0xfe, 0x58, 0x7f, 0xd3, 0xc7, 0x3a, 0x00, 0x47, 0x44, 0x53,
+ 0x56, 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x63, 0x41, 0x56, 0x42, 0x3a, 0x00, 0x01,
+ 0x11, 0x72, 0x01, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52,
+ 0x58, 0x40, 0x93, 0x17, 0xe1, 0x11, 0x27, 0x59, 0xd0, 0xef, 0x75, 0x0b, 0x2b, 0x1c,
+ 0x0f, 0x5f, 0x52, 0xc3, 0x29, 0x23, 0xb5, 0x2a, 0xe6, 0x12, 0x72, 0x6f, 0x39, 0x86,
+ 0x65, 0x2d, 0xf2, 0xe4, 0xe7, 0xd0, 0xaf, 0x0e, 0xa7, 0x99, 0x16, 0x89, 0x97, 0x21,
+ 0xf7, 0xdc, 0x89, 0xdc, 0xde, 0xbb, 0x94, 0x88, 0x1f, 0xda, 0xe2, 0xf3, 0xe0, 0x54,
+ 0xf9, 0x0e, 0x29, 0xb1, 0xbd, 0xe1, 0x0c, 0x0b, 0xd7, 0xf6, 0x3a, 0x00, 0x47, 0x44,
+ 0x54, 0x58, 0x40, 0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56,
+ 0xd9, 0x02, 0x35, 0x2b, 0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4,
+ 0xc2, 0xf1, 0xf9, 0x35, 0x7d, 0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c,
+ 0x12, 0x78, 0x5c, 0x9c, 0x3e, 0xf6, 0x66, 0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f,
+ 0xc9, 0x72, 0xee, 0x73, 0x43, 0x02, 0x8a, 0xef, 0xbc, 0x05, 0x98, 0x3a, 0x00, 0x47,
+ 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01,
+ 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x96, 0x6d, 0x96, 0x42,
+ 0xda, 0x64, 0x51, 0xad, 0xfa, 0x00, 0xbc, 0xbc, 0x95, 0x8a, 0xb0, 0xb9, 0x76, 0x01,
+ 0xe6, 0xbd, 0xc0, 0x26, 0x79, 0x26, 0xfc, 0x0f, 0x1d, 0x87, 0x65, 0xf1, 0xf3, 0x99,
+ 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x10, 0x7f, 0x77, 0xad, 0x70,
+ 0xbd, 0x52, 0x81, 0x28, 0x8d, 0x24, 0x81, 0xb4, 0x3f, 0x21, 0x68, 0x9f, 0xc3, 0x80,
+ 0x68, 0x86, 0x55, 0xfb, 0x2e, 0x6d, 0x96, 0xe1, 0xe1, 0xb7, 0x28, 0x8d, 0x63, 0x85,
+ 0xba, 0x2a, 0x01, 0x33, 0x87, 0x60, 0x63, 0xbb, 0x16, 0x3f, 0x2f, 0x3d, 0xf4, 0x2d,
+ 0x48, 0x5b, 0x87, 0xed, 0xda, 0x34, 0xeb, 0x9c, 0x4d, 0x14, 0xac, 0x65, 0xf4, 0xfa,
+ 0xef, 0x45, 0x0b, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8f, 0xa9, 0x01,
+ 0x78, 0x28, 0x32, 0x35, 0x39, 0x34, 0x38, 0x39, 0x65, 0x36, 0x39, 0x37, 0x34, 0x38,
+ 0x37, 0x30, 0x35, 0x64, 0x65, 0x33, 0x65, 0x32, 0x66, 0x34, 0x34, 0x32, 0x36, 0x37,
+ 0x65, 0x61, 0x34, 0x39, 0x33, 0x38, 0x66, 0x66, 0x36, 0x61, 0x35, 0x37, 0x32, 0x35,
+ 0x02, 0x78, 0x28, 0x35, 0x64, 0x34, 0x65, 0x64, 0x37, 0x66, 0x34, 0x31, 0x37, 0x61,
+ 0x39, 0x35, 0x34, 0x61, 0x31, 0x38, 0x31, 0x34, 0x30, 0x37, 0x62, 0x35, 0x38, 0x38,
+ 0x35, 0x61, 0x66, 0x64, 0x37, 0x32, 0x61, 0x35, 0x62, 0x66, 0x34, 0x30, 0x64, 0x61,
+ 0x36, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 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, 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, 0x00, 0x00,
+ 0x00, 0x00, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x1a, 0xa3, 0x3a, 0x00, 0x01, 0x11,
+ 0x71, 0x67, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x3a, 0x00, 0x01, 0x11, 0x72,
+ 0x0c, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40,
+ 0x26, 0x1a, 0xbd, 0x26, 0xd8, 0x37, 0x8f, 0x4a, 0xf2, 0x9e, 0x49, 0x4d, 0x93, 0x23,
+ 0xc4, 0x6e, 0x02, 0xda, 0xe0, 0x00, 0x02, 0xe7, 0xed, 0x29, 0xdf, 0x2b, 0xb3, 0x69,
+ 0xf3, 0x55, 0x0e, 0x4c, 0x22, 0xdc, 0xcf, 0xf5, 0x92, 0xc9, 0xfa, 0x78, 0x98, 0xf1,
+ 0x0e, 0x55, 0x5f, 0xf4, 0x45, 0xed, 0xc0, 0x0a, 0x72, 0x2a, 0x7a, 0x3a, 0xd2, 0xb1,
+ 0xf7, 0x76, 0xfe, 0x2a, 0x6b, 0x7b, 0x2a, 0x53, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58,
+ 0x40, 0x04, 0x25, 0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30,
+ 0x03, 0xb8, 0xd6, 0xe1, 0x99, 0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c,
+ 0x37, 0x68, 0x4e, 0x1d, 0xc0, 0x24, 0x74, 0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1,
+ 0x43, 0xd2, 0x9c, 0xfc, 0x12, 0x9e, 0x77, 0x0a, 0xde, 0x29, 0x24, 0xff, 0x2e, 0xfa,
+ 0xc7, 0x10, 0xd5, 0x73, 0xd4, 0xc6, 0xdf, 0x62, 0x9f, 0x3a, 0x00, 0x47, 0x44, 0x56,
+ 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27,
+ 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xdb, 0xe7, 0x5b, 0x3f, 0xa3, 0x42,
+ 0xb0, 0x9c, 0xf8, 0x40, 0x8c, 0xb0, 0x9c, 0xf0, 0x0a, 0xaf, 0xdf, 0x6f, 0xe5, 0x09,
+ 0x21, 0x11, 0x92, 0xe1, 0xf8, 0xc5, 0x09, 0x02, 0x3d, 0x1f, 0xb7, 0xc5, 0x3a, 0x00,
+ 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0xc4, 0xc1, 0xd7, 0x1c, 0x2d, 0x26, 0x89,
+ 0x22, 0xcf, 0xa6, 0x99, 0x77, 0x30, 0x84, 0x86, 0x27, 0x59, 0x8f, 0xd8, 0x08, 0x75,
+ 0xe0, 0xb2, 0xef, 0xf9, 0xfa, 0xa5, 0x40, 0x8c, 0xd3, 0xeb, 0xbb, 0xda, 0xf2, 0xc8,
+ 0xae, 0x41, 0x22, 0x50, 0x9c, 0xe8, 0xb2, 0x9c, 0x9b, 0x3f, 0x8a, 0x78, 0x76, 0xab,
+ 0xd0, 0xbe, 0xfc, 0xe4, 0x79, 0xcb, 0x1b, 0x2b, 0xaa, 0x4d, 0xdd, 0x15, 0x61, 0x42,
+ 0x06, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8d, 0xa9, 0x01, 0x78, 0x28,
+ 0x35, 0x64, 0x34, 0x65, 0x64, 0x37, 0x66, 0x34, 0x31, 0x37, 0x61, 0x39, 0x35, 0x34,
+ 0x61, 0x31, 0x38, 0x31, 0x34, 0x30, 0x37, 0x62, 0x35, 0x38, 0x38, 0x35, 0x61, 0x66,
+ 0x64, 0x37, 0x32, 0x61, 0x35, 0x62, 0x66, 0x34, 0x30, 0x64, 0x61, 0x36, 0x02, 0x78,
+ 0x28, 0x36, 0x39, 0x62, 0x31, 0x37, 0x36, 0x37, 0x35, 0x38, 0x61, 0x36, 0x66, 0x34,
+ 0x34, 0x62, 0x35, 0x65, 0x38, 0x39, 0x39, 0x63, 0x64, 0x65, 0x33, 0x63, 0x66, 0x34,
+ 0x35, 0x31, 0x39, 0x61, 0x39, 0x33, 0x35, 0x62, 0x63, 0x39, 0x66, 0x65, 0x34, 0x3a,
+ 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0x31, 0x0d, 0x31, 0xfa, 0x78, 0x58, 0x33, 0xf2,
+ 0xf8, 0x58, 0x6b, 0xe9, 0x68, 0x32, 0x44, 0xd0, 0xfc, 0x2d, 0xe1, 0xfc, 0xe1, 0xc2,
+ 0x4e, 0x2b, 0xa8, 0x2c, 0xa1, 0xc1, 0x48, 0xc6, 0xaa, 0x91, 0x89, 0x4f, 0xb7, 0x9c,
+ 0x40, 0x74, 0x21, 0x36, 0x31, 0x45, 0x09, 0xdf, 0x0c, 0xb4, 0xf9, 0x9a, 0x59, 0xae,
+ 0x4f, 0x21, 0x10, 0xc1, 0x38, 0xa8, 0xa2, 0xbe, 0xc6, 0x36, 0xf0, 0x56, 0x58, 0xdb,
+ 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x18, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6b,
+ 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x20, 0x31, 0x3a, 0x00, 0x01,
+ 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0xce, 0x8a, 0x30, 0x4e,
+ 0x31, 0x53, 0xea, 0xdd, 0x2f, 0xbd, 0x15, 0xbc, 0x6b, 0x0f, 0xe7, 0x43, 0x50, 0xef,
+ 0x65, 0xec, 0x4e, 0x21, 0x64, 0x6e, 0x41, 0x22, 0xac, 0x87, 0xda, 0xf1, 0xf2, 0x80,
+ 0xc6, 0x8a, 0xd8, 0x7b, 0xe8, 0xe2, 0x9b, 0x87, 0x21, 0x5e, 0x26, 0x23, 0x11, 0x89,
+ 0x86, 0x57, 0x2d, 0x47, 0x73, 0x3f, 0x47, 0x87, 0xfa, 0x58, 0x5c, 0x78, 0x7b, 0xa3,
+ 0xfc, 0x2b, 0x6c, 0xed, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xd8, 0x40, 0xa0,
+ 0x60, 0x45, 0x28, 0x5d, 0xd4, 0xc1, 0x08, 0x3c, 0xbc, 0x91, 0xf4, 0xa6, 0xa4, 0xde,
+ 0xd3, 0x3d, 0xbb, 0x24, 0x46, 0xa3, 0x58, 0x49, 0x57, 0x4d, 0x2e, 0x6d, 0x7a, 0x78,
+ 0x4b, 0x9d, 0x28, 0x9a, 0x4e, 0xf1, 0x23, 0x06, 0x35, 0xff, 0x8e, 0x1e, 0xb3, 0x02,
+ 0x63, 0x62, 0x9a, 0x50, 0x6d, 0x18, 0x70, 0x8e, 0xe3, 0x2e, 0x29, 0xb4, 0x22, 0x71,
+ 0x31, 0x39, 0x65, 0xd5, 0xb5, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00,
+ 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20,
+ 0x06, 0x21, 0x58, 0x20, 0x51, 0x3c, 0x4b, 0x56, 0x0b, 0x49, 0x0b, 0xee, 0xc5, 0x71,
+ 0xd4, 0xe7, 0xbc, 0x44, 0x27, 0x4f, 0x4e, 0x67, 0xfc, 0x3a, 0xb9, 0x47, 0x8c, 0x6f,
+ 0x24, 0x29, 0xf8, 0xb8, 0x2f, 0xa7, 0xb3, 0x4d, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41,
+ 0x20, 0x58, 0x40, 0x4e, 0x6d, 0x0e, 0x2b, 0x1d, 0x44, 0x99, 0xb6, 0x63, 0x07, 0x86,
+ 0x1a, 0xce, 0x4b, 0xdc, 0xd1, 0x3a, 0xdc, 0xbf, 0xaa, 0xb3, 0x06, 0xd9, 0xb5, 0x5c,
+ 0x75, 0xf0, 0x14, 0x63, 0xa9, 0x1e, 0x7c, 0x56, 0x62, 0x2c, 0xa5, 0xda, 0xc9, 0x81,
+ 0xcb, 0x3d, 0x63, 0x32, 0x6b, 0x76, 0x81, 0xd2, 0x93, 0xeb, 0xac, 0xfe, 0x0c, 0x87,
+ 0x66, 0x9e, 0x87, 0x82, 0xb4, 0x81, 0x6e, 0x33, 0xf1, 0x08, 0x01, 0x84, 0x43, 0xa1,
+ 0x01, 0x27, 0xa0, 0x59, 0x01, 0x8d, 0xa9, 0x01, 0x78, 0x28, 0x36, 0x39, 0x62, 0x31,
+ 0x37, 0x36, 0x37, 0x35, 0x38, 0x61, 0x36, 0x66, 0x34, 0x34, 0x62, 0x35, 0x65, 0x38,
+ 0x39, 0x39, 0x63, 0x64, 0x65, 0x33, 0x63, 0x66, 0x34, 0x35, 0x31, 0x39, 0x61, 0x39,
+ 0x33, 0x35, 0x62, 0x63, 0x39, 0x66, 0x65, 0x34, 0x02, 0x78, 0x28, 0x32, 0x39, 0x65,
+ 0x34, 0x62, 0x61, 0x63, 0x33, 0x30, 0x31, 0x65, 0x66, 0x36, 0x35, 0x61, 0x38, 0x31,
+ 0x31, 0x62, 0x39, 0x39, 0x62, 0x30, 0x33, 0x64, 0x65, 0x39, 0x35, 0x34, 0x65, 0x61,
+ 0x37, 0x36, 0x61, 0x38, 0x39, 0x31, 0x37, 0x38, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x50,
+ 0x58, 0x40, 0xa4, 0x03, 0xe3, 0xde, 0x44, 0x96, 0xed, 0x31, 0x41, 0xa0, 0xba, 0x59,
+ 0xee, 0x2b, 0x03, 0x65, 0xcb, 0x63, 0x14, 0x78, 0xbe, 0xad, 0x24, 0x33, 0xb8, 0x6b,
+ 0x52, 0xd8, 0xab, 0xd5, 0x79, 0x84, 0x98, 0x6c, 0xc2, 0x66, 0xeb, 0x6c, 0x24, 0xa6,
+ 0xfa, 0x32, 0xa8, 0x16, 0xb8, 0x64, 0x37, 0x2b, 0xd4, 0xc0, 0xc4, 0xc2, 0x63, 0x25,
+ 0x10, 0xce, 0x47, 0xe3, 0x49, 0xad, 0x41, 0xf5, 0xc8, 0xf6, 0x3a, 0x00, 0x47, 0x44,
+ 0x53, 0x58, 0x18, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6b, 0x63, 0x6f, 0x6d, 0x70,
+ 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x20, 0x32, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a,
+ 0x00, 0x47, 0x44, 0x52, 0x58, 0x40, 0xc7, 0x50, 0x09, 0xd0, 0xe0, 0xdd, 0x80, 0x77,
+ 0xae, 0xa7, 0xc8, 0x88, 0x1e, 0x88, 0xd0, 0xc7, 0x0d, 0x7c, 0x49, 0xc5, 0xb5, 0x64,
+ 0x32, 0x28, 0x2c, 0x48, 0x94, 0xc0, 0xd6, 0x7d, 0x9c, 0x86, 0xda, 0xf7, 0x98, 0xc7,
+ 0xae, 0xa4, 0x0e, 0x61, 0xc8, 0xb0, 0x8b, 0x8a, 0xe4, 0xad, 0xcf, 0xcf, 0x6d, 0x60,
+ 0x60, 0x31, 0xdd, 0xa7, 0x24, 0x9b, 0x27, 0x16, 0x31, 0x90, 0x80, 0x70, 0xc3, 0xba,
+ 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40, 0xf8, 0x86, 0xc6, 0x94, 0xf9, 0x3f, 0x66,
+ 0x3c, 0x43, 0x01, 0x29, 0x27, 0x8d, 0x3c, 0xb2, 0x11, 0xf2, 0x04, 0xb6, 0x67, 0x4f,
+ 0x5f, 0x90, 0xcb, 0xc6, 0x73, 0xe6, 0x25, 0x14, 0x63, 0xa7, 0x95, 0x11, 0x0e, 0xa0,
+ 0x1d, 0x3f, 0x6a, 0x58, 0x0a, 0x53, 0xaa, 0x68, 0x3b, 0x92, 0x64, 0x2b, 0x2e, 0x79,
+ 0x80, 0x70, 0x0e, 0x41, 0xf5, 0xe9, 0x2a, 0x36, 0x0a, 0xa4, 0xe8, 0xb4, 0xe5, 0xdd,
+ 0xa6, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58,
+ 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20,
+ 0x9e, 0x04, 0x11, 0x24, 0x34, 0xba, 0x40, 0xed, 0x86, 0xe9, 0x48, 0x70, 0x3b, 0xe7,
+ 0x76, 0xfa, 0xc5, 0xf6, 0x6d, 0xab, 0x86, 0x12, 0x00, 0xbe, 0xc7, 0x00, 0x69, 0x0e,
+ 0x97, 0x97, 0xa6, 0x12, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0xb7,
+ 0x31, 0xd5, 0x4c, 0x7d, 0xf5, 0xd7, 0xb8, 0xb4, 0x4f, 0x93, 0x47, 0x2c, 0x3d, 0x50,
+ 0xcc, 0xad, 0x28, 0x23, 0x68, 0xcf, 0xc2, 0x90, 0xd7, 0x02, 0x00, 0xd8, 0xf1, 0x00,
+ 0x14, 0x03, 0x90, 0x9e, 0x0b, 0x91, 0xa7, 0x22, 0x28, 0xfe, 0x55, 0x42, 0x30, 0x93,
+ 0x05, 0x66, 0xcd, 0xce, 0xb8, 0x48, 0x07, 0x56, 0x54, 0x67, 0xa5, 0xd7, 0xe3, 0x16,
+ 0xd6, 0x75, 0x7c, 0x94, 0x98, 0x1b, 0x0b, 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59,
+ 0x01, 0x8d, 0xa9, 0x01, 0x78, 0x28, 0x32, 0x39, 0x65, 0x34, 0x62, 0x61, 0x63, 0x33,
+ 0x30, 0x31, 0x65, 0x66, 0x36, 0x35, 0x61, 0x38, 0x31, 0x31, 0x62, 0x39, 0x39, 0x62,
+ 0x30, 0x33, 0x64, 0x65, 0x39, 0x35, 0x34, 0x65, 0x61, 0x37, 0x36, 0x61, 0x38, 0x39,
+ 0x31, 0x37, 0x38, 0x35, 0x02, 0x78, 0x28, 0x31, 0x38, 0x37, 0x36, 0x63, 0x61, 0x63,
+ 0x34, 0x32, 0x33, 0x39, 0x35, 0x37, 0x66, 0x33, 0x62, 0x66, 0x62, 0x32, 0x62, 0x32,
+ 0x63, 0x39, 0x33, 0x37, 0x64, 0x31, 0x34, 0x62, 0x62, 0x38, 0x30, 0x64, 0x30, 0x36,
+ 0x37, 0x33, 0x65, 0x66, 0x66, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40, 0xf4, 0x7d,
+ 0x11, 0x21, 0xc1, 0x19, 0x57, 0x23, 0x08, 0x6e, 0x5f, 0xe4, 0x55, 0xc5, 0x08, 0x16,
+ 0x40, 0x5f, 0x2a, 0x6f, 0x04, 0x1e, 0x6f, 0x22, 0xde, 0x53, 0xbd, 0x37, 0xe2, 0xfb,
+ 0xb4, 0x0b, 0x65, 0xf4, 0xdc, 0xc9, 0xf4, 0xce, 0x2d, 0x82, 0x2a, 0xbc, 0xaf, 0x37,
+ 0x80, 0x0b, 0x7f, 0xff, 0x3a, 0x98, 0x9c, 0xa7, 0x70, 0x4f, 0xbc, 0x59, 0x4f, 0x4e,
+ 0xb1, 0x6d, 0xdf, 0x60, 0x39, 0x11, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x18, 0xa2,
+ 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
+ 0x74, 0x20, 0x33, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6, 0x3a, 0x00, 0x47, 0x44, 0x52,
+ 0x58, 0x40, 0xa4, 0xd5, 0x6f, 0xc8, 0xd6, 0xc7, 0xe4, 0x22, 0xb4, 0x7a, 0x26, 0x49,
+ 0xd5, 0xb4, 0xc1, 0xc6, 0x1b, 0xfa, 0x14, 0x8c, 0x49, 0x72, 0x2f, 0xfe, 0xbc, 0xc1,
+ 0xc8, 0xc6, 0x65, 0x62, 0x86, 0xf7, 0xf2, 0x74, 0x45, 0x9b, 0x1a, 0xa0, 0x2b, 0xc4,
+ 0x27, 0x13, 0xc5, 0xc3, 0xe5, 0x28, 0xc2, 0x16, 0xcd, 0x90, 0x6d, 0xa0, 0xf7, 0x27,
+ 0x04, 0xa8, 0xa2, 0x62, 0xaa, 0x2c, 0x0c, 0x75, 0xd5, 0x9d, 0x3a, 0x00, 0x47, 0x44,
+ 0x54, 0x58, 0x40, 0x1d, 0x92, 0x34, 0xfb, 0xfe, 0x74, 0xb7, 0xce, 0x3a, 0x95, 0x45,
+ 0xe5, 0x3e, 0x1f, 0x5f, 0x18, 0x53, 0x5f, 0xe1, 0x85, 0xb0, 0x1d, 0xe3, 0x8d, 0x53,
+ 0x77, 0xdc, 0x86, 0x32, 0x3d, 0x9b, 0xf9, 0xa5, 0x51, 0x17, 0x51, 0x9a, 0xd8, 0xa6,
+ 0x7d, 0x45, 0x98, 0x47, 0xa2, 0x73, 0x54, 0x66, 0x28, 0x66, 0x92, 0x1d, 0x28, 0x8a,
+ 0xe7, 0x5d, 0xb8, 0x96, 0x4b, 0x6a, 0x9d, 0xee, 0xc2, 0xe9, 0x20, 0x3a, 0x00, 0x47,
+ 0x44, 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01,
+ 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x4d, 0xf5, 0x61, 0x1e,
+ 0xa6, 0x64, 0x74, 0x0b, 0x6c, 0x99, 0x8b, 0x6d, 0x34, 0x42, 0x21, 0xdd, 0x82, 0x26,
+ 0x13, 0xb4, 0xf0, 0xbc, 0x9a, 0x0b, 0xf6, 0x56, 0xbd, 0x5d, 0xea, 0xd5, 0x07, 0x7a,
+ 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0x40, 0x4d, 0x09, 0x0d, 0x80,
+ 0xba, 0x12, 0x94, 0x05, 0xfb, 0x1a, 0x23, 0xa3, 0xcb, 0x28, 0x6f, 0xd7, 0x29, 0x95,
+ 0xda, 0x83, 0x07, 0x3c, 0xbe, 0x7c, 0x37, 0xeb, 0x9c, 0xb2, 0x77, 0x10, 0x3f, 0x6a,
+ 0x41, 0x80, 0xce, 0x56, 0xb7, 0x55, 0x22, 0x81, 0x77, 0x2d, 0x3c, 0xf8, 0x16, 0x38,
+ 0x49, 0xcc, 0x9a, 0xe8, 0x3a, 0x03, 0x33, 0x4c, 0xe6, 0x87, 0x72, 0xf6, 0x5a, 0x4a,
+ 0x3f, 0x4e, 0x0a,
+ ],
+ )
+ .unwrap()
+ }
+}
diff --git a/diced/src/lib.rs b/diced/src/lib.rs
new file mode 100644
index 0000000..8562406
--- /dev/null
+++ b/diced/src/lib.rs
@@ -0,0 +1,203 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Implement the android.security.dice.IDiceNode service.
+
+mod error;
+mod permission;
+mod proxy_node_hal;
+mod resident_node;
+
+pub use crate::proxy_node_hal::ProxyNodeHal;
+pub use crate::resident_node::ResidentNode;
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Bcc::Bcc, BccHandover::BccHandover, Config::Config as BinderConfig,
+ InputValues::InputValues as BinderInputValues, Mode::Mode, Signature::Signature,
+};
+use android_security_dice::aidl::android::security::dice::{
+ IDiceMaintenance::BnDiceMaintenance, IDiceMaintenance::IDiceMaintenance, IDiceNode::BnDiceNode,
+ IDiceNode::IDiceNode, ResponseCode::ResponseCode,
+};
+use anyhow::{Context, Result};
+use binder::{public_api::Result as BinderResult, BinderFeatures, Strong, ThreadState};
+pub use diced_open_dice_cbor as dice;
+use error::{map_or_log_err, Error};
+use keystore2_selinux as selinux;
+use libc::uid_t;
+use permission::Permission;
+use std::sync::Arc;
+
+/// A DiceNode backend implementation.
+/// All functions except demote_self derive effective dice artifacts staring from
+/// this node and iterating through `{ [client | demotion path], input_values }`
+/// in ascending order.
+pub trait DiceNodeImpl {
+ /// Signs the message using the effective dice artifacts and Ed25519Pure.
+ fn sign(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ message: &[u8],
+ ) -> Result<Signature>;
+ /// Returns the effective attestation chain.
+ fn get_attestation_chain(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<Bcc>;
+ /// Returns the effective dice artifacts.
+ fn derive(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<BccHandover>;
+ /// Adds [ `client` | `input_values` ] to the demotion path of the given client.
+ /// This changes the effective dice artifacts for all subsequent API calls of the
+ /// given client.
+ fn demote(&self, client: BinderInputValues, input_values: &[BinderInputValues]) -> Result<()>;
+ /// This demotes the implementation itself. I.e. a resident node would replace its resident
+ /// with the effective artifacts derived using `input_values`. A proxy node would
+ /// simply call `demote` on its parent node. This is not reversible and changes
+ /// the effective dice artifacts of all clients.
+ fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()>;
+}
+
+/// Wraps a DiceNodeImpl and implements the actual IDiceNode AIDL API.
+pub struct DiceNode {
+ node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
+}
+
+/// This function uses its namesake in the permission module and in
+/// combination with with_calling_sid from the binder crate to check
+/// if the caller has the given keystore permission.
+pub fn check_caller_permission<T: selinux::ClassPermission>(perm: T) -> Result<()> {
+ ThreadState::with_calling_sid(|calling_sid| {
+ let target_context =
+ selinux::getcon().context("In check_caller_permission: getcon failed.")?;
+
+ selinux::check_permission(
+ calling_sid.ok_or(Error::Rc(ResponseCode::SYSTEM_ERROR)).context(
+ "In check_keystore_permission: Cannot check permission without calling_sid.",
+ )?,
+ &target_context,
+ perm,
+ )
+ })
+}
+
+fn client_input_values(uid: uid_t) -> Result<BinderInputValues> {
+ Ok(BinderInputValues {
+ codeHash: vec![0; dice::HASH_SIZE],
+ config: BinderConfig {
+ desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
+ .context("In client_input_values: failed to format config descriptor")?,
+ },
+ authorityHash: vec![0; dice::HASH_SIZE],
+ authorityDescriptor: None,
+ hidden: vec![0; dice::HIDDEN_SIZE],
+ mode: Mode::NORMAL,
+ })
+}
+
+impl DiceNode {
+ /// Constructs an instance of DiceNode, wraps it with a BnDiceNode object and
+ /// returns a strong pointer to the binder. The result can be used to register
+ /// the service with service manager.
+ pub fn new_as_binder(
+ node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
+ ) -> Result<Strong<dyn IDiceNode>> {
+ let result = BnDiceNode::new_binder(
+ DiceNode { node_impl },
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ );
+ Ok(result)
+ }
+
+ fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature> {
+ check_caller_permission(Permission::UseSign).context("In DiceNode::sign:")?;
+ let client =
+ client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::sign:")?;
+ self.node_impl.sign(client, input_values, message)
+ }
+ fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc> {
+ check_caller_permission(Permission::GetAttestationChain)
+ .context("In DiceNode::get_attestation_chain:")?;
+ let client = client_input_values(ThreadState::get_calling_uid())
+ .context("In DiceNode::get_attestation_chain:")?;
+ self.node_impl.get_attestation_chain(client, input_values)
+ }
+ fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover> {
+ check_caller_permission(Permission::Derive).context("In DiceNode::derive:")?;
+ let client =
+ client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::extend:")?;
+ self.node_impl.derive(client, input_values)
+ }
+ fn demote(&self, input_values: &[BinderInputValues]) -> Result<()> {
+ check_caller_permission(Permission::Demote).context("In DiceNode::demote:")?;
+ let client =
+ client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::demote:")?;
+ self.node_impl.demote(client, input_values)
+ }
+}
+
+impl binder::Interface for DiceNode {}
+
+impl IDiceNode for DiceNode {
+ fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> BinderResult<Signature> {
+ map_or_log_err(self.sign(input_values, message), Ok)
+ }
+ fn getAttestationChain(&self, input_values: &[BinderInputValues]) -> BinderResult<Bcc> {
+ map_or_log_err(self.get_attestation_chain(input_values), Ok)
+ }
+ fn derive(&self, input_values: &[BinderInputValues]) -> BinderResult<BccHandover> {
+ map_or_log_err(self.derive(input_values), Ok)
+ }
+ fn demote(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
+ map_or_log_err(self.demote(input_values), Ok)
+ }
+}
+
+/// Wraps a DiceNodeImpl and implements the IDiceMaintenance AIDL API.
+pub struct DiceMaintenance {
+ node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
+}
+
+impl DiceMaintenance {
+ /// Constructs an instance of DiceMaintenance, wraps it with a BnDiceMaintenance object and
+ /// returns a strong pointer to the binder. The result can be used to register the service
+ /// with service manager.
+ pub fn new_as_binder(
+ node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
+ ) -> Result<Strong<dyn IDiceMaintenance>> {
+ let result = BnDiceMaintenance::new_binder(
+ DiceMaintenance { node_impl },
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ );
+ Ok(result)
+ }
+
+ fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
+ check_caller_permission(Permission::DemoteSelf)
+ .context("In DiceMaintenance::demote_self:")?;
+ self.node_impl.demote_self(input_values)
+ }
+}
+
+impl binder::Interface for DiceMaintenance {}
+
+impl IDiceMaintenance for DiceMaintenance {
+ fn demoteSelf(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
+ map_or_log_err(self.demote_self(input_values), Ok)
+ }
+}
diff --git a/diced/src/lib_vendor.rs b/diced/src/lib_vendor.rs
new file mode 100644
index 0000000..01c804b
--- /dev/null
+++ b/diced/src/lib_vendor.rs
@@ -0,0 +1,20 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! This crate implements the android.hardware.security.dice.IDiceDevice interface
+//! and provides support for implementing a DICE HAL service.
+
+mod error_vendor;
+pub mod hal_node;
+pub use diced_open_dice_cbor as dice;
diff --git a/diced/src/permission.rs b/diced/src/permission.rs
new file mode 100644
index 0000000..116df1b
--- /dev/null
+++ b/diced/src/permission.rs
@@ -0,0 +1,46 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! This crate provides convenience wrappers for the SELinux permission
+//! defined in the diced SELinux access class.
+
+use keystore2_selinux as selinux;
+use selinux::{implement_class, ClassPermission};
+
+implement_class!(
+ /// Permission provides a convenient abstraction from the SELinux class `diced`.
+ #[selinux(class_name = diced)]
+ #[derive(Clone, Copy, Debug, PartialEq)]
+ pub enum Permission {
+ /// Checked when a client attempts to call seal or unseal.
+ #[selinux(name = use_seal)]
+ UseSeal,
+ /// Checked when a client attempts to call IDiceNode::sign.
+ #[selinux(name = use_sign)]
+ UseSign,
+ /// Checked when a client attempts to call IDiceNode::getAttestationChain.
+ #[selinux(name = get_attestation_chain)]
+ GetAttestationChain,
+ /// Checked when a client attempts to call IDiceNode::derive.
+ #[selinux(name = derive)]
+ Derive,
+ /// Checked when a client wants to demote itself by calling IDiceNode::demote.
+ #[selinux(name = demote)]
+ Demote,
+ /// Checked when a client calls IDiceMaintenance::demote in an attempt to
+ /// demote this dice node.
+ #[selinux(name = demote_self)]
+ DemoteSelf,
+ }
+);
diff --git a/diced/src/proxy_node_hal.rs b/diced/src/proxy_node_hal.rs
new file mode 100644
index 0000000..3f31419
--- /dev/null
+++ b/diced/src/proxy_node_hal.rs
@@ -0,0 +1,119 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! A proxy dice node delegates all accesses to CDI_attest and CDI_seal to a parent
+//! node, here an implementation of android.hardware.security.dice.IDiceDevice.
+
+#![allow(dead_code)]
+
+use crate::DiceNodeImpl;
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Bcc::Bcc, BccHandover::BccHandover, IDiceDevice::IDiceDevice,
+ InputValues::InputValues as BinderInputValues, Signature::Signature,
+};
+use anyhow::{Context, Result};
+use binder::public_api::Strong;
+use std::collections::HashMap;
+use std::sync::RwLock;
+
+/// The ProxyNodeHal implements a IDiceNode backend delegating crypto operations
+/// to the corresponding HAL.
+pub struct ProxyNodeHal {
+ parent: Strong<dyn IDiceDevice>,
+ demotion_db: RwLock<HashMap<BinderInputValues, Vec<BinderInputValues>>>,
+}
+
+impl ProxyNodeHal {
+ /// Creates a new proxy node with a reference to the parent service.
+ pub fn new(parent: Strong<dyn IDiceDevice>) -> Result<Self> {
+ Ok(ProxyNodeHal { parent, demotion_db: Default::default() })
+ }
+
+ fn get_effective_input_values(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Vec<BinderInputValues> {
+ let demotion_db = self.demotion_db.read().unwrap();
+
+ let client_arr = [client];
+
+ demotion_db
+ .get(&client_arr[0])
+ .map(|v| v.iter())
+ .unwrap_or_else(|| client_arr.iter())
+ .chain(input_values.iter())
+ .cloned()
+ .collect()
+ }
+}
+
+impl DiceNodeImpl for ProxyNodeHal {
+ fn sign(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ message: &[u8],
+ ) -> Result<Signature> {
+ self.parent
+ .sign(&self.get_effective_input_values(client, input_values), message)
+ .context("In ProxyNodeHal::sign:")
+ }
+
+ fn get_attestation_chain(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<Bcc> {
+ self.parent
+ .getAttestationChain(&self.get_effective_input_values(client, input_values))
+ .context("In ProxyNodeHal::get_attestation_chain:")
+ }
+
+ fn derive(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<BccHandover> {
+ self.parent
+ .derive(&self.get_effective_input_values(client, input_values))
+ .context("In ProxyNodeHal::derive:")
+ }
+
+ fn demote(&self, client: BinderInputValues, input_values: &[BinderInputValues]) -> Result<()> {
+ let mut demotion_db = self.demotion_db.write().unwrap();
+
+ let client_arr = [client];
+
+ // The following statement consults demotion database which yields an optional demotion
+ // path. It then constructs an iterator over the following elements, then clones and
+ // collects them into a new vector:
+ // [ demotion path | client ], input_values
+ let new_path: Vec<BinderInputValues> = demotion_db
+ .get(&client_arr[0])
+ .map(|v| v.iter())
+ .unwrap_or_else(|| client_arr.iter())
+ .chain(input_values)
+ .cloned()
+ .collect();
+
+ let [client] = client_arr;
+ demotion_db.insert(client, new_path);
+ Ok(())
+ }
+
+ fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
+ self.parent.demote(input_values).context("In ProxyNodeHal::demote_self:")
+ }
+}
diff --git a/diced/src/resident_node.rs b/diced/src/resident_node.rs
new file mode 100644
index 0000000..5fe4dc9
--- /dev/null
+++ b/diced/src/resident_node.rs
@@ -0,0 +1,191 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! A resident dice node keeps CDI_attest and CDI_seal memory resident and can serve
+//! its clients directly by performing all crypto operations including derivations and
+//! certificate generation itself.
+
+use crate::DiceNodeImpl;
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Bcc::Bcc, BccHandover::BccHandover, InputValues::InputValues as BinderInputValues,
+ Signature::Signature,
+};
+use anyhow::{Context, Result};
+use dice::{ContextImpl, OpenDiceCborContext};
+use diced_open_dice_cbor as dice;
+use diced_utils::{self as utils, InputValues, ResidentArtifacts};
+use std::collections::HashMap;
+use std::convert::TryInto;
+use std::sync::RwLock;
+
+/// The ResidentNode implements a IDiceNode backend with memory resident DICE secrets.
+pub struct ResidentNode {
+ artifacts: RwLock<ResidentArtifacts>,
+ demotion_db: RwLock<HashMap<BinderInputValues, Vec<BinderInputValues>>>,
+}
+
+impl ResidentNode {
+ /// Creates a new Resident node with the given dice secrets and certificate chain.
+ pub fn new(
+ cdi_attest: &[u8; dice::CDI_SIZE],
+ cdi_seal: &[u8; dice::CDI_SIZE],
+ bcc: Vec<u8>,
+ ) -> Result<Self> {
+ Ok(ResidentNode {
+ artifacts: RwLock::new(
+ ResidentArtifacts::new(cdi_attest, cdi_seal, &bcc)
+ .context("In ResidentNode::new: Trying to initialize ResidentArtifacts")?,
+ ),
+ demotion_db: Default::default(),
+ })
+ }
+
+ fn get_effective_artifacts(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<ResidentArtifacts> {
+ let artifacts = self.artifacts.read().unwrap().try_clone()?;
+ let demotion_db = self.demotion_db.read().unwrap();
+
+ let client_arr = [client];
+
+ let input_values: Vec<utils::InputValues> = demotion_db
+ .get(&client_arr[0])
+ .map(|v| v.iter())
+ .unwrap_or_else(|| client_arr.iter())
+ .chain(input_values.iter())
+ .map(|v| v.try_into())
+ .collect::<Result<_>>()?;
+
+ artifacts
+ .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+ .context("In get_effective_artifacts:")
+ }
+}
+
+impl DiceNodeImpl for ResidentNode {
+ fn sign(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ message: &[u8],
+ ) -> Result<Signature> {
+ let (cdi_attest, _, _) = self
+ .get_effective_artifacts(client, input_values)
+ .context("In ResidentNode::sign: Failed to get effective_artifacts.")?
+ .into_tuple();
+ let mut dice = OpenDiceCborContext::new();
+ let seed = dice
+ .derive_cdi_private_key_seed(cdi_attest[..].try_into().with_context(|| {
+ format!(
+ "In ResidentNode::sign: Failed to convert cdi_attest (length: {}).",
+ cdi_attest.len()
+ )
+ })?)
+ .context("In ResidentNode::sign: Failed to derive seed from cdi_attest.")?;
+ let (_public_key, private_key) = dice
+ .keypair_from_seed(seed[..].try_into().with_context(|| {
+ format!("In ResidentNode::sign: Failed to convert seed (length: {}).", seed.len())
+ })?)
+ .context("In ResidentNode::sign: Failed to derive keypair from seed.")?;
+ Ok(Signature {
+ data: dice
+ .sign(
+ message,
+ private_key[..].try_into().with_context(|| {
+ format!(
+ "In ResidentNode::sign: Failed to convert private_key (length: {}).",
+ private_key.len()
+ )
+ })?,
+ )
+ .context("In ResidentNode::sign: Failed to sign.")?,
+ })
+ }
+
+ fn get_attestation_chain(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<Bcc> {
+ let (_, _, bcc) = self
+ .get_effective_artifacts(client, input_values)
+ .context("In ResidentNode::get_attestation_chain: Failed to get effective_artifacts.")?
+ .into_tuple();
+
+ Ok(Bcc { data: bcc })
+ }
+
+ fn derive(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<BccHandover> {
+ let (cdi_attest, cdi_seal, bcc) =
+ self.get_effective_artifacts(client, input_values)?.into_tuple();
+
+ utils::make_bcc_handover(
+ &cdi_attest[..]
+ .try_into()
+ .context("In ResidentNode::derive: Trying to convert cdi_attest to sized array.")?,
+ &cdi_seal[..]
+ .try_into()
+ .context("In ResidentNode::derive: Trying to convert cdi_attest to sized array.")?,
+ &bcc,
+ )
+ .context("In ResidentNode::derive: Trying to format bcc handover.")
+ }
+
+ fn demote(&self, client: BinderInputValues, input_values: &[BinderInputValues]) -> Result<()> {
+ let mut demotion_db = self.demotion_db.write().unwrap();
+
+ let client_arr = [client];
+
+ // The following statement consults demotion database which yields an optional demotion
+ // path. It then constructs an iterator over the following elements, then clones and
+ // collects them into a new vector:
+ // [ demotion path | client ], input_values
+ let new_path: Vec<BinderInputValues> = demotion_db
+ .get(&client_arr[0])
+ .map(|v| v.iter())
+ .unwrap_or_else(|| client_arr.iter())
+ .chain(input_values)
+ .cloned()
+ .collect();
+
+ let [client] = client_arr;
+ demotion_db.insert(client, new_path);
+ Ok(())
+ }
+
+ fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
+ let mut artifacts = self.artifacts.write().unwrap();
+
+ let input_values = input_values
+ .iter()
+ .map(|v| {
+ v.try_into().with_context(|| format!("Failed to convert input values: {:#?}", v))
+ })
+ .collect::<Result<Vec<InputValues>>>()
+ .context("In ResidentNode::demote_self:")?;
+
+ *artifacts = artifacts
+ .try_clone()
+ .context("In ResidentNode::demote_self: Failed to clone resident artifacts")?
+ .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+ .context("In ResidentNode::demote_self:")?;
+ Ok(())
+ }
+}
diff --git a/diced/src/sample_inputs.rs b/diced/src/sample_inputs.rs
new file mode 100644
index 0000000..f76ebc9
--- /dev/null
+++ b/diced/src/sample_inputs.rs
@@ -0,0 +1,255 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! This module provides a set of sample input values for a DICE chain, a sample UDS,
+//! as well as tuple of CDIs and BCC derived thereof.
+
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Config::Config as BinderConfig, InputValues::InputValues as BinderInputValues, Mode::Mode,
+};
+use anyhow::{Context, Result};
+use dice::ContextImpl;
+use diced_open_dice_cbor as dice;
+use diced_utils::cbor;
+use diced_utils::InputValues;
+use keystore2_crypto::ZVec;
+use std::convert::{TryFrom, TryInto};
+use std::io::Write;
+
+/// Sample UDS used to perform the root dice flow by `make_sample_bcc_and_cdis`.
+pub static UDS: &[u8; dice::CDI_SIZE] = &[
+ 0x65, 0x4f, 0xab, 0xa9, 0xa5, 0xad, 0x0f, 0x5e, 0x15, 0xc3, 0x12, 0xf7, 0x77, 0x45, 0xfa, 0x55,
+ 0x18, 0x6a, 0xa6, 0x34, 0xb6, 0x7c, 0x82, 0x7b, 0x89, 0x4c, 0xc5, 0x52, 0xd3, 0x27, 0x35, 0x8e,
+];
+
+fn encode_pub_key_ed25519(pub_key: &[u8], stream: &mut dyn Write) -> Result<()> {
+ cbor::encode_header(5 /* CBOR MAP */, 5, stream)
+ .context("In encode_pub_key_ed25519: Trying to encode map header.")?;
+ cbor::encode_number(1, stream)
+ .context("In encode_pub_key_ed25519: Trying to encode Key type tag.")?;
+ cbor::encode_number(1, stream)
+ .context("In encode_pub_key_ed25519: Trying to encode Key type.")?;
+ cbor::encode_number(3, stream)
+ .context("In encode_pub_key_ed25519: Trying to encode algorithm tag.")?;
+ // Encoding a -8 for AlgorithmEdDSA. The encoded number is -1 - <header argument>,
+ // the an argument of 7 below.
+ cbor::encode_header(1 /* CBOR NEGATIVE INT */, 7 /* -1 -7 = -8*/, stream)
+ .context("In encode_pub_key_ed25519: Trying to encode algorithm.")?;
+ cbor::encode_number(4, stream)
+ .context("In encode_pub_key_ed25519: Trying to encode ops tag.")?;
+ // Ops 2 for verify.
+ cbor::encode_number(2, stream).context("In encode_pub_key_ed25519: Trying to encode ops.")?;
+ cbor::encode_header(1 /* CBOR NEGATIVE INT */, 0 /* -1 -0 = -1*/, stream)
+ .context("In encode_pub_key_ed25519: Trying to encode curve tag.")?;
+ // Curve 6 for Ed25519
+ cbor::encode_number(6, stream).context("In encode_pub_key_ed25519: Trying to encode curve.")?;
+ cbor::encode_header(1 /* CBOR NEGATIVE INT */, 1 /* -1 -1 = -2*/, stream)
+ .context("In encode_pub_key_ed25519: Trying to encode X coordinate tag.")?;
+ cbor::encode_bstr(pub_key, stream)
+ .context("In encode_pub_key_ed25519: Trying to encode X coordinate.")?;
+ Ok(())
+}
+
+/// Derives a tuple of (CDI_ATTEST, CDI_SEAL, BCC) derived of the vector of input values returned
+/// by `get_input_values_vector`.
+pub fn make_sample_bcc_and_cdis() -> Result<(ZVec, ZVec, Vec<u8>)> {
+ let mut dice_ctx = dice::OpenDiceCborContext::new();
+ let private_key_seed = dice_ctx
+ .derive_cdi_private_key_seed(UDS)
+ .context("In make_sample_bcc_and_cdis: Trying to derive private key seed.")?;
+
+ let (public_key, _) =
+ dice_ctx
+ .keypair_from_seed(&private_key_seed[..].try_into().context(
+ "In make_sample_bcc_and_cids: Failed to convert seed to array reference.",
+ )?)
+ .context("In make_sample_bcc_and_cids: Failed to generate key pair.")?;
+
+ let input_values_vector = get_input_values_vector();
+
+ let (cdi_attest, cdi_seal, mut cert) = dice_ctx
+ .main_flow(
+ UDS,
+ UDS,
+ &InputValues::try_from(&input_values_vector[0])
+ .context("In make_sample_bcc_and_cdis: Trying to convert input values. (0)")?,
+ )
+ .context("In make_sample_bcc_and_cdis: Trying to run first main flow.")?;
+
+ let mut bcc: Vec<u8> = vec![];
+
+ cbor::encode_header(4 /* CBOR ARRAY */, 2, &mut bcc)
+ .context("In make_sample_bcc_and_cdis: Trying to encode array header.")?;
+ encode_pub_key_ed25519(&public_key, &mut bcc)
+ .context("In make_sample_bcc_and_cdis: Trying encode pub_key.")?;
+
+ bcc.append(&mut cert);
+
+ let (cdi_attest, cdi_seal, bcc) = dice_ctx
+ .bcc_main_flow(
+ &cdi_attest[..].try_into().context(
+ "In make_sample_bcc_and_cdis: Failed to convert cdi_attest to array reference. (1)",
+ )?,
+ &cdi_seal[..].try_into().context(
+ "In make_sample_bcc_and_cdis: Failed to convert cdi_seal to array reference. (1)",
+ )?,
+ &bcc,
+ &InputValues::try_from(&input_values_vector[1])
+ .context("In make_sample_bcc_and_cdis: Trying to convert input values. (1)")?,
+ )
+ .context("In make_sample_bcc_and_cdis: Trying to run first bcc main flow.")?;
+ dice_ctx
+ .bcc_main_flow(
+ &cdi_attest[..].try_into().context(
+ "In make_sample_bcc_and_cdis: Failed to convert cdi_attest to array reference. (2)",
+ )?,
+ &cdi_seal[..].try_into().context(
+ "In make_sample_bcc_and_cdis: Failed to convert cdi_seal to array reference. (2)",
+ )?,
+ &bcc,
+ &InputValues::try_from(&input_values_vector[2])
+ .context("In make_sample_bcc_and_cdis: Trying to convert input values. (2)")?,
+ )
+ .context("In make_sample_bcc_and_cdis: Trying to run second bcc main flow.")
+}
+
+fn make_input_values(
+ code_hash: &[u8; dice::HASH_SIZE],
+ authority_hash: &[u8; dice::HASH_SIZE],
+ config_name: &str,
+ config_version: u64,
+ config_resettable: bool,
+ mode: Mode,
+ hidden: &[u8; dice::HIDDEN_SIZE],
+) -> Result<BinderInputValues> {
+ Ok(BinderInputValues {
+ codeHash: code_hash.to_vec(),
+ config: BinderConfig {
+ desc: dice::bcc::format_config_descriptor(
+ Some(config_name),
+ Some(config_version),
+ config_resettable,
+ )
+ .context("In make_input_values: Failed to format config descriptor.")?,
+ },
+ authorityHash: authority_hash.to_vec(),
+ authorityDescriptor: None,
+ hidden: hidden.to_vec(),
+ mode,
+ })
+}
+
+/// Returns a set of sample input for a dice chain comprising the android boot loader ABL,
+/// the verified boot information AVB, and Android S.
+pub fn get_input_values_vector() -> Vec<BinderInputValues> {
+ vec![
+ make_input_values(
+ &[
+ // code hash
+ 0x16, 0x48, 0xf2, 0x55, 0x53, 0x23, 0xdd, 0x15, 0x2e, 0x83, 0x38, 0xc3, 0x64, 0x38,
+ 0x63, 0x26, 0x0f, 0xcf, 0x5b, 0xd1, 0x3a, 0xd3, 0x40, 0x3e, 0x23, 0xf8, 0x34, 0x4c,
+ 0x6d, 0xa2, 0xbe, 0x25, 0x1c, 0xb0, 0x29, 0xe8, 0xc3, 0xfb, 0xb8, 0x80, 0xdc, 0xb1,
+ 0xd2, 0xb3, 0x91, 0x4d, 0xd3, 0xfb, 0x01, 0x0f, 0xe4, 0xe9, 0x46, 0xa2, 0xc0, 0x26,
+ 0x57, 0x5a, 0xba, 0x30, 0xf7, 0x15, 0x98, 0x14,
+ ],
+ &[
+ // authority hash
+ 0xf9, 0x00, 0x9d, 0xc2, 0x59, 0x09, 0xe0, 0xb6, 0x98, 0xbd, 0xe3, 0x97, 0x4a, 0xcb,
+ 0x3c, 0xe7, 0x6b, 0x24, 0xc3, 0xe4, 0x98, 0xdd, 0xa9, 0x6a, 0x41, 0x59, 0x15, 0xb1,
+ 0x23, 0xe6, 0xc8, 0xdf, 0xfb, 0x52, 0xb4, 0x52, 0xc1, 0xb9, 0x61, 0xdd, 0xbc, 0x5b,
+ 0x37, 0x0e, 0x12, 0x12, 0xb2, 0xfd, 0xc1, 0x09, 0xb0, 0xcf, 0x33, 0x81, 0x4c, 0xc6,
+ 0x29, 0x1b, 0x99, 0xea, 0xae, 0xfd, 0xaa, 0x0d,
+ ],
+ "ABL", // config name
+ 1, // config version
+ true, // resettable
+ Mode::NORMAL,
+ &[
+ // hidden
+ 0xa2, 0x01, 0xd0, 0xc0, 0xaa, 0x75, 0x3c, 0x06, 0x43, 0x98, 0x6c, 0xc3, 0x5a, 0xb5,
+ 0x5f, 0x1f, 0x0f, 0x92, 0x44, 0x3b, 0x0e, 0xd4, 0x29, 0x75, 0xe3, 0xdb, 0x36, 0xda,
+ 0xc8, 0x07, 0x97, 0x4d, 0xff, 0xbc, 0x6a, 0xa4, 0x8a, 0xef, 0xc4, 0x7f, 0xf8, 0x61,
+ 0x7d, 0x51, 0x4d, 0x2f, 0xdf, 0x7e, 0x8c, 0x3d, 0xa3, 0xfc, 0x63, 0xd4, 0xd4, 0x74,
+ 0x8a, 0xc4, 0x14, 0x45, 0x83, 0x6b, 0x12, 0x7e,
+ ],
+ )
+ .unwrap(),
+ make_input_values(
+ &[
+ // code hash
+ 0xa4, 0x0c, 0xcb, 0xc1, 0xbf, 0xfa, 0xcc, 0xfd, 0xeb, 0xf4, 0xfc, 0x43, 0x83, 0x7f,
+ 0x46, 0x8d, 0xd8, 0xd8, 0x14, 0xc1, 0x96, 0x14, 0x1f, 0x6e, 0xb3, 0xa0, 0xd9, 0x56,
+ 0xb3, 0xbf, 0x2f, 0xfa, 0x88, 0x70, 0x11, 0x07, 0x39, 0xa4, 0xd2, 0xa9, 0x6b, 0x18,
+ 0x28, 0xe8, 0x29, 0x20, 0x49, 0x0f, 0xbb, 0x8d, 0x08, 0x8c, 0xc6, 0x54, 0xe9, 0x71,
+ 0xd2, 0x7e, 0xa4, 0xfe, 0x58, 0x7f, 0xd3, 0xc7,
+ ],
+ &[
+ // authority hash
+ 0xb2, 0x69, 0x05, 0x48, 0x56, 0xb5, 0xfa, 0x55, 0x6f, 0xac, 0x56, 0xd9, 0x02, 0x35,
+ 0x2b, 0xaa, 0x4c, 0xba, 0x28, 0xdd, 0x82, 0x3a, 0x86, 0xf5, 0xd4, 0xc2, 0xf1, 0xf9,
+ 0x35, 0x7d, 0xe4, 0x43, 0x13, 0xbf, 0xfe, 0xd3, 0x36, 0xd8, 0x1c, 0x12, 0x78, 0x5c,
+ 0x9c, 0x3e, 0xf6, 0x66, 0xef, 0xab, 0x3d, 0x0f, 0x89, 0xa4, 0x6f, 0xc9, 0x72, 0xee,
+ 0x73, 0x43, 0x02, 0x8a, 0xef, 0xbc, 0x05, 0x98,
+ ],
+ "AVB", // config name
+ 1, // config version
+ true, // resettable
+ Mode::NORMAL,
+ &[
+ // hidden
+ 0x5b, 0x3f, 0xc9, 0x6b, 0xe3, 0x95, 0x59, 0x40, 0x5e, 0x64, 0xe5, 0x64, 0x3f, 0xfd,
+ 0x21, 0x09, 0x9d, 0xf3, 0xcd, 0xc7, 0xa4, 0x2a, 0xe2, 0x97, 0xdd, 0xe2, 0x4f, 0xb0,
+ 0x7d, 0x7e, 0xf5, 0x8e, 0xd6, 0x4d, 0x84, 0x25, 0x54, 0x41, 0x3f, 0x8f, 0x78, 0x64,
+ 0x1a, 0x51, 0x27, 0x9d, 0x55, 0x8a, 0xe9, 0x90, 0x35, 0xab, 0x39, 0x80, 0x4b, 0x94,
+ 0x40, 0x84, 0xa2, 0xfd, 0x73, 0xeb, 0x35, 0x7a,
+ ],
+ )
+ .unwrap(),
+ make_input_values(
+ &[
+ // code hash
+ 0; dice::HASH_SIZE
+ ],
+ &[
+ // authority hash
+ 0x04, 0x25, 0x5d, 0x60, 0x5f, 0x5c, 0x45, 0x0d, 0xf2, 0x9a, 0x6e, 0x99, 0x30, 0x03,
+ 0xb8, 0xd6, 0xe1, 0x99, 0x71, 0x1b, 0xf8, 0x44, 0xfa, 0xb5, 0x31, 0x79, 0x1c, 0x37,
+ 0x68, 0x4e, 0x1d, 0xc0, 0x24, 0x74, 0x68, 0xf8, 0x80, 0x20, 0x3e, 0x44, 0xb1, 0x43,
+ 0xd2, 0x9c, 0xfc, 0x12, 0x9e, 0x77, 0x0a, 0xde, 0x29, 0x24, 0xff, 0x2e, 0xfa, 0xc7,
+ 0x10, 0xd5, 0x73, 0xd4, 0xc6, 0xdf, 0x62, 0x9f,
+ ],
+ "Android", // config name
+ 12, // config version
+ true, // resettable
+ Mode::NORMAL,
+ &[
+ // hidden
+ 0; dice::HIDDEN_SIZE
+ ],
+ )
+ .unwrap(),
+ ]
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ // This simple test checks if the invocation succeeds, essentially it tests
+ // if the initial bcc is accepted by `DiceContext::bcc_main_flow`.
+ #[test]
+ fn make_sample_bcc_and_cdis_test() {
+ make_sample_bcc_and_cdis().unwrap();
+ }
+}
diff --git a/diced/src/utils.rs b/diced/src/utils.rs
new file mode 100644
index 0000000..3d3db55
--- /dev/null
+++ b/diced/src/utils.rs
@@ -0,0 +1,497 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Implements utility functions and types for diced and the dice HAL.
+
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Bcc::Bcc, BccHandover::BccHandover, InputValues::InputValues as BinderInputValues,
+ Mode::Mode as BinderMode,
+};
+use anyhow::{anyhow, Context, Result};
+use dice::ContextImpl;
+use diced_open_dice_cbor as dice;
+use keystore2_crypto::ZVec;
+use std::convert::{TryFrom, TryInto};
+
+/// This new type wraps a reference to BinderInputValues and implements the open dice
+/// InputValues trait.
+#[derive(Debug)]
+pub struct InputValues<'a>(&'a BinderInputValues);
+
+impl<'a> TryFrom<&'a BinderInputValues> for InputValues<'a> {
+ type Error = anyhow::Error;
+
+ fn try_from(input_values: &'a BinderInputValues) -> Result<InputValues<'a>> {
+ if input_values.codeHash.len() != dice::HASH_SIZE {
+ return Err(anyhow!(format!(
+ "In try_from: Code hash has invalid size: {}",
+ input_values.codeHash.len()
+ )));
+ }
+ if input_values.authorityHash.len() != dice::HASH_SIZE {
+ return Err(anyhow!(format!(
+ "In try_from: Authority hash has invalid size: {}",
+ input_values.authorityHash.len()
+ )));
+ }
+ if input_values.hidden.len() != dice::HIDDEN_SIZE {
+ return Err(anyhow!(format!(
+ "In try_from: Hidden has invalid size: {}",
+ input_values.hidden.len()
+ )));
+ }
+
+ Ok(Self(input_values))
+ }
+}
+
+impl From<&InputValues<'_>> for BinderInputValues {
+ fn from(input_values: &InputValues) -> BinderInputValues {
+ input_values.0.clone()
+ }
+}
+impl From<InputValues<'_>> for BinderInputValues {
+ fn from(input_values: InputValues) -> BinderInputValues {
+ input_values.0.clone()
+ }
+}
+
+impl dice::InputValues for InputValues<'_> {
+ fn code_hash(&self) -> &[u8; dice::HASH_SIZE] {
+ // If `self` was created using try_from the length was checked and this cannot panic.
+ self.0.codeHash.as_slice().try_into().unwrap()
+ }
+
+ fn config(&self) -> dice::Config {
+ dice::Config::Descriptor(self.0.config.desc.as_slice())
+ }
+
+ fn authority_hash(&self) -> &[u8; dice::HASH_SIZE] {
+ // If `self` was created using try_from the length was checked and this cannot panic.
+ self.0.authorityHash.as_slice().try_into().unwrap()
+ }
+
+ fn authority_descriptor(&self) -> Option<&[u8]> {
+ self.0.authorityDescriptor.as_deref()
+ }
+
+ fn mode(&self) -> dice::Mode {
+ match self.0.mode {
+ BinderMode::NOT_INITIALIZED => dice::Mode::NotConfigured,
+ BinderMode::NORMAL => dice::Mode::Normal,
+ BinderMode::DEBUG => dice::Mode::Debug,
+ BinderMode::RECOVERY => dice::Mode::Recovery,
+ _ => dice::Mode::NotConfigured,
+ }
+ }
+
+ fn hidden(&self) -> &[u8; dice::HIDDEN_SIZE] {
+ // If `self` was created using try_from the length was checked and this cannot panic.
+ self.0.hidden.as_slice().try_into().unwrap()
+ }
+}
+
+/// Initializes an aidl defined BccHandover object with the arguments `cdi_attest`, `cdi_seal`,
+/// and `bcc`.
+pub fn make_bcc_handover(
+ cdi_attest: &[u8; dice::CDI_SIZE],
+ cdi_seal: &[u8; dice::CDI_SIZE],
+ bcc: &[u8],
+) -> Result<BccHandover> {
+ Ok(BccHandover {
+ cdiAttest: cdi_attest.to_vec(),
+ cdiSeal: cdi_seal.to_vec(),
+ bcc: Bcc { data: bcc.to_vec() },
+ })
+}
+
+/// ResidentArtifacts stores a set of dice artifacts comprising CDI_ATTEST, CDI_SEAL,
+/// and the BCC formatted attestation certificate chain. The sensitive secrets are
+/// stored in zeroing vectors, and it implements functionality to perform DICE
+/// derivation steps using libopen-dice-cbor.
+pub struct ResidentArtifacts {
+ cdi_attest: ZVec,
+ cdi_seal: ZVec,
+ bcc: Vec<u8>,
+}
+
+impl ResidentArtifacts {
+ /// Create a ResidentArtifacts object. The parameters ensure that the stored secrets
+ /// can only have the appropriate size, so that subsequent casts to array references
+ /// cannot fail.
+ pub fn new(
+ cdi_attest: &[u8; dice::CDI_SIZE],
+ cdi_seal: &[u8; dice::CDI_SIZE],
+ bcc: &[u8],
+ ) -> Result<Self> {
+ Ok(ResidentArtifacts {
+ cdi_attest: cdi_attest[..]
+ .try_into()
+ .context("In ResidentArtifacts::new: Trying to convert cdi_attest to ZVec.")?,
+ cdi_seal: cdi_seal[..]
+ .try_into()
+ .context("In ResidentArtifacts::new: Trying to convert cdi_seal to ZVec.")?,
+ bcc: bcc.to_vec(),
+ })
+ }
+
+ /// Creates a ResidentArtifacts object from another one implementing the DiceArtifacts
+ /// trait. Like `new` this function can only create artifacts of appropriate size
+ /// because DiceArtifacts returns array references of appropriate size.
+ pub fn new_from<T: DiceArtifacts + ?Sized>(artifacts: &T) -> Result<Self> {
+ Ok(ResidentArtifacts {
+ cdi_attest: artifacts.cdi_attest()[..].try_into()?,
+ cdi_seal: artifacts.cdi_seal()[..].try_into()?,
+ bcc: artifacts.bcc(),
+ })
+ }
+
+ /// Attempts to clone the artifacts. This operation is fallible due to the fallible
+ /// nature of ZVec.
+ pub fn try_clone(&self) -> Result<Self> {
+ Ok(ResidentArtifacts {
+ cdi_attest: self
+ .cdi_attest
+ .try_clone()
+ .context("In ResidentArtifacts::new: Trying to clone cdi_attest.")?,
+ cdi_seal: self
+ .cdi_seal
+ .try_clone()
+ .context("In ResidentArtifacts::new: Trying to clone cdi_seal.")?,
+ bcc: self.bcc.clone(),
+ })
+ }
+
+ /// Deconstruct the Artifacts into a tuple.
+ /// (CDI_ATTEST, CDI_SEAL, BCC)
+ pub fn into_tuple(self) -> (ZVec, ZVec, Vec<u8>) {
+ let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
+ (cdi_attest, cdi_seal, bcc)
+ }
+
+ fn execute_step(self, input_values: &dyn dice::InputValues) -> Result<Self> {
+ let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
+
+ let (cdi_attest, cdi_seal, bcc) = dice::OpenDiceCborContext::new()
+ .bcc_main_flow(
+ cdi_attest[..].try_into().with_context(|| {
+ format!("Trying to convert cdi_attest. (length: {})", cdi_attest.len())
+ })?,
+ cdi_seal[..].try_into().with_context(|| {
+ format!("Trying to convert cdi_seal. (length: {})", cdi_seal.len())
+ })?,
+ &bcc,
+ input_values,
+ )
+ .context("In ResidentArtifacts::execute_step:")?;
+ Ok(ResidentArtifacts { cdi_attest, cdi_seal, bcc })
+ }
+
+ /// Iterate through the iterator of dice input values performing one
+ /// BCC main flow step on each element.
+ pub fn execute_steps<'a, Iter>(self, input_values: Iter) -> Result<Self>
+ where
+ Iter: IntoIterator<Item = &'a dyn dice::InputValues>,
+ {
+ input_values
+ .into_iter()
+ .try_fold(self, |acc, input_values| acc.execute_step(input_values))
+ .context("In ResidentArtifacts::execute_step:")
+ }
+}
+
+/// An object that implements this trait provides the typical DICE artifacts.
+/// CDI_ATTEST, CDI_SEAL, and a certificate chain up to the public key that
+/// can be derived from CDI_ATTEST. Implementations should check the length of
+/// the stored CDI_* secrets on creation so that any valid instance returns the
+/// correct secrets in an infallible way.
+pub trait DiceArtifacts {
+ /// Returns CDI_ATTEST.
+ fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE];
+ /// Returns CDI_SEAL.
+ fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE];
+ /// Returns the attestation certificate chain in BCC format.
+ fn bcc(&self) -> Vec<u8>;
+}
+
+/// Implement this trait to provide read and write access to a secure artifact
+/// storage that can be used by the ResidentHal implementation.
+pub trait UpdatableDiceArtifacts {
+ /// With artifacts provides access to the stored artifacts for the duration
+ /// of the function call by means of calling the callback.
+ fn with_artifacts<F, T>(&self, f: F) -> Result<T>
+ where
+ F: FnOnce(&dyn DiceArtifacts) -> Result<T>;
+
+ /// Consumes the object and returns a an updated version of itself.
+ fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self>
+ where
+ Self: Sized;
+}
+
+impl DiceArtifacts for ResidentArtifacts {
+ fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
+ self.cdi_attest[..].try_into().unwrap()
+ }
+ fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
+ self.cdi_seal[..].try_into().unwrap()
+ }
+ fn bcc(&self) -> Vec<u8> {
+ self.bcc.clone()
+ }
+}
+
+/// This submodule implements a limited set of CBOR generation functionality. Essentially,
+/// a cbor header generator and some convenience functions for number and BSTR encoding.
+pub mod cbor {
+ use anyhow::{anyhow, Context, Result};
+ use std::convert::TryInto;
+ use std::io::Write;
+
+ /// CBOR encodes a positive number.
+ pub fn encode_number(n: u64, buffer: &mut dyn Write) -> Result<()> {
+ encode_header(0, n, buffer)
+ }
+
+ /// CBOR encodes a binary string.
+ pub fn encode_bstr(bstr: &[u8], buffer: &mut dyn Write) -> Result<()> {
+ encode_header(
+ 2,
+ bstr.len().try_into().context("In encode_bstr: Failed to convert usize to u64.")?,
+ buffer,
+ )
+ .context("In encode_bstr: While writing header.")?;
+ let written = buffer.write(bstr).context("In encode_bstr: While writing payload.")?;
+ if written != bstr.len() {
+ return Err(anyhow!("In encode_bstr: Buffer too small. ({}, {})", written, bstr.len()));
+ }
+ Ok(())
+ }
+
+ /// Formats a CBOR header. `t` is the type, and n is the header argument.
+ pub fn encode_header(t: u8, n: u64, buffer: &mut dyn Write) -> Result<()> {
+ match n {
+ n if n < 24 => {
+ let written = buffer
+ .write(&u8::to_be_bytes(((t as u8) << 5) | (n as u8 & 0x1F)))
+ .with_context(|| {
+ format!("In encode_header: Failed to write header ({}, {})", t, n)
+ })?;
+ if written != 1 {
+ return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+ }
+ }
+ n if n <= 0xFF => {
+ let written =
+ buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (24u8 & 0x1F))).with_context(
+ || format!("In encode_header: Failed to write header ({}, {})", t, n),
+ )?;
+ if written != 1 {
+ return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+ }
+ let written = buffer.write(&u8::to_be_bytes(n as u8)).with_context(|| {
+ format!("In encode_header: Failed to write size ({}, {})", t, n)
+ })?;
+ if written != 1 {
+ return Err(anyhow!(
+ "In encode_header while writing size: Buffer to small. ({}, {})",
+ t,
+ n
+ ));
+ }
+ }
+ n if n <= 0xFFFF => {
+ let written =
+ buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (25u8 & 0x1F))).with_context(
+ || format!("In encode_header: Failed to write header ({}, {})", t, n),
+ )?;
+ if written != 1 {
+ return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+ }
+ let written = buffer.write(&u16::to_be_bytes(n as u16)).with_context(|| {
+ format!("In encode_header: Failed to write size ({}, {})", t, n)
+ })?;
+ if written != 2 {
+ return Err(anyhow!(
+ "In encode_header while writing size: Buffer to small. ({}, {})",
+ t,
+ n
+ ));
+ }
+ }
+ n if n <= 0xFFFFFFFF => {
+ let written =
+ buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (26u8 & 0x1F))).with_context(
+ || format!("In encode_header: Failed to write header ({}, {})", t, n),
+ )?;
+ if written != 1 {
+ return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+ }
+ let written = buffer.write(&u32::to_be_bytes(n as u32)).with_context(|| {
+ format!("In encode_header: Failed to write size ({}, {})", t, n)
+ })?;
+ if written != 4 {
+ return Err(anyhow!(
+ "In encode_header while writing size: Buffer to small. ({}, {})",
+ t,
+ n
+ ));
+ }
+ }
+ n => {
+ let written =
+ buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (27u8 & 0x1F))).with_context(
+ || format!("In encode_header: Failed to write header ({}, {})", t, n),
+ )?;
+ if written != 1 {
+ return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
+ }
+ let written = buffer.write(&u64::to_be_bytes(n as u64)).with_context(|| {
+ format!("In encode_header: Failed to write size ({}, {})", t, n)
+ })?;
+ if written != 8 {
+ return Err(anyhow!(
+ "In encode_header while writing size: Buffer to small. ({}, {})",
+ t,
+ n
+ ));
+ }
+ }
+ }
+ Ok(())
+ }
+
+ #[cfg(test)]
+ mod test {
+ use super::*;
+
+ fn encode_header_helper(t: u8, n: u64) -> Vec<u8> {
+ let mut b: Vec<u8> = vec![];
+ encode_header(t, n, &mut b).unwrap();
+ b
+ }
+
+ #[test]
+ fn encode_header_test() {
+ assert_eq!(&encode_header_helper(0, 0), &[0b000_00000]);
+ assert_eq!(&encode_header_helper(0, 23), &[0b000_10111]);
+ assert_eq!(&encode_header_helper(0, 24), &[0b000_11000, 24]);
+ assert_eq!(&encode_header_helper(0, 0xff), &[0b000_11000, 0xff]);
+ assert_eq!(&encode_header_helper(0, 0x100), &[0b000_11001, 0x01, 0x00]);
+ assert_eq!(&encode_header_helper(0, 0xffff), &[0b000_11001, 0xff, 0xff]);
+ assert_eq!(&encode_header_helper(0, 0x10000), &[0b000_11010, 0x00, 0x01, 0x00, 0x00]);
+ assert_eq!(
+ &encode_header_helper(0, 0xffffffff),
+ &[0b000_11010, 0xff, 0xff, 0xff, 0xff]
+ );
+ assert_eq!(
+ &encode_header_helper(0, 0x100000000),
+ &[0b000_11011, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]
+ );
+ assert_eq!(
+ &encode_header_helper(0, 0xffffffffffffffff),
+ &[0b000_11011, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
+ );
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Config::Config as BinderConfig, InputValues::InputValues as BinderInputValues,
+ };
+ use dice::InputValues as DiceInputValues;
+ use diced_open_dice_cbor as dice;
+
+ static CODE_HASH_TEST_VECTOR: [u8; dice::HASH_SIZE] = [1u8; dice::HASH_SIZE];
+ static CONFIG_DESCRIPTOR_TEST_VECTOR: &[u8] = &[3, 2, 1];
+ static AUTHORITY_HASH_TEST_VECTOR: [u8; dice::HASH_SIZE] = [3u8; dice::HASH_SIZE];
+ static AUTHORITY_DESCRIPTOR_TEST_VECTOR: &[u8] = &[1, 2, 3];
+ static HIDDEN_TEST_VECTOR: [u8; dice::HIDDEN_SIZE] = [4u8; dice::HIDDEN_SIZE];
+
+ #[test]
+ fn try_from_input_values_binder() {
+ let input_values_good = BinderInputValues {
+ codeHash: CODE_HASH_TEST_VECTOR.to_vec(),
+ config: BinderConfig { desc: CONFIG_DESCRIPTOR_TEST_VECTOR.to_vec() },
+ authorityHash: AUTHORITY_HASH_TEST_VECTOR.to_vec(),
+ authorityDescriptor: Some(AUTHORITY_DESCRIPTOR_TEST_VECTOR.to_vec()),
+ mode: BinderMode::NORMAL,
+ hidden: HIDDEN_TEST_VECTOR.to_vec(),
+ };
+
+ let converted_input_values: InputValues =
+ (&input_values_good).try_into().expect("This should succeed.");
+ assert_eq!(*converted_input_values.code_hash(), CODE_HASH_TEST_VECTOR);
+ assert_eq!(
+ converted_input_values.config(),
+ dice::Config::Descriptor(CONFIG_DESCRIPTOR_TEST_VECTOR)
+ );
+ assert_eq!(*converted_input_values.authority_hash(), AUTHORITY_HASH_TEST_VECTOR);
+ assert_eq!(
+ converted_input_values.authority_descriptor(),
+ Some(AUTHORITY_DESCRIPTOR_TEST_VECTOR)
+ );
+ assert_eq!(converted_input_values.mode(), dice::Mode::Normal);
+ assert_eq!(*converted_input_values.hidden(), HIDDEN_TEST_VECTOR);
+
+ // One more time without authority descriptor.
+ let input_values_still_good_without_authority_descriptor =
+ BinderInputValues { authorityDescriptor: None, ..input_values_good.clone() };
+
+ let converted_input_values: InputValues =
+ (&input_values_still_good_without_authority_descriptor)
+ .try_into()
+ .expect("This should succeed.");
+ assert_eq!(*converted_input_values.code_hash(), CODE_HASH_TEST_VECTOR);
+ assert_eq!(
+ converted_input_values.config(),
+ dice::Config::Descriptor(CONFIG_DESCRIPTOR_TEST_VECTOR)
+ );
+ assert_eq!(*converted_input_values.authority_hash(), AUTHORITY_HASH_TEST_VECTOR);
+ assert_eq!(converted_input_values.authority_descriptor(), None);
+ assert_eq!(converted_input_values.mode(), dice::Mode::Normal);
+ assert_eq!(*converted_input_values.hidden(), HIDDEN_TEST_VECTOR);
+
+ // Now check the failure cases.
+ // Wrong sized codeHash.
+ let input_values_bad_code_hash = BinderInputValues {
+ codeHash: vec![1u8; dice::HASH_SIZE + 1],
+ ..input_values_good.clone()
+ };
+
+ InputValues::try_from(&input_values_bad_code_hash)
+ .expect_err("Conversion of input values with wrong sized code hash succeeded.");
+
+ // Wrong sized authority hash.
+ let input_values_bad_authority_hash = BinderInputValues {
+ authorityHash: vec![1u8; dice::HASH_SIZE + 1],
+ ..input_values_good.clone()
+ };
+
+ InputValues::try_from(&input_values_bad_authority_hash)
+ .expect_err("Conversion of input values with wrong sized authority hash succeeded.");
+
+ // Wrong sized hidden.
+ let input_values_bad_hidden = BinderInputValues {
+ authorityHash: vec![1u8; dice::HASH_SIZE + 1],
+ ..input_values_good.clone()
+ };
+
+ InputValues::try_from(&input_values_bad_hidden)
+ .expect_err("Conversion of input values with wrong sized hidden succeeded.");
+ }
+}
diff --git a/fsverity/Android.bp b/fsverity/Android.bp
index 5fb38ae..5c3d6a0 100644
--- a/fsverity/Android.bp
+++ b/fsverity/Android.bp
@@ -41,3 +41,15 @@
},
},
}
+
+rust_protobuf {
+ name: "libfsverity_digests_proto_rust",
+ crate_name: "fsverity_digests_proto",
+ source_stem: "fsverity_digests_proto",
+ protos: [
+ "fsverity_digests.proto",
+ ],
+ apex_available: [
+ "com.android.compos",
+ ],
+}
diff --git a/keystore2/src/crypto/Android.bp b/keystore2/src/crypto/Android.bp
index 4e76507..76c02c5 100644
--- a/keystore2/src/crypto/Android.bp
+++ b/keystore2/src/crypto/Android.bp
@@ -35,6 +35,7 @@
"libkeystore2_crypto",
"libcrypto",
],
+ vendor_available: true,
}
cc_library {
@@ -48,6 +49,7 @@
"libcrypto",
"liblog",
],
+ vendor_available: true,
}
rust_bindgen {
@@ -56,6 +58,7 @@
crate_name: "keystore2_crypto_bindgen",
source_stem: "bindings",
host_supported: true,
+ vendor_available: true,
shared_libs: ["libcrypto"],
bindgen_flags: [
"--size_t-is-usize",
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index d73cc8b..7099f5a 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -45,6 +45,7 @@
pub(crate) mod utils;
mod versioning;
+use crate::gc::Gc;
use crate::impl_metadata; // This is in db_utils.rs
use crate::key_parameter::{KeyParameter, Tag};
use crate::metrics_store::log_rkp_error_stats;
@@ -54,7 +55,6 @@
error::{Error as KsError, ErrorCode, ResponseCode},
super_key::SuperKeyType,
};
-use crate::{gc::Gc, super_key::USER_SUPER_KEY};
use anyhow::{anyhow, Context, Result};
use std::{convert::TryFrom, convert::TryInto, ops::Deref, time::SystemTimeError};
use utils as db_utils;
@@ -2895,7 +2895,6 @@
) OR (
key_type = ?
AND namespace = ?
- AND alias = ?
AND state = ?
);",
aid_user_offset = AID_USER_OFFSET
@@ -2915,7 +2914,6 @@
// OR super key:
KeyType::Super,
user_id,
- USER_SUPER_KEY.alias,
KeyLifeCycle::Live
])
.context("In unbind_keys_for_user. Failed to query the keys created by apps.")?;
@@ -3218,7 +3216,7 @@
};
use crate::key_perm_set;
use crate::permission::{KeyPerm, KeyPermSet};
- use crate::super_key::SuperKeyManager;
+ use crate::super_key::{SuperKeyManager, USER_SUPER_KEY, SuperEncryptionAlgorithm, SuperKeyType};
use keystore2_test_utils::TempDir;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
HardwareAuthToken::HardwareAuthToken,
@@ -5456,6 +5454,80 @@
}
#[test]
+ fn test_unbind_keys_for_user_removes_superkeys() -> Result<()> {
+ let mut db = new_test_db()?;
+ let super_key = keystore2_crypto::generate_aes256_key()?;
+ let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
+ let (encrypted_super_key, metadata) =
+ SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
+
+ let key_name_enc = SuperKeyType {
+ alias: "test_super_key_1",
+ algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+ };
+
+ let key_name_nonenc = SuperKeyType {
+ alias: "test_super_key_2",
+ algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
+ };
+
+ // Install two super keys.
+ db.store_super_key(
+ 1,
+ &key_name_nonenc,
+ &super_key,
+ &BlobMetaData::new(),
+ &KeyMetaData::new(),
+ )?;
+ db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
+
+ // Check that both can be found in the database.
+ assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
+ assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
+
+ // Install the same keys for a different user.
+ db.store_super_key(
+ 2,
+ &key_name_nonenc,
+ &super_key,
+ &BlobMetaData::new(),
+ &KeyMetaData::new(),
+ )?;
+ db.store_super_key(2, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
+
+ // Check that the second pair of keys can be found in the database.
+ assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
+ assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
+
+ // Delete only encrypted keys.
+ db.unbind_keys_for_user(1, true)?;
+
+ // The encrypted superkey should be gone now.
+ assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
+ assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
+
+ // Reinsert the encrypted key.
+ db.store_super_key(1, &key_name_enc, &encrypted_super_key, &metadata, &KeyMetaData::new())?;
+
+ // Check that both can be found in the database, again..
+ assert!(db.load_super_key(&key_name_enc, 1)?.is_some());
+ assert!(db.load_super_key(&key_name_nonenc, 1)?.is_some());
+
+ // Delete all even unencrypted keys.
+ db.unbind_keys_for_user(1, false)?;
+
+ // Both should be gone now.
+ assert!(db.load_super_key(&key_name_enc, 1)?.is_none());
+ assert!(db.load_super_key(&key_name_nonenc, 1)?.is_none());
+
+ // Check that the second pair of keys was untouched.
+ assert!(db.load_super_key(&key_name_enc, 2)?.is_some());
+ assert!(db.load_super_key(&key_name_nonenc, 2)?.is_some());
+
+ Ok(())
+ }
+
+ #[test]
fn test_store_super_key() -> Result<()> {
let mut db = new_test_db()?;
let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
@@ -5474,7 +5546,7 @@
&KeyMetaData::new(),
)?;
- //check if super key exists
+ // Check if super key exists.
assert!(db.key_exists(Domain::APP, 1, USER_SUPER_KEY.alias, KeyType::Super)?);
let (_, key_entry) = db.load_super_key(&USER_SUPER_KEY, 1)?.unwrap();
@@ -5488,6 +5560,7 @@
let decrypted_secret_bytes =
loaded_super_key.aes_gcm_decrypt(&encrypted_secret, &iv, &tag)?;
assert_eq!(secret_bytes, &*decrypted_secret_bytes);
+
Ok(())
}
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index a1e4c48..ca5e593 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -75,9 +75,9 @@
/// A particular user may have several superencryption keys in the database, each for a
/// different purpose, distinguished by alias. Each is associated with a static
/// constant of this type.
-pub struct SuperKeyType {
+pub struct SuperKeyType<'a> {
/// Alias used to look the key up in the `persistent.keyentry` table.
- pub alias: &'static str,
+ pub alias: &'a str,
/// Encryption algorithm
pub algorithm: SuperEncryptionAlgorithm,
}
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index 47cba00..24a46b9 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -283,9 +283,10 @@
}
Result<void> verifyAllFilesUsingCompOs(const std::string& directory_path,
- std::map<std::string, std::string> digests,
+ const std::map<std::string, std::string>& digests,
const SigningKey& signing_key) {
std::error_code ec;
+ size_t verified_count = 0;
auto it = std::filesystem::recursive_directory_iterator(directory_path, ec);
for (auto end = std::filesystem::recursive_directory_iterator(); it != end; it.increment(ec)) {
auto& path = it->path();
@@ -305,7 +306,9 @@
if (verity_digest.ok()) {
// The file is already in fs-verity. We need to make sure it was signed
// by CompOS, so we just check that it has the digest we expect.
- if (verity_digest.value() != compos_digest) {
+ if (verity_digest.value() == compos_digest) {
+ ++verified_count;
+ } else {
return Error() << "fs-verity digest does not match CompOS digest: " << path;
}
} else {
@@ -333,6 +336,7 @@
if (!enabled.ok()) {
return Error() << enabled.error();
}
+ ++verified_count;
}
} else if (it->is_directory()) {
// These are fine to ignore
@@ -346,6 +350,12 @@
return Error() << "Failed to iterate " << directory_path << ": " << ec.message();
}
+ // Make sure all the files we expected have been seen
+ if (verified_count != digests.size()) {
+ return Error() << "Verified " << verified_count << " files, but expected "
+ << digests.size();
+ }
+
return {};
}
diff --git a/ondevice-signing/include/VerityUtils.h b/ondevice-signing/include/VerityUtils.h
index 7715628..0559c35 100644
--- a/ondevice-signing/include/VerityUtils.h
+++ b/ondevice-signing/include/VerityUtils.h
@@ -34,6 +34,7 @@
android::base::Result<std::map<std::string, std::string>>
addFilesToVerityRecursive(const std::string& path, const SigningKey& key);
-android::base::Result<void> verifyAllFilesUsingCompOs(const std::string& directory_path,
- std::map<std::string, std::string> digests,
- const SigningKey& signing_key);
+android::base::Result<void>
+verifyAllFilesUsingCompOs(const std::string& directory_path,
+ const std::map<std::string, std::string>& digests,
+ const SigningKey& signing_key);
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index 0433a3e..a324857 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -39,7 +39,6 @@
using android::base::ErrnoError;
using android::base::Error;
-using android::base::GetProperty;
using android::base::Result;
using android::base::SetProperty;
@@ -149,11 +148,6 @@
return access(kCompOsVerifyPath, X_OK) == 0 && access(kKvmDevicePath, F_OK) == 0;
}
-bool isDebugBuild() {
- std::string build_type = GetProperty("ro.build.type", "");
- return build_type == "userdebug" || build_type == "eng";
-}
-
Result<void> verifyExistingRootCert(const SigningKey& key) {
if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
@@ -531,43 +525,46 @@
return art::odrefresh::ExitCode::kCompilationRequired;
}
- // Read the CompOS signature before checking, otherwise odrefresh will delete it
- // (And there's no point checking the artifacts if we don't have a valid signature.)
+ // Make sure the artifacts we have are genuinely produced by the current
+ // instance of CompOS.
auto compos_info = getComposInfo(compos_key);
if (!compos_info.ok()) {
LOG(WARNING) << compos_info.error();
} else {
- odrefresh_status = checkArtifacts();
- if (odrefresh_status != art::odrefresh::ExitCode::kOkay) {
- LOG(WARNING) << "Pending artifacts are not OK";
- return odrefresh_status;
- }
-
- // The artifacts appear to be up to date - but we haven't
- // verified that they are genuine yet.
-
std::map<std::string, std::string> compos_digests(compos_info->file_hashes().begin(),
compos_info->file_hashes().end());
auto status = verifyAllFilesUsingCompOs(kArtArtifactsDir, compos_digests, signing_key);
if (!status.ok()) {
- LOG(WARNING) << status.error();
+ LOG(WARNING) << "Faild to verify CompOS artifacts: " << status.error();
} else {
- auto persisted = persistDigests(compos_digests, signing_key);
-
- if (!persisted.ok()) {
- LOG(WARNING) << persisted.error();
- } else {
- LOG(INFO) << "Pending artifacts successfully verified.";
+ LOG(INFO) << "CompOS artifacts successfully verified.";
+ odrefresh_status = checkArtifacts();
+ if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
+ // We have digests of all the files, and they aren't going to change, so
+ // we can just sign them & save them now, and skip checking them later.
+ auto persisted = persistDigests(compos_digests, signing_key);
+ if (!persisted.ok()) {
+ LOG(ERROR) << persisted.error();
+ // Don't try to compile again - if we can't write the digests, things
+ // are pretty bad.
+ return art::odrefresh::ExitCode::kCleanupFailed;
+ }
+ LOG(INFO) << "Persisted CompOS digests.";
*digests_verified = true;
- return art::odrefresh::ExitCode::kOkay;
}
+ return odrefresh_status;
}
}
// We can't use the existing artifacts, so we will need to generate new
// ones.
- removeDirectory(kArtArtifactsDir);
+ if (removeDirectory(kArtArtifactsDir) == 0) {
+ // We have unsigned artifacts that we can't delete, so it's not safe to continue.
+ LOG(ERROR) << "Unable to delete invalid CompOS artifacts";
+ return art::odrefresh::ExitCode::kCleanupFailed;
+ }
+
return art::odrefresh::ExitCode::kCompilationRequired;
}
} // namespace
@@ -607,7 +604,7 @@
LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
}
- bool useCompOs = kUseCompOs && supportsFsVerity && compOsPresent() && isDebugBuild();
+ bool useCompOs = kUseCompOs && supportsFsVerity && compOsPresent();
if (supportsFsVerity) {
auto existing_cert = verifyExistingRootCert(*key);