xref: /aosp_15_r20/system/keymint/tests/src/bin/auth-keyblob-parse.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 //! Utility program to parse a legacy authenticated keyblob.
16 
17 // Explicitly include alloc because macros from `kmr_common` assume it.
18 extern crate alloc;
19 
20 use kmr_common::{
21     crypto::*,
22     get_tag_value,
23     keyblob::{legacy::KeyBlob, *},
24     tag,
25 };
26 use kmr_crypto_boring::{eq::BoringEq, hmac::BoringHmac};
27 use kmr_wire::{
28     keymint,
29     keymint::{
30         Algorithm, DateTime, EcCurve, ErrorCode, KeyCharacteristics, KeyParam, SecurityLevel,
31     },
32 };
33 use std::convert::TryInto;
34 
main()35 fn main() {
36     let mut hex = false;
37     let args: Vec<String> = std::env::args().collect();
38     for arg in &args[1..] {
39         if arg == "--hex" {
40             hex = !hex;
41         } else {
42             process(arg, hex);
43         }
44     }
45 }
46 
47 const SOFTWARE_ROOT_OF_TRUST: &[u8] = b"SW";
48 
49 /// Remove all instances of some tags from a set of `KeyParameter`s.
remove_tags(params: &[KeyParam], tags: &[keymint::Tag]) -> Vec<KeyParam>50 pub fn remove_tags(params: &[KeyParam], tags: &[keymint::Tag]) -> Vec<KeyParam> {
51     params.iter().filter(|p| !tags.contains(&p.tag())).cloned().collect()
52 }
53 
process(filename: &str, hex: bool)54 fn process(filename: &str, hex: bool) {
55     let _ = env_logger::builder().is_test(true).try_init();
56 
57     let mut data: Vec<u8> = std::fs::read(filename).unwrap();
58     if hex {
59         let hexdata = std::str::from_utf8(&data).unwrap().trim();
60         data = match hex::decode(hexdata) {
61             Ok(v) => v,
62             Err(e) => {
63                 eprintln!(
64                     "{}: Failed to parse hex ({:?}): len={} {}",
65                     filename,
66                     e,
67                     hexdata.len(),
68                     hexdata
69                 );
70                 return;
71             }
72         };
73     }
74     let hidden = tag::hidden(&[], SOFTWARE_ROOT_OF_TRUST).unwrap();
75     let hmac = BoringHmac {};
76     let keyblob = match KeyBlob::deserialize(&hmac, &data, &hidden, BoringEq) {
77         Ok(k) => k,
78         Err(e) => {
79             eprintln!("{}: Failed to parse: {:?}", filename, e);
80             return;
81         }
82     };
83     println!(
84         "{}: KeyBlob  {{\n  key_material=...(len {}),\n  hw_enforced={:?},\n  sw_enforced={:?},\n}}",
85         filename,
86         keyblob.key_material.len(),
87         keyblob.hw_enforced,
88         keyblob.sw_enforced
89     );
90 
91     #[cfg(soong)]
92     {
93         // Also round-trip the keyblob to binary and expect to get back where we started.
94         let regenerated_data = keyblob.serialize(&hmac, &hidden).unwrap();
95         assert_eq!(&regenerated_data[..regenerated_data.len()], &data[..data.len()]);
96     }
97 
98     // Create a PlaintextKeyBlob from the data.
99     let mut combined = keyblob.hw_enforced.clone();
100     combined.extend_from_slice(&keyblob.sw_enforced);
101 
102     let algo_val = get_tag_value!(&combined, Algorithm, ErrorCode::InvalidArgument)
103         .expect("characteristics missing algorithm");
104 
105     let raw_key = keyblob.key_material.clone();
106     let key_material = match algo_val {
107         Algorithm::Aes => KeyMaterial::Aes(aes::Key::new(raw_key).unwrap().into()),
108         Algorithm::TripleDes => KeyMaterial::TripleDes(
109             des::Key(raw_key.try_into().expect("Incorrect length for 3DES key")).into(),
110         ),
111         Algorithm::Hmac => KeyMaterial::Hmac(hmac::Key(raw_key).into()),
112         Algorithm::Ec => {
113             let curve_val = tag::get_ec_curve(&combined).expect("characteristics missing EC curve");
114             match curve_val {
115                 EcCurve::P224 => KeyMaterial::Ec(
116                     EcCurve::P224,
117                     CurveType::Nist,
118                     ec::Key::P224(ec::NistKey(raw_key)).into(),
119                 ),
120                 EcCurve::P256 => KeyMaterial::Ec(
121                     EcCurve::P256,
122                     CurveType::Nist,
123                     ec::Key::P256(ec::NistKey(raw_key)).into(),
124                 ),
125                 EcCurve::P384 => KeyMaterial::Ec(
126                     EcCurve::P384,
127                     CurveType::Nist,
128                     ec::Key::P384(ec::NistKey(raw_key)).into(),
129                 ),
130                 EcCurve::P521 => KeyMaterial::Ec(
131                     EcCurve::P521,
132                     CurveType::Nist,
133                     ec::Key::P521(ec::NistKey(raw_key)).into(),
134                 ),
135                 EcCurve::Curve25519 => {
136                     ec::import_pkcs8_key(&raw_key).expect("curve25519 key in PKCS#8 format")
137                 }
138             }
139         }
140         Algorithm::Rsa => KeyMaterial::Rsa(rsa::Key(raw_key).into()),
141     };
142 
143     // Test the `tag::extract_key_characteristics()` entrypoint by comparing what it
144     // produces against the keyblob's combined characteristics. To do this, we need
145     // to simulate a key-generation operation by:
146     // - removing the KeyMint-added tags
147     // - removing any Keystore-enforced tags
148     // - adding any tags required for key generation.
149     let mut filtered = keyblob.hw_enforced.clone();
150     filtered.extend_from_slice(&keyblob.sw_enforced);
151     let filtered = remove_tags(&filtered, tag::AUTO_ADDED_CHARACTERISTICS);
152     let mut filtered = remove_tags(&filtered, tag::KEYSTORE_ENFORCED_CHARACTERISTICS);
153     filtered.sort_by(tag::legacy::param_compare);
154 
155     let mut keygen_params = filtered.clone();
156     match tag::get_algorithm(&filtered).unwrap() {
157         Algorithm::Ec | Algorithm::Rsa => {
158             keygen_params.push(KeyParam::CertificateNotBefore(DateTime { ms_since_epoch: 0 }));
159             keygen_params.push(KeyParam::CertificateNotAfter(DateTime {
160                 ms_since_epoch: 1_900_000_000_000,
161             }));
162         }
163         _ => {}
164     }
165     keygen_params.sort_by(tag::legacy::param_compare);
166     let (extracted, _) = tag::extract_key_gen_characteristics(
167         kmr_common::tag::SecureStorage::Unavailable,
168         &keygen_params,
169         SecurityLevel::Software,
170     )
171     .unwrap();
172     assert_eq!(extracted[0].authorizations, filtered);
173 
174     let plaintext_keyblob = PlaintextKeyBlob {
175         characteristics: vec![
176             KeyCharacteristics {
177                 security_level: SecurityLevel::TrustedEnvironment,
178                 authorizations: keyblob.hw_enforced,
179             },
180             KeyCharacteristics {
181                 security_level: SecurityLevel::Software,
182                 authorizations: keyblob.sw_enforced,
183             },
184         ],
185         key_material,
186     };
187     println!("{}:  => {:?}", filename, plaintext_keyblob);
188 }
189