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