1 //
2 // Copyright (C) 2022 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 //! Emulated implementation of device traits for `IRemotelyProvisionedComponent`.
17 
18 use core::cell::RefCell;
19 use kmr_common::crypto::{ec, ec::CoseKeyPurpose, Ec, KeyMaterial};
20 use kmr_common::{crypto, explicit, rpc_err, vec_try, Error};
21 use kmr_crypto_boring::{ec::BoringEc, hmac::BoringHmac, rng::BoringRng};
22 use kmr_ta::device::{
23     CsrSigningAlgorithm, DiceInfo, PubDiceArtifacts, RetrieveRpcArtifacts, RpcV2Req,
24 };
25 use kmr_wire::coset::{iana, CoseSign1Builder, HeaderBuilder};
26 use kmr_wire::keymint::{Digest, EcCurve};
27 use kmr_wire::{cbor::value::Value, coset::AsCborValue, rpc, CborError};
28 
29 /// Trait to encapsulate deterministic derivation of secret data.
30 pub trait DeriveBytes {
31     /// Derive `output_len` bytes of data from `context`, deterministically.
derive_bytes(&self, context: &[u8], output_len: usize) -> Result<Vec<u8>, Error>32     fn derive_bytes(&self, context: &[u8], output_len: usize) -> Result<Vec<u8>, Error>;
33 }
34 
35 /// Common emulated implementation of RPC artifact retrieval.
36 pub struct Artifacts<T: DeriveBytes> {
37     derive: T,
38     sign_algo: CsrSigningAlgorithm,
39     // Invariant once populated: `self.dice_info.signing_algorithm` == `self.sign_algo`
40     dice_info: RefCell<Option<DiceInfo>>,
41     // Invariant once populated: `self.bcc_signing_key` is a variant that matches `self.sign_algo`
42     bcc_signing_key: RefCell<Option<ec::Key>>,
43 }
44 
45 impl<T: DeriveBytes> RetrieveRpcArtifacts for Artifacts<T> {
derive_bytes_from_hbk( &self, _hkdf: &dyn crypto::Hkdf, context: &[u8], output_len: usize, ) -> Result<Vec<u8>, Error>46     fn derive_bytes_from_hbk(
47         &self,
48         _hkdf: &dyn crypto::Hkdf,
49         context: &[u8],
50         output_len: usize,
51     ) -> Result<Vec<u8>, Error> {
52         self.derive.derive_bytes(context, output_len)
53     }
54 
get_dice_info(&self, _test_mode: rpc::TestMode) -> Result<DiceInfo, Error>55     fn get_dice_info(&self, _test_mode: rpc::TestMode) -> Result<DiceInfo, Error> {
56         if self.dice_info.borrow().is_none() {
57             let (dice_info, priv_key) = self.generate_dice_artifacts(rpc::TestMode(false))?;
58             *self.dice_info.borrow_mut() = Some(dice_info);
59             *self.bcc_signing_key.borrow_mut() = Some(priv_key);
60         }
61 
62         Ok(self
63             .dice_info
64             .borrow()
65             .as_ref()
66             .ok_or_else(|| rpc_err!(Failed, "DICE artifacts are not initialized."))?
67             .clone())
68     }
69 
sign_data( &self, ec: &dyn crypto::Ec, data: &[u8], _rpc_v2: Option<RpcV2Req>, ) -> Result<Vec<u8>, Error>70     fn sign_data(
71         &self,
72         ec: &dyn crypto::Ec,
73         data: &[u8],
74         _rpc_v2: Option<RpcV2Req>,
75     ) -> Result<Vec<u8>, Error> {
76         // DICE artifacts should have been initialized via `get_dice_info()` by the time this
77         // method is called.
78         let private_key = self
79             .bcc_signing_key
80             .borrow()
81             .as_ref()
82             .ok_or_else(|| rpc_err!(Failed, "DICE artifacts are not initialized."))?
83             .clone();
84 
85         let mut op = ec.begin_sign(private_key.into(), self.signing_digest())?;
86         op.update(data)?;
87         let sig = op.finish()?;
88         crypto::ec::to_cose_signature(self.signing_curve(), sig)
89     }
90 }
91 
92 impl<T: DeriveBytes> Artifacts<T> {
93     /// Constructor.
new(derive: T, sign_algo: CsrSigningAlgorithm) -> Self94     pub fn new(derive: T, sign_algo: CsrSigningAlgorithm) -> Self {
95         Self {
96             derive,
97             sign_algo,
98             dice_info: RefCell::new(None),
99             bcc_signing_key: RefCell::new(None),
100         }
101     }
102 
103     /// Indicate the curve used in signing.
signing_curve(&self) -> EcCurve104     fn signing_curve(&self) -> EcCurve {
105         match self.sign_algo {
106             CsrSigningAlgorithm::ES256 => EcCurve::P256,
107             CsrSigningAlgorithm::ES384 => EcCurve::P384,
108             CsrSigningAlgorithm::EdDSA => EcCurve::Curve25519,
109         }
110     }
111 
112     /// Indicate the digest used in signing.
signing_digest(&self) -> Digest113     fn signing_digest(&self) -> Digest {
114         match self.sign_algo {
115             CsrSigningAlgorithm::ES256 => Digest::Sha256,
116             CsrSigningAlgorithm::ES384 => Digest::Sha384,
117             CsrSigningAlgorithm::EdDSA => Digest::None,
118         }
119     }
120 
121     /// Indicate the COSE algorithm value associated with signing.
signing_cose_algo(&self) -> iana::Algorithm122     fn signing_cose_algo(&self) -> iana::Algorithm {
123         match self.sign_algo {
124             CsrSigningAlgorithm::ES256 => iana::Algorithm::ES256,
125             CsrSigningAlgorithm::ES384 => iana::Algorithm::ES384,
126             CsrSigningAlgorithm::EdDSA => iana::Algorithm::EdDSA,
127         }
128     }
129 
generate_dice_artifacts( &self, _test_mode: rpc::TestMode, ) -> Result<(DiceInfo, ec::Key), Error>130     fn generate_dice_artifacts(
131         &self,
132         _test_mode: rpc::TestMode,
133     ) -> Result<(DiceInfo, ec::Key), Error> {
134         let ec = BoringEc::default();
135 
136         let key_material = match self.sign_algo {
137             CsrSigningAlgorithm::EdDSA => {
138                 let secret = self.derive_bytes_from_hbk(&BoringHmac, b"Device Key Seed", 32)?;
139                 ec::import_raw_ed25519_key(&secret)
140             }
141             // TODO: generate the *same* key after reboot, by use of the TPM.
142             CsrSigningAlgorithm::ES256 => {
143                 ec.generate_nist_key(&mut BoringRng, ec::NistCurve::P256, &[])
144             }
145             CsrSigningAlgorithm::ES384 => {
146                 ec.generate_nist_key(&mut BoringRng, ec::NistCurve::P384, &[])
147             }
148         }?;
149         let (pub_cose_key, private_key) = match key_material {
150             KeyMaterial::Ec(curve, curve_type, key) => (
151                 key.public_cose_key(
152                     &ec,
153                     curve,
154                     curve_type,
155                     CoseKeyPurpose::Sign,
156                     None, /* no key ID */
157                     rpc::TestMode(false),
158                 )?,
159                 key,
160             ),
161             _ => {
162                 return Err(rpc_err!(
163                     Failed,
164                     "expected the Ec variant of KeyMaterial for the cdi leaf key."
165                 ))
166             }
167         };
168 
169         let cose_key_cbor = pub_cose_key.to_cbor_value().map_err(CborError::from)?;
170         let cose_key_cbor_data = kmr_ta::rkp::serialize_cbor(&cose_key_cbor)?;
171 
172         // Construct `DiceChainEntryPayload`
173         let dice_chain_entry_payload = Value::Map(vec_try![
174             // Issuer
175             (
176                 Value::Integer(1.into()),
177                 Value::Text(String::from("Issuer"))
178             ),
179             // Subject
180             (
181                 Value::Integer(2.into()),
182                 Value::Text(String::from("Subject"))
183             ),
184             // Subject public key
185             (
186                 Value::Integer((-4670552).into()),
187                 Value::Bytes(cose_key_cbor_data)
188             ),
189             // Key Usage field contains a CBOR byte string of the bits which correspond
190             // to `keyCertSign` as per RFC 5280 Section 4.2.1.3 (in little-endian byte order)
191             (
192                 Value::Integer((-4670553).into()),
193                 Value::Bytes(vec_try![0x20]?)
194             ),
195         ]?);
196         let dice_chain_entry_payload_data = kmr_ta::rkp::serialize_cbor(&dice_chain_entry_payload)?;
197 
198         // Construct `DiceChainEntry`
199         let protected = HeaderBuilder::new()
200             .algorithm(self.signing_cose_algo())
201             .build();
202         let dice_chain_entry = CoseSign1Builder::new()
203             .protected(protected)
204             .payload(dice_chain_entry_payload_data)
205             .try_create_signature(&[], |input| {
206                 let mut op = ec.begin_sign(private_key.clone(), self.signing_digest())?;
207                 op.update(input)?;
208                 let sig = op.finish()?;
209                 crypto::ec::to_cose_signature(self.signing_curve(), sig)
210             })?
211             .build();
212         let dice_chain_entry_cbor = dice_chain_entry.to_cbor_value().map_err(CborError::from)?;
213 
214         // Construct `DiceCertChain`
215         let dice_cert_chain = Value::Array(vec_try![cose_key_cbor, dice_chain_entry_cbor]?);
216         let dice_cert_chain_data = kmr_ta::rkp::serialize_cbor(&dice_cert_chain)?;
217 
218         // Construct `UdsCerts` as an empty CBOR map
219         let uds_certs_data = kmr_ta::rkp::serialize_cbor(&Value::Map(Vec::new()))?;
220 
221         let pub_dice_artifacts = PubDiceArtifacts {
222             dice_cert_chain: dice_cert_chain_data,
223             uds_certs: uds_certs_data,
224         };
225 
226         let dice_info = DiceInfo {
227             pub_dice_artifacts,
228             signing_algorithm: self.sign_algo,
229             rpc_v2_test_cdi_priv: None,
230         };
231 
232         Ok((dice_info, explicit!(private_key)?))
233     }
234 }
235