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