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!(®enerated_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