1*9860b763SAndroid Build Coastguard Worker // Copyright 2022, The Android Open Source Project
2*9860b763SAndroid Build Coastguard Worker //
3*9860b763SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9860b763SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9860b763SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9860b763SAndroid Build Coastguard Worker //
7*9860b763SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*9860b763SAndroid Build Coastguard Worker //
9*9860b763SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9860b763SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9860b763SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9860b763SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9860b763SAndroid Build Coastguard Worker // limitations under the License.
14*9860b763SAndroid Build Coastguard Worker
15*9860b763SAndroid Build Coastguard Worker use kmr_common::{crypto, keyblob};
16*9860b763SAndroid Build Coastguard Worker use kmr_wire::keymint;
17*9860b763SAndroid Build Coastguard Worker use std::collections::HashMap;
18*9860b763SAndroid Build Coastguard Worker use std::fmt::Write;
19*9860b763SAndroid Build Coastguard Worker
20*9860b763SAndroid Build Coastguard Worker /// Combined schema, with CBOR-encoded examples of specific types.
21*9860b763SAndroid Build Coastguard Worker #[derive(Default)]
22*9860b763SAndroid Build Coastguard Worker struct AccumulatedSchema {
23*9860b763SAndroid Build Coastguard Worker schema: String,
24*9860b763SAndroid Build Coastguard Worker samples: HashMap<String, Vec<u8>>,
25*9860b763SAndroid Build Coastguard Worker }
26*9860b763SAndroid Build Coastguard Worker
27*9860b763SAndroid Build Coastguard Worker impl AccumulatedSchema {
28*9860b763SAndroid Build Coastguard Worker /// Add a new type to the accumulated schema, along with a sample instance of the type.
add<T: kmr_wire::AsCborValue>(&mut self, sample: T)29*9860b763SAndroid Build Coastguard Worker fn add<T: kmr_wire::AsCborValue>(&mut self, sample: T) {
30*9860b763SAndroid Build Coastguard Worker if let (Some(name), Some(schema)) = (<T>::cddl_typename(), <T>::cddl_schema()) {
31*9860b763SAndroid Build Coastguard Worker self.add_name_schema(&name, &schema);
32*9860b763SAndroid Build Coastguard Worker self.samples.insert(name, sample.into_vec().unwrap());
33*9860b763SAndroid Build Coastguard Worker } else {
34*9860b763SAndroid Build Coastguard Worker eprintln!("No CDDL typename+schema for {}", std::any::type_name::<T>());
35*9860b763SAndroid Build Coastguard Worker }
36*9860b763SAndroid Build Coastguard Worker }
37*9860b763SAndroid Build Coastguard Worker
38*9860b763SAndroid Build Coastguard Worker /// Add the given name = schema to the accumulated schema.
add_name_schema(&mut self, name: &str, schema: &str)39*9860b763SAndroid Build Coastguard Worker fn add_name_schema(&mut self, name: &str, schema: &str) {
40*9860b763SAndroid Build Coastguard Worker let _ = writeln!(self.schema, "{} = {}", name, schema);
41*9860b763SAndroid Build Coastguard Worker }
42*9860b763SAndroid Build Coastguard Worker
43*9860b763SAndroid Build Coastguard Worker /// Check that all of the sample type instances match their CDDL schema.
44*9860b763SAndroid Build Coastguard Worker ///
45*9860b763SAndroid Build Coastguard Worker /// This method is a no-op if the `cddl-cat` feature is not enabled.
check(&self)46*9860b763SAndroid Build Coastguard Worker fn check(&self) {
47*9860b763SAndroid Build Coastguard Worker // TODO: enable this if/when cddl-cat supports tagged CBOR items (which are used in the
48*9860b763SAndroid Build Coastguard Worker // EncryptedKeyBlob encoding)
49*9860b763SAndroid Build Coastguard Worker #[cfg(feature = "cddl-cat")]
50*9860b763SAndroid Build Coastguard Worker for (name, data) in &self.samples {
51*9860b763SAndroid Build Coastguard Worker if let Err(e) = cddl_cat::validate_cbor_bytes(&name, &self.schema, &data) {
52*9860b763SAndroid Build Coastguard Worker eprintln!("Failed to validate sample data for {} against CDDL: {:?}", name, e);
53*9860b763SAndroid Build Coastguard Worker }
54*9860b763SAndroid Build Coastguard Worker }
55*9860b763SAndroid Build Coastguard Worker }
56*9860b763SAndroid Build Coastguard Worker }
57*9860b763SAndroid Build Coastguard Worker
58*9860b763SAndroid Build Coastguard Worker impl std::fmt::Display for AccumulatedSchema {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result59*9860b763SAndroid Build Coastguard Worker fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60*9860b763SAndroid Build Coastguard Worker write!(f, "{}", self.schema)
61*9860b763SAndroid Build Coastguard Worker }
62*9860b763SAndroid Build Coastguard Worker }
63*9860b763SAndroid Build Coastguard Worker
main()64*9860b763SAndroid Build Coastguard Worker fn main() {
65*9860b763SAndroid Build Coastguard Worker // CDDL for encrypted keyblobs, top-down.
66*9860b763SAndroid Build Coastguard Worker let mut schema = AccumulatedSchema::default();
67*9860b763SAndroid Build Coastguard Worker
68*9860b763SAndroid Build Coastguard Worker schema.add(keyblob::EncryptedKeyBlob::V1(keyblob::EncryptedKeyBlobV1 {
69*9860b763SAndroid Build Coastguard Worker characteristics: vec![],
70*9860b763SAndroid Build Coastguard Worker key_derivation_input: [0u8; 32],
71*9860b763SAndroid Build Coastguard Worker kek_context: vec![],
72*9860b763SAndroid Build Coastguard Worker encrypted_key_material: coset::CoseEncrypt0Builder::new()
73*9860b763SAndroid Build Coastguard Worker .protected(
74*9860b763SAndroid Build Coastguard Worker coset::HeaderBuilder::new().algorithm(coset::iana::Algorithm::A256GCM).build(),
75*9860b763SAndroid Build Coastguard Worker )
76*9860b763SAndroid Build Coastguard Worker .ciphertext(vec![1, 2, 3])
77*9860b763SAndroid Build Coastguard Worker .build(),
78*9860b763SAndroid Build Coastguard Worker secure_deletion_slot: Some(keyblob::SecureDeletionSlot(1)),
79*9860b763SAndroid Build Coastguard Worker }));
80*9860b763SAndroid Build Coastguard Worker schema.add(keyblob::Version::V1);
81*9860b763SAndroid Build Coastguard Worker schema.add(keyblob::EncryptedKeyBlobV1 {
82*9860b763SAndroid Build Coastguard Worker characteristics: vec![],
83*9860b763SAndroid Build Coastguard Worker key_derivation_input: [0u8; 32],
84*9860b763SAndroid Build Coastguard Worker kek_context: vec![],
85*9860b763SAndroid Build Coastguard Worker encrypted_key_material: coset::CoseEncrypt0Builder::new()
86*9860b763SAndroid Build Coastguard Worker .protected(
87*9860b763SAndroid Build Coastguard Worker coset::HeaderBuilder::new().algorithm(coset::iana::Algorithm::A256GCM).build(),
88*9860b763SAndroid Build Coastguard Worker )
89*9860b763SAndroid Build Coastguard Worker .ciphertext(vec![1, 2, 3])
90*9860b763SAndroid Build Coastguard Worker .build(),
91*9860b763SAndroid Build Coastguard Worker secure_deletion_slot: Some(keyblob::SecureDeletionSlot(1)),
92*9860b763SAndroid Build Coastguard Worker });
93*9860b763SAndroid Build Coastguard Worker schema.add(keymint::KeyCharacteristics {
94*9860b763SAndroid Build Coastguard Worker security_level: keymint::SecurityLevel::TrustedEnvironment,
95*9860b763SAndroid Build Coastguard Worker authorizations: vec![],
96*9860b763SAndroid Build Coastguard Worker });
97*9860b763SAndroid Build Coastguard Worker // From RFC 8152.
98*9860b763SAndroid Build Coastguard Worker schema.add_name_schema(
99*9860b763SAndroid Build Coastguard Worker "Cose_Encrypt0",
100*9860b763SAndroid Build Coastguard Worker "[ protected: bstr, unprotected: { * (int / tstr) => any }, ciphertext: bstr / nil ]",
101*9860b763SAndroid Build Coastguard Worker );
102*9860b763SAndroid Build Coastguard Worker
103*9860b763SAndroid Build Coastguard Worker schema.add(crypto::KeyMaterial::Aes(crypto::aes::Key::Aes128([0u8; 16]).into()));
104*9860b763SAndroid Build Coastguard Worker schema.add(keyblob::SecureDeletionSlot(1));
105*9860b763SAndroid Build Coastguard Worker schema.add(keyblob::SecureDeletionData {
106*9860b763SAndroid Build Coastguard Worker factory_reset_secret: [0; 32],
107*9860b763SAndroid Build Coastguard Worker secure_deletion_secret: [0; 16],
108*9860b763SAndroid Build Coastguard Worker });
109*9860b763SAndroid Build Coastguard Worker schema.add(keyblob::RootOfTrustInfo {
110*9860b763SAndroid Build Coastguard Worker verified_boot_key: vec![0; 32],
111*9860b763SAndroid Build Coastguard Worker device_boot_locked: false,
112*9860b763SAndroid Build Coastguard Worker verified_boot_state: keymint::VerifiedBootState::Unverified,
113*9860b763SAndroid Build Coastguard Worker });
114*9860b763SAndroid Build Coastguard Worker schema.add(keymint::VerifiedBootState::Unverified);
115*9860b763SAndroid Build Coastguard Worker
116*9860b763SAndroid Build Coastguard Worker schema.add(keymint::SecurityLevel::TrustedEnvironment);
117*9860b763SAndroid Build Coastguard Worker schema.add(keymint::KeyParam::CreationDatetime(keymint::DateTime {
118*9860b763SAndroid Build Coastguard Worker ms_since_epoch: 22_593_600_000,
119*9860b763SAndroid Build Coastguard Worker }));
120*9860b763SAndroid Build Coastguard Worker schema.add(keymint::Tag::NoAuthRequired);
121*9860b763SAndroid Build Coastguard Worker
122*9860b763SAndroid Build Coastguard Worker schema.add(keymint::Algorithm::Ec);
123*9860b763SAndroid Build Coastguard Worker schema.add(keymint::BlockMode::Ecb);
124*9860b763SAndroid Build Coastguard Worker schema.add(keymint::Digest::None);
125*9860b763SAndroid Build Coastguard Worker schema.add(keymint::EcCurve::Curve25519);
126*9860b763SAndroid Build Coastguard Worker schema.add(crypto::CurveType::Nist);
127*9860b763SAndroid Build Coastguard Worker schema.add(keymint::KeyOrigin::Generated);
128*9860b763SAndroid Build Coastguard Worker schema.add(keymint::KeyPurpose::Sign);
129*9860b763SAndroid Build Coastguard Worker schema.add(keymint::HardwareAuthenticatorType::Fingerprint);
130*9860b763SAndroid Build Coastguard Worker schema.add(keymint::PaddingMode::None);
131*9860b763SAndroid Build Coastguard Worker
132*9860b763SAndroid Build Coastguard Worker schema.add(keymint::DateTime { ms_since_epoch: 22_593_600_000 });
133*9860b763SAndroid Build Coastguard Worker schema.add(kmr_wire::KeySizeInBits(256));
134*9860b763SAndroid Build Coastguard Worker schema.add(kmr_wire::RsaExponent(65537));
135*9860b763SAndroid Build Coastguard Worker
136*9860b763SAndroid Build Coastguard Worker println!(
137*9860b763SAndroid Build Coastguard Worker "; encrypted_key_material is AES-GCM encrypted with:\n\
138*9860b763SAndroid Build Coastguard Worker ; - key derived as described below\n\
139*9860b763SAndroid Build Coastguard Worker ; - plaintext is the CBOR-serialization of `KeyMaterial`\n\
140*9860b763SAndroid Build Coastguard Worker ; - nonce value is fixed, all zeroes\n\
141*9860b763SAndroid Build Coastguard Worker ; - no additional data\n\
142*9860b763SAndroid Build Coastguard Worker ;\n\
143*9860b763SAndroid Build Coastguard Worker ; Key derivation uses HKDF (RFC 5869) with HMAC-SHA256 to generate an AES-256 key:\n\
144*9860b763SAndroid Build Coastguard Worker ; - input keying material = a root key held in hardware\n\
145*9860b763SAndroid Build Coastguard Worker ; - salt = absent\n\
146*9860b763SAndroid Build Coastguard Worker ; - info = the following three or four chunks of context data concatenated:\n\
147*9860b763SAndroid Build Coastguard Worker ; - content of `EncryptedKeyBlob.key_derivation_input` (a random nonce)\n\
148*9860b763SAndroid Build Coastguard Worker ; - CBOR-serialization of `EncryptedKeyBlob.characteristics`\n\
149*9860b763SAndroid Build Coastguard Worker ; - CBOR-serialized array of additional hidden `KeyParam` items associated with the key, specifically:\n\
150*9860b763SAndroid Build Coastguard Worker ; - [Tag_ApplicationId, bstr] if required\n\
151*9860b763SAndroid Build Coastguard Worker ; - [Tag_ApplicationData, bstr] if required\n\
152*9860b763SAndroid Build Coastguard Worker ; - [Tag_RootOfTrust, bstr .cbor RootOfTrustInfo]\n\
153*9860b763SAndroid Build Coastguard Worker ; - (if secure storage is available) CBOR serialization of the `SecureDeletionData` structure, with:\n\
154*9860b763SAndroid Build Coastguard Worker ; - `factory_reset_secret` always populated\n\
155*9860b763SAndroid Build Coastguard Worker ; - `secure_deletion_secret` populated with:\n\
156*9860b763SAndroid Build Coastguard Worker ; - all zeroes (if `EncryptedKeyBlob.secure_deletion_slot` is empty)\n\
157*9860b763SAndroid Build Coastguard Worker ; - the contents of the slot (if `EncryptedKeyBlob.secure_deletion_slot` is non-empty)",
158*9860b763SAndroid Build Coastguard Worker );
159*9860b763SAndroid Build Coastguard Worker println!("{}", schema);
160*9860b763SAndroid Build Coastguard Worker schema.check();
161*9860b763SAndroid Build Coastguard Worker }
162