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