xref: /aosp_15_r20/system/security/keystore2/src/sw_keyblob.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1*e1997b9aSAndroid Build Coastguard Worker // Copyright 2023, The Android Open Source Project
2*e1997b9aSAndroid Build Coastguard Worker //
3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*e1997b9aSAndroid Build Coastguard Worker //
7*e1997b9aSAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*e1997b9aSAndroid Build Coastguard Worker //
9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License.
14*e1997b9aSAndroid Build Coastguard Worker 
15*e1997b9aSAndroid Build Coastguard Worker //! Code for parsing software-backed keyblobs, as emitted by the C++ reference implementation of
16*e1997b9aSAndroid Build Coastguard Worker //! KeyMint.
17*e1997b9aSAndroid Build Coastguard Worker 
18*e1997b9aSAndroid Build Coastguard Worker use crate::error::Error;
19*e1997b9aSAndroid Build Coastguard Worker use crate::ks_err;
20*e1997b9aSAndroid Build Coastguard Worker use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
21*e1997b9aSAndroid Build Coastguard Worker     Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
22*e1997b9aSAndroid Build Coastguard Worker     ErrorCode::ErrorCode, HardwareAuthenticatorType::HardwareAuthenticatorType,
23*e1997b9aSAndroid Build Coastguard Worker     KeyFormat::KeyFormat, KeyOrigin::KeyOrigin, KeyParameter::KeyParameter,
24*e1997b9aSAndroid Build Coastguard Worker     KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
25*e1997b9aSAndroid Build Coastguard Worker     Tag::Tag, TagType::TagType,
26*e1997b9aSAndroid Build Coastguard Worker };
27*e1997b9aSAndroid Build Coastguard Worker use anyhow::Result;
28*e1997b9aSAndroid Build Coastguard Worker use keystore2_crypto::hmac_sha256;
29*e1997b9aSAndroid Build Coastguard Worker use std::mem::size_of;
30*e1997b9aSAndroid Build Coastguard Worker 
31*e1997b9aSAndroid Build Coastguard Worker #[cfg(test)]
32*e1997b9aSAndroid Build Coastguard Worker mod tests;
33*e1997b9aSAndroid Build Coastguard Worker 
34*e1997b9aSAndroid Build Coastguard Worker /// Root of trust value.
35*e1997b9aSAndroid Build Coastguard Worker const SOFTWARE_ROOT_OF_TRUST: &[u8] = b"SW";
36*e1997b9aSAndroid Build Coastguard Worker 
37*e1997b9aSAndroid Build Coastguard Worker /// Error macro.
38*e1997b9aSAndroid Build Coastguard Worker macro_rules! bloberr {
39*e1997b9aSAndroid Build Coastguard Worker     { $($arg:tt)+ } => {
40*e1997b9aSAndroid Build Coastguard Worker         anyhow::Error::new(Error::Km(ErrorCode::INVALID_KEY_BLOB)).context(ks_err!($($arg)+))
41*e1997b9aSAndroid Build Coastguard Worker     };
42*e1997b9aSAndroid Build Coastguard Worker }
43*e1997b9aSAndroid Build Coastguard Worker 
44*e1997b9aSAndroid Build Coastguard Worker /// Get the `KeyParameterValue` associated with a tag from a collection of `KeyParameter`s.
get_tag_value(params: &[KeyParameter], tag: Tag) -> Option<&KeyParameterValue>45*e1997b9aSAndroid Build Coastguard Worker fn get_tag_value(params: &[KeyParameter], tag: Tag) -> Option<&KeyParameterValue> {
46*e1997b9aSAndroid Build Coastguard Worker     params.iter().find_map(|kp| if kp.tag == tag { Some(&kp.value) } else { None })
47*e1997b9aSAndroid Build Coastguard Worker }
48*e1997b9aSAndroid Build Coastguard Worker 
49*e1997b9aSAndroid Build Coastguard Worker /// Get the [`TagType`] for a [`Tag`].
tag_type(tag: &Tag) -> TagType50*e1997b9aSAndroid Build Coastguard Worker fn tag_type(tag: &Tag) -> TagType {
51*e1997b9aSAndroid Build Coastguard Worker     TagType((tag.0 as u32 & 0xf0000000) as i32)
52*e1997b9aSAndroid Build Coastguard Worker }
53*e1997b9aSAndroid Build Coastguard Worker 
54*e1997b9aSAndroid Build Coastguard Worker /// Extract key material and combined key characteristics from a legacy authenticated keyblob.
export_key( data: &[u8], params: &[KeyParameter], ) -> Result<(KeyFormat, Vec<u8>, Vec<KeyParameter>)>55*e1997b9aSAndroid Build Coastguard Worker pub fn export_key(
56*e1997b9aSAndroid Build Coastguard Worker     data: &[u8],
57*e1997b9aSAndroid Build Coastguard Worker     params: &[KeyParameter],
58*e1997b9aSAndroid Build Coastguard Worker ) -> Result<(KeyFormat, Vec<u8>, Vec<KeyParameter>)> {
59*e1997b9aSAndroid Build Coastguard Worker     let hidden = hidden_params(params, &[SOFTWARE_ROOT_OF_TRUST]);
60*e1997b9aSAndroid Build Coastguard Worker     let KeyBlob { key_material, hw_enforced, sw_enforced } =
61*e1997b9aSAndroid Build Coastguard Worker         KeyBlob::new_from_serialized(data, &hidden)?;
62*e1997b9aSAndroid Build Coastguard Worker 
63*e1997b9aSAndroid Build Coastguard Worker     let mut combined = hw_enforced;
64*e1997b9aSAndroid Build Coastguard Worker     combined.extend_from_slice(&sw_enforced);
65*e1997b9aSAndroid Build Coastguard Worker 
66*e1997b9aSAndroid Build Coastguard Worker     let algo_val =
67*e1997b9aSAndroid Build Coastguard Worker         get_tag_value(&combined, Tag::ALGORITHM).ok_or_else(|| bloberr!("No algorithm found!"))?;
68*e1997b9aSAndroid Build Coastguard Worker 
69*e1997b9aSAndroid Build Coastguard Worker     let format = match algo_val {
70*e1997b9aSAndroid Build Coastguard Worker         KeyParameterValue::Algorithm(Algorithm::AES)
71*e1997b9aSAndroid Build Coastguard Worker         | KeyParameterValue::Algorithm(Algorithm::TRIPLE_DES)
72*e1997b9aSAndroid Build Coastguard Worker         | KeyParameterValue::Algorithm(Algorithm::HMAC) => KeyFormat::RAW,
73*e1997b9aSAndroid Build Coastguard Worker         KeyParameterValue::Algorithm(Algorithm::RSA)
74*e1997b9aSAndroid Build Coastguard Worker         | KeyParameterValue::Algorithm(Algorithm::EC) => KeyFormat::PKCS8,
75*e1997b9aSAndroid Build Coastguard Worker         _ => return Err(bloberr!("Unexpected algorithm {:?}", algo_val)),
76*e1997b9aSAndroid Build Coastguard Worker     };
77*e1997b9aSAndroid Build Coastguard Worker 
78*e1997b9aSAndroid Build Coastguard Worker     let key_material = match (format, algo_val) {
79*e1997b9aSAndroid Build Coastguard Worker         (KeyFormat::PKCS8, KeyParameterValue::Algorithm(Algorithm::EC)) => {
80*e1997b9aSAndroid Build Coastguard Worker             // Key material format depends on the curve.
81*e1997b9aSAndroid Build Coastguard Worker             let curve = get_tag_value(&combined, Tag::EC_CURVE)
82*e1997b9aSAndroid Build Coastguard Worker                 .ok_or_else(|| bloberr!("Failed to determine curve for EC key!"))?;
83*e1997b9aSAndroid Build Coastguard Worker             match curve {
84*e1997b9aSAndroid Build Coastguard Worker                 KeyParameterValue::EcCurve(EcCurve::CURVE_25519) => key_material,
85*e1997b9aSAndroid Build Coastguard Worker                 KeyParameterValue::EcCurve(EcCurve::P_224) => {
86*e1997b9aSAndroid Build Coastguard Worker                     pkcs8_wrap_nist_key(&key_material, EcCurve::P_224)?
87*e1997b9aSAndroid Build Coastguard Worker                 }
88*e1997b9aSAndroid Build Coastguard Worker                 KeyParameterValue::EcCurve(EcCurve::P_256) => {
89*e1997b9aSAndroid Build Coastguard Worker                     pkcs8_wrap_nist_key(&key_material, EcCurve::P_256)?
90*e1997b9aSAndroid Build Coastguard Worker                 }
91*e1997b9aSAndroid Build Coastguard Worker                 KeyParameterValue::EcCurve(EcCurve::P_384) => {
92*e1997b9aSAndroid Build Coastguard Worker                     pkcs8_wrap_nist_key(&key_material, EcCurve::P_384)?
93*e1997b9aSAndroid Build Coastguard Worker                 }
94*e1997b9aSAndroid Build Coastguard Worker                 KeyParameterValue::EcCurve(EcCurve::P_521) => {
95*e1997b9aSAndroid Build Coastguard Worker                     pkcs8_wrap_nist_key(&key_material, EcCurve::P_521)?
96*e1997b9aSAndroid Build Coastguard Worker                 }
97*e1997b9aSAndroid Build Coastguard Worker                 _ => {
98*e1997b9aSAndroid Build Coastguard Worker                     return Err(bloberr!("Unexpected EC curve {curve:?}"));
99*e1997b9aSAndroid Build Coastguard Worker                 }
100*e1997b9aSAndroid Build Coastguard Worker             }
101*e1997b9aSAndroid Build Coastguard Worker         }
102*e1997b9aSAndroid Build Coastguard Worker         (KeyFormat::RAW, _) => key_material,
103*e1997b9aSAndroid Build Coastguard Worker         (format, algo) => {
104*e1997b9aSAndroid Build Coastguard Worker             return Err(bloberr!(
105*e1997b9aSAndroid Build Coastguard Worker                 "Unsupported combination of {format:?} format for {algo:?} algorithm"
106*e1997b9aSAndroid Build Coastguard Worker             ));
107*e1997b9aSAndroid Build Coastguard Worker         }
108*e1997b9aSAndroid Build Coastguard Worker     };
109*e1997b9aSAndroid Build Coastguard Worker     Ok((format, key_material, combined))
110*e1997b9aSAndroid Build Coastguard Worker }
111*e1997b9aSAndroid Build Coastguard Worker 
112*e1997b9aSAndroid Build Coastguard Worker /// DER-encoded `AlgorithmIdentifier` for a P-224 key.
113*e1997b9aSAndroid Build Coastguard Worker const DER_ALGORITHM_ID_P224: &[u8] = &[
114*e1997b9aSAndroid Build Coastguard Worker     0x30, 0x10, // SEQUENCE (AlgorithmIdentifier) {
115*e1997b9aSAndroid Build Coastguard Worker     0x06, 0x07, // OBJECT IDENTIFIER (algorithm)
116*e1997b9aSAndroid Build Coastguard Worker     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // 1.2.840.10045.2.1 (ecPublicKey)
117*e1997b9aSAndroid Build Coastguard Worker     0x06, 0x05, // OBJECT IDENTIFIER (param)
118*e1997b9aSAndroid Build Coastguard Worker     0x2b, 0x81, 0x04, 0x00, 0x21, //  1.3.132.0.33 (secp224r1) }
119*e1997b9aSAndroid Build Coastguard Worker ];
120*e1997b9aSAndroid Build Coastguard Worker 
121*e1997b9aSAndroid Build Coastguard Worker /// DER-encoded `AlgorithmIdentifier` for a P-256 key.
122*e1997b9aSAndroid Build Coastguard Worker const DER_ALGORITHM_ID_P256: &[u8] = &[
123*e1997b9aSAndroid Build Coastguard Worker     0x30, 0x13, // SEQUENCE (AlgorithmIdentifier) {
124*e1997b9aSAndroid Build Coastguard Worker     0x06, 0x07, // OBJECT IDENTIFIER (algorithm)
125*e1997b9aSAndroid Build Coastguard Worker     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // 1.2.840.10045.2.1 (ecPublicKey)
126*e1997b9aSAndroid Build Coastguard Worker     0x06, 0x08, // OBJECT IDENTIFIER (param)
127*e1997b9aSAndroid Build Coastguard Worker     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, //  1.2.840.10045.3.1.7 (secp256r1) }
128*e1997b9aSAndroid Build Coastguard Worker ];
129*e1997b9aSAndroid Build Coastguard Worker 
130*e1997b9aSAndroid Build Coastguard Worker /// DER-encoded `AlgorithmIdentifier` for a P-384 key.
131*e1997b9aSAndroid Build Coastguard Worker const DER_ALGORITHM_ID_P384: &[u8] = &[
132*e1997b9aSAndroid Build Coastguard Worker     0x30, 0x10, // SEQUENCE (AlgorithmIdentifier) {
133*e1997b9aSAndroid Build Coastguard Worker     0x06, 0x07, // OBJECT IDENTIFIER (algorithm)
134*e1997b9aSAndroid Build Coastguard Worker     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // 1.2.840.10045.2.1 (ecPublicKey)
135*e1997b9aSAndroid Build Coastguard Worker     0x06, 0x05, // OBJECT IDENTIFIER (param)
136*e1997b9aSAndroid Build Coastguard Worker     0x2b, 0x81, 0x04, 0x00, 0x22, //  1.3.132.0.34 (secp384r1) }
137*e1997b9aSAndroid Build Coastguard Worker ];
138*e1997b9aSAndroid Build Coastguard Worker 
139*e1997b9aSAndroid Build Coastguard Worker /// DER-encoded `AlgorithmIdentifier` for a P-384 key.
140*e1997b9aSAndroid Build Coastguard Worker const DER_ALGORITHM_ID_P521: &[u8] = &[
141*e1997b9aSAndroid Build Coastguard Worker     0x30, 0x10, // SEQUENCE (AlgorithmIdentifier) {
142*e1997b9aSAndroid Build Coastguard Worker     0x06, 0x07, // OBJECT IDENTIFIER (algorithm)
143*e1997b9aSAndroid Build Coastguard Worker     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // 1.2.840.10045.2.1 (ecPublicKey)
144*e1997b9aSAndroid Build Coastguard Worker     0x06, 0x05, // OBJECT IDENTIFIER (param)
145*e1997b9aSAndroid Build Coastguard Worker     0x2b, 0x81, 0x04, 0x00, 0x23, //  1.3.132.0.35 (secp521r1) }
146*e1997b9aSAndroid Build Coastguard Worker ];
147*e1997b9aSAndroid Build Coastguard Worker 
148*e1997b9aSAndroid Build Coastguard Worker /// DER-encoded integer value zero.
149*e1997b9aSAndroid Build Coastguard Worker const DER_VERSION_0: &[u8] = &[
150*e1997b9aSAndroid Build Coastguard Worker     0x02, // INTEGER
151*e1997b9aSAndroid Build Coastguard Worker     0x01, // len
152*e1997b9aSAndroid Build Coastguard Worker     0x00, // value 0
153*e1997b9aSAndroid Build Coastguard Worker ];
154*e1997b9aSAndroid Build Coastguard Worker 
155*e1997b9aSAndroid Build Coastguard Worker /// Given a NIST curve EC key in the form of a DER-encoded `ECPrivateKey`
156*e1997b9aSAndroid Build Coastguard Worker /// (RFC 5915 s3), wrap it in a DER-encoded PKCS#8 format (RFC 5208 s5).
pkcs8_wrap_nist_key(nist_key: &[u8], curve: EcCurve) -> Result<Vec<u8>>157*e1997b9aSAndroid Build Coastguard Worker fn pkcs8_wrap_nist_key(nist_key: &[u8], curve: EcCurve) -> Result<Vec<u8>> {
158*e1997b9aSAndroid Build Coastguard Worker     let der_alg_id = match curve {
159*e1997b9aSAndroid Build Coastguard Worker         EcCurve::P_224 => DER_ALGORITHM_ID_P224,
160*e1997b9aSAndroid Build Coastguard Worker         EcCurve::P_256 => DER_ALGORITHM_ID_P256,
161*e1997b9aSAndroid Build Coastguard Worker         EcCurve::P_384 => DER_ALGORITHM_ID_P384,
162*e1997b9aSAndroid Build Coastguard Worker         EcCurve::P_521 => DER_ALGORITHM_ID_P521,
163*e1997b9aSAndroid Build Coastguard Worker         _ => return Err(bloberr!("unknown curve {curve:?}")),
164*e1997b9aSAndroid Build Coastguard Worker     };
165*e1997b9aSAndroid Build Coastguard Worker 
166*e1997b9aSAndroid Build Coastguard Worker     // Output format is:
167*e1997b9aSAndroid Build Coastguard Worker     //
168*e1997b9aSAndroid Build Coastguard Worker     //    PrivateKeyInfo ::= SEQUENCE {
169*e1997b9aSAndroid Build Coastguard Worker     //        version                   INTEGER,
170*e1997b9aSAndroid Build Coastguard Worker     //        privateKeyAlgorithm       AlgorithmIdentifier,
171*e1997b9aSAndroid Build Coastguard Worker     //        privateKey                OCTET STRING,
172*e1997b9aSAndroid Build Coastguard Worker     //    }
173*e1997b9aSAndroid Build Coastguard Worker     //
174*e1997b9aSAndroid Build Coastguard Worker     // Start by building the OCTET STRING so we know its length.
175*e1997b9aSAndroid Build Coastguard Worker     let mut nist_key_octet_string = Vec::new();
176*e1997b9aSAndroid Build Coastguard Worker     nist_key_octet_string.push(0x04); // OCTET STRING
177*e1997b9aSAndroid Build Coastguard Worker     add_der_len(&mut nist_key_octet_string, nist_key.len())?;
178*e1997b9aSAndroid Build Coastguard Worker     nist_key_octet_string.extend_from_slice(nist_key);
179*e1997b9aSAndroid Build Coastguard Worker 
180*e1997b9aSAndroid Build Coastguard Worker     let mut buf = Vec::new();
181*e1997b9aSAndroid Build Coastguard Worker     buf.push(0x30); // SEQUENCE
182*e1997b9aSAndroid Build Coastguard Worker     add_der_len(&mut buf, DER_VERSION_0.len() + der_alg_id.len() + nist_key_octet_string.len())?;
183*e1997b9aSAndroid Build Coastguard Worker     buf.extend_from_slice(DER_VERSION_0);
184*e1997b9aSAndroid Build Coastguard Worker     buf.extend_from_slice(der_alg_id);
185*e1997b9aSAndroid Build Coastguard Worker     buf.extend_from_slice(&nist_key_octet_string);
186*e1997b9aSAndroid Build Coastguard Worker     Ok(buf)
187*e1997b9aSAndroid Build Coastguard Worker }
188*e1997b9aSAndroid Build Coastguard Worker 
189*e1997b9aSAndroid Build Coastguard Worker /// Append a DER-encoded length value to the given buffer.
add_der_len(buf: &mut Vec<u8>, len: usize) -> Result<()>190*e1997b9aSAndroid Build Coastguard Worker fn add_der_len(buf: &mut Vec<u8>, len: usize) -> Result<()> {
191*e1997b9aSAndroid Build Coastguard Worker     if len <= 0x7f {
192*e1997b9aSAndroid Build Coastguard Worker         buf.push(len as u8)
193*e1997b9aSAndroid Build Coastguard Worker     } else if len <= 0xff {
194*e1997b9aSAndroid Build Coastguard Worker         buf.push(0x81); // One length octet to come
195*e1997b9aSAndroid Build Coastguard Worker         buf.push(len as u8);
196*e1997b9aSAndroid Build Coastguard Worker     } else if len <= 0xffff {
197*e1997b9aSAndroid Build Coastguard Worker         buf.push(0x82); // Two length octets to come
198*e1997b9aSAndroid Build Coastguard Worker         buf.push((len >> 8) as u8);
199*e1997b9aSAndroid Build Coastguard Worker         buf.push((len & 0xff) as u8);
200*e1997b9aSAndroid Build Coastguard Worker     } else {
201*e1997b9aSAndroid Build Coastguard Worker         return Err(bloberr!("Unsupported DER length {len}"));
202*e1997b9aSAndroid Build Coastguard Worker     }
203*e1997b9aSAndroid Build Coastguard Worker     Ok(())
204*e1997b9aSAndroid Build Coastguard Worker }
205*e1997b9aSAndroid Build Coastguard Worker 
206*e1997b9aSAndroid Build Coastguard Worker /// Plaintext key blob, with key characteristics.
207*e1997b9aSAndroid Build Coastguard Worker #[derive(PartialEq, Eq)]
208*e1997b9aSAndroid Build Coastguard Worker struct KeyBlob {
209*e1997b9aSAndroid Build Coastguard Worker     /// Raw key material.
210*e1997b9aSAndroid Build Coastguard Worker     key_material: Vec<u8>,
211*e1997b9aSAndroid Build Coastguard Worker     /// Hardware-enforced key characteristics.
212*e1997b9aSAndroid Build Coastguard Worker     hw_enforced: Vec<KeyParameter>,
213*e1997b9aSAndroid Build Coastguard Worker     /// Software-enforced key characteristics.
214*e1997b9aSAndroid Build Coastguard Worker     sw_enforced: Vec<KeyParameter>,
215*e1997b9aSAndroid Build Coastguard Worker }
216*e1997b9aSAndroid Build Coastguard Worker 
217*e1997b9aSAndroid Build Coastguard Worker impl KeyBlob {
218*e1997b9aSAndroid Build Coastguard Worker     /// Key blob version.
219*e1997b9aSAndroid Build Coastguard Worker     const KEY_BLOB_VERSION: u8 = 0;
220*e1997b9aSAndroid Build Coastguard Worker 
221*e1997b9aSAndroid Build Coastguard Worker     /// Hard-coded HMAC key used for keyblob authentication.
222*e1997b9aSAndroid Build Coastguard Worker     const LEGACY_HMAC_KEY: &'static [u8] = b"IntegrityAssuredBlob0\0";
223*e1997b9aSAndroid Build Coastguard Worker 
224*e1997b9aSAndroid Build Coastguard Worker     /// Size (in bytes) of appended MAC.
225*e1997b9aSAndroid Build Coastguard Worker     const MAC_LEN: usize = 8;
226*e1997b9aSAndroid Build Coastguard Worker 
227*e1997b9aSAndroid Build Coastguard Worker     /// Parse a serialized [`KeyBlob`].
new_from_serialized(mut data: &[u8], hidden: &[KeyParameter]) -> Result<Self>228*e1997b9aSAndroid Build Coastguard Worker     fn new_from_serialized(mut data: &[u8], hidden: &[KeyParameter]) -> Result<Self> {
229*e1997b9aSAndroid Build Coastguard Worker         // Keyblob needs to be at least long enough for:
230*e1997b9aSAndroid Build Coastguard Worker         // - version byte,
231*e1997b9aSAndroid Build Coastguard Worker         // - 4-byte len for key material
232*e1997b9aSAndroid Build Coastguard Worker         // - 4-byte len for hw_enforced params
233*e1997b9aSAndroid Build Coastguard Worker         // - 4-byte len for sw_enforced params
234*e1997b9aSAndroid Build Coastguard Worker         // - MAC tag.
235*e1997b9aSAndroid Build Coastguard Worker         if data.len() < (1 + 3 * size_of::<u32>() + Self::MAC_LEN) {
236*e1997b9aSAndroid Build Coastguard Worker             return Err(bloberr!("blob not long enough (len = {})", data.len()));
237*e1997b9aSAndroid Build Coastguard Worker         }
238*e1997b9aSAndroid Build Coastguard Worker 
239*e1997b9aSAndroid Build Coastguard Worker         // Check the HMAC in the last 8 bytes before doing anything else.
240*e1997b9aSAndroid Build Coastguard Worker         let mac = &data[data.len() - Self::MAC_LEN..];
241*e1997b9aSAndroid Build Coastguard Worker         let computed_mac = Self::compute_hmac(&data[..data.len() - Self::MAC_LEN], hidden)?;
242*e1997b9aSAndroid Build Coastguard Worker         if mac != computed_mac {
243*e1997b9aSAndroid Build Coastguard Worker             return Err(bloberr!("invalid key blob"));
244*e1997b9aSAndroid Build Coastguard Worker         }
245*e1997b9aSAndroid Build Coastguard Worker 
246*e1997b9aSAndroid Build Coastguard Worker         let version = consume_u8(&mut data)?;
247*e1997b9aSAndroid Build Coastguard Worker         if version != Self::KEY_BLOB_VERSION {
248*e1997b9aSAndroid Build Coastguard Worker             return Err(bloberr!("unexpected blob version {}", version));
249*e1997b9aSAndroid Build Coastguard Worker         }
250*e1997b9aSAndroid Build Coastguard Worker         let key_material = consume_vec(&mut data)?;
251*e1997b9aSAndroid Build Coastguard Worker         let hw_enforced = deserialize_params(&mut data)?;
252*e1997b9aSAndroid Build Coastguard Worker         let sw_enforced = deserialize_params(&mut data)?;
253*e1997b9aSAndroid Build Coastguard Worker 
254*e1997b9aSAndroid Build Coastguard Worker         // Should just be the (already-checked) MAC left.
255*e1997b9aSAndroid Build Coastguard Worker         let rest = &data[Self::MAC_LEN..];
256*e1997b9aSAndroid Build Coastguard Worker         if !rest.is_empty() {
257*e1997b9aSAndroid Build Coastguard Worker             return Err(bloberr!("extra data (len {})", rest.len()));
258*e1997b9aSAndroid Build Coastguard Worker         }
259*e1997b9aSAndroid Build Coastguard Worker         Ok(KeyBlob { key_material, hw_enforced, sw_enforced })
260*e1997b9aSAndroid Build Coastguard Worker     }
261*e1997b9aSAndroid Build Coastguard Worker 
262*e1997b9aSAndroid Build Coastguard Worker     /// Compute the authentication HMAC for a KeyBlob. This is built as:
263*e1997b9aSAndroid Build Coastguard Worker     ///   HMAC-SHA256(HK, data || serialize(hidden))
264*e1997b9aSAndroid Build Coastguard Worker     /// with HK = b"IntegrityAssuredBlob0\0".
compute_hmac(data: &[u8], hidden: &[KeyParameter]) -> Result<Vec<u8>>265*e1997b9aSAndroid Build Coastguard Worker     fn compute_hmac(data: &[u8], hidden: &[KeyParameter]) -> Result<Vec<u8>> {
266*e1997b9aSAndroid Build Coastguard Worker         let hidden_data = serialize_params(hidden)?;
267*e1997b9aSAndroid Build Coastguard Worker         let mut combined = data.to_vec();
268*e1997b9aSAndroid Build Coastguard Worker         combined.extend_from_slice(&hidden_data);
269*e1997b9aSAndroid Build Coastguard Worker         let mut tag = hmac_sha256(Self::LEGACY_HMAC_KEY, &combined)?;
270*e1997b9aSAndroid Build Coastguard Worker         tag.truncate(Self::MAC_LEN);
271*e1997b9aSAndroid Build Coastguard Worker         Ok(tag)
272*e1997b9aSAndroid Build Coastguard Worker     }
273*e1997b9aSAndroid Build Coastguard Worker }
274*e1997b9aSAndroid Build Coastguard Worker 
275*e1997b9aSAndroid Build Coastguard Worker /// Build the parameters that are used as the hidden input to HMAC calculations:
276*e1997b9aSAndroid Build Coastguard Worker /// - `ApplicationId(data)` if present
277*e1997b9aSAndroid Build Coastguard Worker /// - `ApplicationData(data)` if present
278*e1997b9aSAndroid Build Coastguard Worker /// - (repeated) `RootOfTrust(rot)` where `rot` is a hardcoded piece of root of trust information.
hidden_params(params: &[KeyParameter], rots: &[&[u8]]) -> Vec<KeyParameter>279*e1997b9aSAndroid Build Coastguard Worker fn hidden_params(params: &[KeyParameter], rots: &[&[u8]]) -> Vec<KeyParameter> {
280*e1997b9aSAndroid Build Coastguard Worker     let mut results = Vec::new();
281*e1997b9aSAndroid Build Coastguard Worker     if let Some(app_id) = get_tag_value(params, Tag::APPLICATION_ID) {
282*e1997b9aSAndroid Build Coastguard Worker         results.push(KeyParameter { tag: Tag::APPLICATION_ID, value: app_id.clone() });
283*e1997b9aSAndroid Build Coastguard Worker     }
284*e1997b9aSAndroid Build Coastguard Worker     if let Some(app_data) = get_tag_value(params, Tag::APPLICATION_DATA) {
285*e1997b9aSAndroid Build Coastguard Worker         results.push(KeyParameter { tag: Tag::APPLICATION_DATA, value: app_data.clone() });
286*e1997b9aSAndroid Build Coastguard Worker     }
287*e1997b9aSAndroid Build Coastguard Worker     for rot in rots {
288*e1997b9aSAndroid Build Coastguard Worker         results.push(KeyParameter {
289*e1997b9aSAndroid Build Coastguard Worker             tag: Tag::ROOT_OF_TRUST,
290*e1997b9aSAndroid Build Coastguard Worker             value: KeyParameterValue::Blob(rot.to_vec()),
291*e1997b9aSAndroid Build Coastguard Worker         });
292*e1997b9aSAndroid Build Coastguard Worker     }
293*e1997b9aSAndroid Build Coastguard Worker     results
294*e1997b9aSAndroid Build Coastguard Worker }
295*e1997b9aSAndroid Build Coastguard Worker 
296*e1997b9aSAndroid Build Coastguard Worker /// Retrieve a `u8` from the start of the given slice, if possible.
consume_u8(data: &mut &[u8]) -> Result<u8>297*e1997b9aSAndroid Build Coastguard Worker fn consume_u8(data: &mut &[u8]) -> Result<u8> {
298*e1997b9aSAndroid Build Coastguard Worker     match data.first() {
299*e1997b9aSAndroid Build Coastguard Worker         Some(b) => {
300*e1997b9aSAndroid Build Coastguard Worker             *data = &(*data)[1..];
301*e1997b9aSAndroid Build Coastguard Worker             Ok(*b)
302*e1997b9aSAndroid Build Coastguard Worker         }
303*e1997b9aSAndroid Build Coastguard Worker         None => Err(bloberr!("failed to find 1 byte")),
304*e1997b9aSAndroid Build Coastguard Worker     }
305*e1997b9aSAndroid Build Coastguard Worker }
306*e1997b9aSAndroid Build Coastguard Worker 
307*e1997b9aSAndroid Build Coastguard Worker /// Move past a bool value from the start of the given slice, if possible.
308*e1997b9aSAndroid Build Coastguard Worker /// Bool values should only be included if `true`, so fail if the value
309*e1997b9aSAndroid Build Coastguard Worker /// is anything other than 1.
consume_bool(data: &mut &[u8]) -> Result<bool>310*e1997b9aSAndroid Build Coastguard Worker fn consume_bool(data: &mut &[u8]) -> Result<bool> {
311*e1997b9aSAndroid Build Coastguard Worker     let b = consume_u8(data)?;
312*e1997b9aSAndroid Build Coastguard Worker     if b == 0x01 {
313*e1997b9aSAndroid Build Coastguard Worker         Ok(true)
314*e1997b9aSAndroid Build Coastguard Worker     } else {
315*e1997b9aSAndroid Build Coastguard Worker         Err(bloberr!("bool value other than 1 encountered"))
316*e1997b9aSAndroid Build Coastguard Worker     }
317*e1997b9aSAndroid Build Coastguard Worker }
318*e1997b9aSAndroid Build Coastguard Worker 
319*e1997b9aSAndroid Build Coastguard Worker /// Retrieve a (host-ordered) `u32` from the start of the given slice, if possible.
consume_u32(data: &mut &[u8]) -> Result<u32>320*e1997b9aSAndroid Build Coastguard Worker fn consume_u32(data: &mut &[u8]) -> Result<u32> {
321*e1997b9aSAndroid Build Coastguard Worker     const LEN: usize = size_of::<u32>();
322*e1997b9aSAndroid Build Coastguard Worker     if data.len() < LEN {
323*e1997b9aSAndroid Build Coastguard Worker         return Err(bloberr!("failed to find {LEN} bytes"));
324*e1997b9aSAndroid Build Coastguard Worker     }
325*e1997b9aSAndroid Build Coastguard Worker     let chunk: [u8; LEN] = data[..LEN].try_into().unwrap(); // safe: just checked
326*e1997b9aSAndroid Build Coastguard Worker     *data = &(*data)[LEN..];
327*e1997b9aSAndroid Build Coastguard Worker     Ok(u32::from_ne_bytes(chunk))
328*e1997b9aSAndroid Build Coastguard Worker }
329*e1997b9aSAndroid Build Coastguard Worker 
330*e1997b9aSAndroid Build Coastguard Worker /// Retrieve a (host-ordered) `i32` from the start of the given slice, if possible.
consume_i32(data: &mut &[u8]) -> Result<i32>331*e1997b9aSAndroid Build Coastguard Worker fn consume_i32(data: &mut &[u8]) -> Result<i32> {
332*e1997b9aSAndroid Build Coastguard Worker     const LEN: usize = size_of::<i32>();
333*e1997b9aSAndroid Build Coastguard Worker     if data.len() < LEN {
334*e1997b9aSAndroid Build Coastguard Worker         return Err(bloberr!("failed to find {LEN} bytes"));
335*e1997b9aSAndroid Build Coastguard Worker     }
336*e1997b9aSAndroid Build Coastguard Worker     let chunk: [u8; LEN] = data[..LEN].try_into().unwrap(); // safe: just checked
337*e1997b9aSAndroid Build Coastguard Worker     *data = &(*data)[4..];
338*e1997b9aSAndroid Build Coastguard Worker     Ok(i32::from_ne_bytes(chunk))
339*e1997b9aSAndroid Build Coastguard Worker }
340*e1997b9aSAndroid Build Coastguard Worker 
341*e1997b9aSAndroid Build Coastguard Worker /// Retrieve a (host-ordered) `i64` from the start of the given slice, if possible.
consume_i64(data: &mut &[u8]) -> Result<i64>342*e1997b9aSAndroid Build Coastguard Worker fn consume_i64(data: &mut &[u8]) -> Result<i64> {
343*e1997b9aSAndroid Build Coastguard Worker     const LEN: usize = size_of::<i64>();
344*e1997b9aSAndroid Build Coastguard Worker     if data.len() < LEN {
345*e1997b9aSAndroid Build Coastguard Worker         return Err(bloberr!("failed to find {LEN} bytes"));
346*e1997b9aSAndroid Build Coastguard Worker     }
347*e1997b9aSAndroid Build Coastguard Worker     let chunk: [u8; LEN] = data[..LEN].try_into().unwrap(); // safe: just checked
348*e1997b9aSAndroid Build Coastguard Worker     *data = &(*data)[LEN..];
349*e1997b9aSAndroid Build Coastguard Worker     Ok(i64::from_ne_bytes(chunk))
350*e1997b9aSAndroid Build Coastguard Worker }
351*e1997b9aSAndroid Build Coastguard Worker 
352*e1997b9aSAndroid Build Coastguard Worker /// Retrieve a vector of bytes from the start of the given slice, if possible,
353*e1997b9aSAndroid Build Coastguard Worker /// with the length of the data expected to appear as a host-ordered `u32` prefix.
consume_vec(data: &mut &[u8]) -> Result<Vec<u8>>354*e1997b9aSAndroid Build Coastguard Worker fn consume_vec(data: &mut &[u8]) -> Result<Vec<u8>> {
355*e1997b9aSAndroid Build Coastguard Worker     let len = consume_u32(data)? as usize;
356*e1997b9aSAndroid Build Coastguard Worker     if len > data.len() {
357*e1997b9aSAndroid Build Coastguard Worker         return Err(bloberr!("failed to find {} bytes", len));
358*e1997b9aSAndroid Build Coastguard Worker     }
359*e1997b9aSAndroid Build Coastguard Worker     let result = data[..len].to_vec();
360*e1997b9aSAndroid Build Coastguard Worker     *data = &(*data)[len..];
361*e1997b9aSAndroid Build Coastguard Worker     Ok(result)
362*e1997b9aSAndroid Build Coastguard Worker }
363*e1997b9aSAndroid Build Coastguard Worker 
364*e1997b9aSAndroid Build Coastguard Worker /// Retrieve the contents of a tag of `TagType::Bytes`.  The `data` parameter holds
365*e1997b9aSAndroid Build Coastguard Worker /// the as-yet unparsed data, and a length and offset are read from this (and consumed).
366*e1997b9aSAndroid Build Coastguard Worker /// This length and offset refer to a location in the combined `blob_data`; however,
367*e1997b9aSAndroid Build Coastguard Worker /// the offset is expected to be the next unconsumed chunk of `blob_data`, as indicated
368*e1997b9aSAndroid Build Coastguard Worker /// by `next_blob_offset` (which itself is updated as a result of consuming the data).
consume_blob( data: &mut &[u8], next_blob_offset: &mut usize, blob_data: &[u8], ) -> Result<Vec<u8>>369*e1997b9aSAndroid Build Coastguard Worker fn consume_blob(
370*e1997b9aSAndroid Build Coastguard Worker     data: &mut &[u8],
371*e1997b9aSAndroid Build Coastguard Worker     next_blob_offset: &mut usize,
372*e1997b9aSAndroid Build Coastguard Worker     blob_data: &[u8],
373*e1997b9aSAndroid Build Coastguard Worker ) -> Result<Vec<u8>> {
374*e1997b9aSAndroid Build Coastguard Worker     let data_len = consume_u32(data)? as usize;
375*e1997b9aSAndroid Build Coastguard Worker     let data_offset = consume_u32(data)? as usize;
376*e1997b9aSAndroid Build Coastguard Worker     // Expect the blob data to come from the next offset in the initial blob chunk.
377*e1997b9aSAndroid Build Coastguard Worker     if data_offset != *next_blob_offset {
378*e1997b9aSAndroid Build Coastguard Worker         return Err(bloberr!("got blob offset {} instead of {}", data_offset, next_blob_offset));
379*e1997b9aSAndroid Build Coastguard Worker     }
380*e1997b9aSAndroid Build Coastguard Worker     if (data_offset + data_len) > blob_data.len() {
381*e1997b9aSAndroid Build Coastguard Worker         return Err(bloberr!(
382*e1997b9aSAndroid Build Coastguard Worker             "blob at offset [{}..{}+{}] goes beyond blob data size {}",
383*e1997b9aSAndroid Build Coastguard Worker             data_offset,
384*e1997b9aSAndroid Build Coastguard Worker             data_offset,
385*e1997b9aSAndroid Build Coastguard Worker             data_len,
386*e1997b9aSAndroid Build Coastguard Worker             blob_data.len(),
387*e1997b9aSAndroid Build Coastguard Worker         ));
388*e1997b9aSAndroid Build Coastguard Worker     }
389*e1997b9aSAndroid Build Coastguard Worker 
390*e1997b9aSAndroid Build Coastguard Worker     let slice = &blob_data[data_offset..data_offset + data_len];
391*e1997b9aSAndroid Build Coastguard Worker     *next_blob_offset += data_len;
392*e1997b9aSAndroid Build Coastguard Worker     Ok(slice.to_vec())
393*e1997b9aSAndroid Build Coastguard Worker }
394*e1997b9aSAndroid Build Coastguard Worker 
395*e1997b9aSAndroid Build Coastguard Worker /// Deserialize a collection of [`KeyParam`]s in legacy serialized format. The provided slice is
396*e1997b9aSAndroid Build Coastguard Worker /// modified to contain the unconsumed part of the data.
deserialize_params(data: &mut &[u8]) -> Result<Vec<KeyParameter>>397*e1997b9aSAndroid Build Coastguard Worker fn deserialize_params(data: &mut &[u8]) -> Result<Vec<KeyParameter>> {
398*e1997b9aSAndroid Build Coastguard Worker     let blob_data_size = consume_u32(data)? as usize;
399*e1997b9aSAndroid Build Coastguard Worker     if blob_data_size > data.len() {
400*e1997b9aSAndroid Build Coastguard Worker         return Err(bloberr!(
401*e1997b9aSAndroid Build Coastguard Worker             "blob data size {} bigger than data (len={})",
402*e1997b9aSAndroid Build Coastguard Worker             blob_data_size,
403*e1997b9aSAndroid Build Coastguard Worker             data.len()
404*e1997b9aSAndroid Build Coastguard Worker         ));
405*e1997b9aSAndroid Build Coastguard Worker     }
406*e1997b9aSAndroid Build Coastguard Worker 
407*e1997b9aSAndroid Build Coastguard Worker     let blob_data = &data[..blob_data_size];
408*e1997b9aSAndroid Build Coastguard Worker     let mut next_blob_offset = 0;
409*e1997b9aSAndroid Build Coastguard Worker 
410*e1997b9aSAndroid Build Coastguard Worker     // Move past the blob data.
411*e1997b9aSAndroid Build Coastguard Worker     *data = &data[blob_data_size..];
412*e1997b9aSAndroid Build Coastguard Worker 
413*e1997b9aSAndroid Build Coastguard Worker     let param_count = consume_u32(data)? as usize;
414*e1997b9aSAndroid Build Coastguard Worker     let param_size = consume_u32(data)? as usize;
415*e1997b9aSAndroid Build Coastguard Worker     if param_size > data.len() {
416*e1997b9aSAndroid Build Coastguard Worker         return Err(bloberr!(
417*e1997b9aSAndroid Build Coastguard Worker             "size mismatch 4+{}+4+4+{} > {}",
418*e1997b9aSAndroid Build Coastguard Worker             blob_data_size,
419*e1997b9aSAndroid Build Coastguard Worker             param_size,
420*e1997b9aSAndroid Build Coastguard Worker             data.len()
421*e1997b9aSAndroid Build Coastguard Worker         ));
422*e1997b9aSAndroid Build Coastguard Worker     }
423*e1997b9aSAndroid Build Coastguard Worker 
424*e1997b9aSAndroid Build Coastguard Worker     let mut results = Vec::new();
425*e1997b9aSAndroid Build Coastguard Worker     for _i in 0..param_count {
426*e1997b9aSAndroid Build Coastguard Worker         let tag_num = consume_u32(data)? as i32;
427*e1997b9aSAndroid Build Coastguard Worker         let tag = Tag(tag_num);
428*e1997b9aSAndroid Build Coastguard Worker         let value = match tag_type(&tag) {
429*e1997b9aSAndroid Build Coastguard Worker             TagType::INVALID => return Err(bloberr!("invalid tag {:?} encountered", tag)),
430*e1997b9aSAndroid Build Coastguard Worker             TagType::ENUM | TagType::ENUM_REP => {
431*e1997b9aSAndroid Build Coastguard Worker                 let val = consume_i32(data)?;
432*e1997b9aSAndroid Build Coastguard Worker                 match tag {
433*e1997b9aSAndroid Build Coastguard Worker                     Tag::ALGORITHM => KeyParameterValue::Algorithm(Algorithm(val)),
434*e1997b9aSAndroid Build Coastguard Worker                     Tag::BLOCK_MODE => KeyParameterValue::BlockMode(BlockMode(val)),
435*e1997b9aSAndroid Build Coastguard Worker                     Tag::PADDING => KeyParameterValue::PaddingMode(PaddingMode(val)),
436*e1997b9aSAndroid Build Coastguard Worker                     Tag::DIGEST | Tag::RSA_OAEP_MGF_DIGEST => {
437*e1997b9aSAndroid Build Coastguard Worker                         KeyParameterValue::Digest(Digest(val))
438*e1997b9aSAndroid Build Coastguard Worker                     }
439*e1997b9aSAndroid Build Coastguard Worker                     Tag::EC_CURVE => KeyParameterValue::EcCurve(EcCurve(val)),
440*e1997b9aSAndroid Build Coastguard Worker                     Tag::ORIGIN => KeyParameterValue::Origin(KeyOrigin(val)),
441*e1997b9aSAndroid Build Coastguard Worker                     Tag::PURPOSE => KeyParameterValue::KeyPurpose(KeyPurpose(val)),
442*e1997b9aSAndroid Build Coastguard Worker                     Tag::USER_AUTH_TYPE => {
443*e1997b9aSAndroid Build Coastguard Worker                         KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType(val))
444*e1997b9aSAndroid Build Coastguard Worker                     }
445*e1997b9aSAndroid Build Coastguard Worker                     _ => KeyParameterValue::Integer(val),
446*e1997b9aSAndroid Build Coastguard Worker                 }
447*e1997b9aSAndroid Build Coastguard Worker             }
448*e1997b9aSAndroid Build Coastguard Worker             TagType::UINT | TagType::UINT_REP => KeyParameterValue::Integer(consume_i32(data)?),
449*e1997b9aSAndroid Build Coastguard Worker             TagType::ULONG | TagType::ULONG_REP => {
450*e1997b9aSAndroid Build Coastguard Worker                 KeyParameterValue::LongInteger(consume_i64(data)?)
451*e1997b9aSAndroid Build Coastguard Worker             }
452*e1997b9aSAndroid Build Coastguard Worker             TagType::DATE => KeyParameterValue::DateTime(consume_i64(data)?),
453*e1997b9aSAndroid Build Coastguard Worker             TagType::BOOL => KeyParameterValue::BoolValue(consume_bool(data)?),
454*e1997b9aSAndroid Build Coastguard Worker             TagType::BIGNUM | TagType::BYTES => {
455*e1997b9aSAndroid Build Coastguard Worker                 KeyParameterValue::Blob(consume_blob(data, &mut next_blob_offset, blob_data)?)
456*e1997b9aSAndroid Build Coastguard Worker             }
457*e1997b9aSAndroid Build Coastguard Worker             _ => return Err(bloberr!("unexpected tag type for {:?}", tag)),
458*e1997b9aSAndroid Build Coastguard Worker         };
459*e1997b9aSAndroid Build Coastguard Worker         results.push(KeyParameter { tag, value });
460*e1997b9aSAndroid Build Coastguard Worker     }
461*e1997b9aSAndroid Build Coastguard Worker 
462*e1997b9aSAndroid Build Coastguard Worker     Ok(results)
463*e1997b9aSAndroid Build Coastguard Worker }
464*e1997b9aSAndroid Build Coastguard Worker 
465*e1997b9aSAndroid Build Coastguard Worker /// Serialize a collection of [`KeyParameter`]s into a format that is compatible with previous
466*e1997b9aSAndroid Build Coastguard Worker /// implementations:
467*e1997b9aSAndroid Build Coastguard Worker ///
468*e1997b9aSAndroid Build Coastguard Worker /// ```text
469*e1997b9aSAndroid Build Coastguard Worker /// [0..4]              Size B of `TagType::Bytes` data, in host order.
470*e1997b9aSAndroid Build Coastguard Worker /// [4..4+B]      (*)   Concatenated contents of each `TagType::Bytes` tag.
471*e1997b9aSAndroid Build Coastguard Worker /// [4+B..4+B+4]        Count N of the number of parameters, in host order.
472*e1997b9aSAndroid Build Coastguard Worker /// [8+B..8+B+4]        Size Z of encoded parameters.
473*e1997b9aSAndroid Build Coastguard Worker /// [12+B..12+B+Z]      Serialized parameters one after another.
474*e1997b9aSAndroid Build Coastguard Worker /// ```
475*e1997b9aSAndroid Build Coastguard Worker ///
476*e1997b9aSAndroid Build Coastguard Worker /// Individual parameters are serialized in the last chunk as:
477*e1997b9aSAndroid Build Coastguard Worker ///
478*e1997b9aSAndroid Build Coastguard Worker /// ```text
479*e1997b9aSAndroid Build Coastguard Worker /// [0..4]              Tag number, in host order.
480*e1997b9aSAndroid Build Coastguard Worker /// Followed by one of the following depending on the tag's `TagType`; all integers in host order:
481*e1997b9aSAndroid Build Coastguard Worker ///   [4..5]            Bool value (`TagType::Bool`)
482*e1997b9aSAndroid Build Coastguard Worker ///   [4..8]            i32 values (`TagType::Uint[Rep]`, `TagType::Enum[Rep]`)
483*e1997b9aSAndroid Build Coastguard Worker ///   [4..12]           i64 values, in host order (`TagType::UlongRep`, `TagType::Date`)
484*e1997b9aSAndroid Build Coastguard Worker ///   [4..8] + [8..12]  Size + offset of data in (*) above (`TagType::Bytes`, `TagType::Bignum`)
485*e1997b9aSAndroid Build Coastguard Worker /// ```
serialize_params(params: &[KeyParameter]) -> Result<Vec<u8>>486*e1997b9aSAndroid Build Coastguard Worker fn serialize_params(params: &[KeyParameter]) -> Result<Vec<u8>> {
487*e1997b9aSAndroid Build Coastguard Worker     // First 4 bytes are the length of the combined [`TagType::Bytes`] data; come back to set that
488*e1997b9aSAndroid Build Coastguard Worker     // in a moment.
489*e1997b9aSAndroid Build Coastguard Worker     let mut result = vec![0; 4];
490*e1997b9aSAndroid Build Coastguard Worker 
491*e1997b9aSAndroid Build Coastguard Worker     // Next append the contents of all of the [`TagType::Bytes`] data.
492*e1997b9aSAndroid Build Coastguard Worker     let mut blob_size = 0u32;
493*e1997b9aSAndroid Build Coastguard Worker     for param in params {
494*e1997b9aSAndroid Build Coastguard Worker         let tag_type = tag_type(&param.tag);
495*e1997b9aSAndroid Build Coastguard Worker         if let KeyParameterValue::Blob(v) = &param.value {
496*e1997b9aSAndroid Build Coastguard Worker             if tag_type != TagType::BIGNUM && tag_type != TagType::BYTES {
497*e1997b9aSAndroid Build Coastguard Worker                 return Err(bloberr!("unexpected tag type for tag {:?} with blob", param.tag));
498*e1997b9aSAndroid Build Coastguard Worker             }
499*e1997b9aSAndroid Build Coastguard Worker             result.extend_from_slice(v);
500*e1997b9aSAndroid Build Coastguard Worker             blob_size += v.len() as u32;
501*e1997b9aSAndroid Build Coastguard Worker         }
502*e1997b9aSAndroid Build Coastguard Worker     }
503*e1997b9aSAndroid Build Coastguard Worker     // Go back and fill in the combined blob length in native order at the start.
504*e1997b9aSAndroid Build Coastguard Worker     result[..4].clone_from_slice(&blob_size.to_ne_bytes());
505*e1997b9aSAndroid Build Coastguard Worker 
506*e1997b9aSAndroid Build Coastguard Worker     result.extend_from_slice(&(params.len() as u32).to_ne_bytes());
507*e1997b9aSAndroid Build Coastguard Worker 
508*e1997b9aSAndroid Build Coastguard Worker     let params_size_offset = result.len();
509*e1997b9aSAndroid Build Coastguard Worker     result.extend_from_slice(&[0u8; 4]); // placeholder for size of elements
510*e1997b9aSAndroid Build Coastguard Worker     let first_param_offset = result.len();
511*e1997b9aSAndroid Build Coastguard Worker     let mut blob_offset = 0u32;
512*e1997b9aSAndroid Build Coastguard Worker     for param in params {
513*e1997b9aSAndroid Build Coastguard Worker         result.extend_from_slice(&(param.tag.0 as u32).to_ne_bytes());
514*e1997b9aSAndroid Build Coastguard Worker         match &param.value {
515*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::Invalid(_v) => {
516*e1997b9aSAndroid Build Coastguard Worker                 return Err(bloberr!("invalid tag found in {:?}", param))
517*e1997b9aSAndroid Build Coastguard Worker             }
518*e1997b9aSAndroid Build Coastguard Worker 
519*e1997b9aSAndroid Build Coastguard Worker             // Enum-holding variants.
520*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::Algorithm(v) => {
521*e1997b9aSAndroid Build Coastguard Worker                 result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
522*e1997b9aSAndroid Build Coastguard Worker             }
523*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::BlockMode(v) => {
524*e1997b9aSAndroid Build Coastguard Worker                 result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
525*e1997b9aSAndroid Build Coastguard Worker             }
526*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::PaddingMode(v) => {
527*e1997b9aSAndroid Build Coastguard Worker                 result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
528*e1997b9aSAndroid Build Coastguard Worker             }
529*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::Digest(v) => result.extend_from_slice(&(v.0 as u32).to_ne_bytes()),
530*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::EcCurve(v) => result.extend_from_slice(&(v.0 as u32).to_ne_bytes()),
531*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::Origin(v) => result.extend_from_slice(&(v.0 as u32).to_ne_bytes()),
532*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::KeyPurpose(v) => {
533*e1997b9aSAndroid Build Coastguard Worker                 result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
534*e1997b9aSAndroid Build Coastguard Worker             }
535*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::HardwareAuthenticatorType(v) => {
536*e1997b9aSAndroid Build Coastguard Worker                 result.extend_from_slice(&(v.0 as u32).to_ne_bytes())
537*e1997b9aSAndroid Build Coastguard Worker             }
538*e1997b9aSAndroid Build Coastguard Worker 
539*e1997b9aSAndroid Build Coastguard Worker             // Value-holding variants.
540*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::Integer(v) => result.extend_from_slice(&(*v as u32).to_ne_bytes()),
541*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::BoolValue(_v) => result.push(0x01u8),
542*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::LongInteger(v) | KeyParameterValue::DateTime(v) => {
543*e1997b9aSAndroid Build Coastguard Worker                 result.extend_from_slice(&(*v as u64).to_ne_bytes())
544*e1997b9aSAndroid Build Coastguard Worker             }
545*e1997b9aSAndroid Build Coastguard Worker             KeyParameterValue::Blob(v) => {
546*e1997b9aSAndroid Build Coastguard Worker                 let blob_len = v.len() as u32;
547*e1997b9aSAndroid Build Coastguard Worker                 result.extend_from_slice(&blob_len.to_ne_bytes());
548*e1997b9aSAndroid Build Coastguard Worker                 result.extend_from_slice(&blob_offset.to_ne_bytes());
549*e1997b9aSAndroid Build Coastguard Worker                 blob_offset += blob_len;
550*e1997b9aSAndroid Build Coastguard Worker             }
551*e1997b9aSAndroid Build Coastguard Worker 
552*e1997b9aSAndroid Build Coastguard Worker             _ => return Err(bloberr!("unknown value found in {:?}", param)),
553*e1997b9aSAndroid Build Coastguard Worker         }
554*e1997b9aSAndroid Build Coastguard Worker     }
555*e1997b9aSAndroid Build Coastguard Worker     let serialized_size = (result.len() - first_param_offset) as u32;
556*e1997b9aSAndroid Build Coastguard Worker 
557*e1997b9aSAndroid Build Coastguard Worker     // Go back and fill in the total serialized size.
558*e1997b9aSAndroid Build Coastguard Worker     result[params_size_offset..params_size_offset + 4]
559*e1997b9aSAndroid Build Coastguard Worker         .clone_from_slice(&serialized_size.to_ne_bytes());
560*e1997b9aSAndroid Build Coastguard Worker     Ok(result)
561*e1997b9aSAndroid Build Coastguard Worker }
562