blob: fadd25241769a75da3a6a5311dddb04cc25dcad9 [file] [log] [blame]
Max Bires148c08e2020-10-13 13:41:41 -07001// Copyright 2020, 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//! This is the implementation for the remote provisioning AIDL interface between
16//! the network providers for remote provisioning and the system. This interface
17//! allows the caller to prompt the Remote Provisioning HAL to generate keys and
18//! CBOR blobs that can be ferried to a provisioning server that will return
19//! certificate chains signed by some root authority and stored in a keystore SQLite
20//! DB.
21
Max Biresb2e1d032021-02-08 21:35:05 -080022use std::collections::HashMap;
Max Bires148c08e2020-10-13 13:41:41 -070023
Max Biresb2e1d032021-02-08 21:35:05 -080024use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Max Bires97f96812021-02-23 23:44:57 -080025 Algorithm::Algorithm, AttestationKey::AttestationKey, Certificate::Certificate,
Max Bires834dd362021-03-23 13:01:57 -070026 DeviceInfo::DeviceInfo, IRemotelyProvisionedComponent::IRemotelyProvisionedComponent,
27 KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue,
28 MacedPublicKey::MacedPublicKey, ProtectedData::ProtectedData, SecurityLevel::SecurityLevel,
29 Tag::Tag,
Max Biresb2e1d032021-02-08 21:35:05 -080030};
Max Bires148c08e2020-10-13 13:41:41 -070031use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
32 AttestationPoolStatus::AttestationPoolStatus, IRemoteProvisioning::BnRemoteProvisioning,
Seth Moore7ee79f92021-12-07 11:42:49 -080033 IRemoteProvisioning::IRemoteProvisioning,
34 IRemotelyProvisionedKeyPool::IRemotelyProvisionedKeyPool, ImplInfo::ImplInfo,
35 RemotelyProvisionedKey::RemotelyProvisionedKey,
Max Bires148c08e2020-10-13 13:41:41 -070036};
Andrew Walbrande45c8b2021-04-13 14:42:38 +000037use android_security_remoteprovisioning::binder::{BinderFeatures, Strong};
Max Bires97f96812021-02-23 23:44:57 -080038use android_system_keystore2::aidl::android::system::keystore2::{
Seth Moore7ee79f92021-12-07 11:42:49 -080039 Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
Max Bires97f96812021-02-23 23:44:57 -080040};
Max Biresb2e1d032021-02-08 21:35:05 -080041use anyhow::{Context, Result};
Max Bires97f96812021-02-23 23:44:57 -080042use keystore2_crypto::parse_subject_from_certificate;
Max Bires48fc2e52021-11-17 10:13:04 -080043use serde_cbor::Value;
44use std::collections::BTreeMap;
Max Bires97f96812021-02-23 23:44:57 -080045use std::sync::atomic::{AtomicBool, Ordering};
Max Bires148c08e2020-10-13 13:41:41 -070046
Max Bires97f96812021-02-23 23:44:57 -080047use crate::database::{CertificateChain, KeystoreDB, Uuid};
48use crate::error::{self, map_or_log_err, map_rem_prov_error, Error};
Max Biresb2e1d032021-02-08 21:35:05 -080049use crate::globals::{get_keymint_device, get_remotely_provisioned_component, DB};
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000050use crate::metrics_store::log_rkp_error_stats;
Seth Moore7ee79f92021-12-07 11:42:49 -080051use crate::permission::KeystorePerm;
52use crate::utils::{check_keystore_permission, watchdog as wd};
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000053use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
Max Bires148c08e2020-10-13 13:41:41 -070054
Max Bires97f96812021-02-23 23:44:57 -080055/// Contains helper functions to check if remote provisioning is enabled on the system and, if so,
56/// to assign and retrieve attestation keys and certificate chains.
57#[derive(Default)]
58pub struct RemProvState {
59 security_level: SecurityLevel,
60 km_uuid: Uuid,
61 is_hal_present: AtomicBool,
62}
63
Max Bires48fc2e52021-11-17 10:13:04 -080064static COSE_KEY_XCOORD: Value = Value::Integer(-2);
65static COSE_KEY_YCOORD: Value = Value::Integer(-3);
66static COSE_MAC0_LEN: usize = 4;
67static COSE_MAC0_PAYLOAD: usize = 2;
68
Max Bires97f96812021-02-23 23:44:57 -080069impl RemProvState {
70 /// Creates a RemProvState struct.
71 pub fn new(security_level: SecurityLevel, km_uuid: Uuid) -> Self {
72 Self { security_level, km_uuid, is_hal_present: AtomicBool::new(true) }
73 }
74
75 /// Checks if remote provisioning is enabled and partially caches the result. On a hybrid system
76 /// remote provisioning can flip from being disabled to enabled depending on responses from the
77 /// server, so unfortunately caching the presence or absence of the HAL is not enough to fully
78 /// make decisions about the state of remote provisioning during runtime.
79 fn check_rem_prov_enabled(&self, db: &mut KeystoreDB) -> Result<bool> {
80 if !self.is_hal_present.load(Ordering::Relaxed)
81 || get_remotely_provisioned_component(&self.security_level).is_err()
82 {
83 self.is_hal_present.store(false, Ordering::Relaxed);
84 return Ok(false);
85 }
86 // To check if remote provisioning is enabled on a system that supports both remote
87 // provisioning and factory provisioned keys, we only need to check if there are any
88 // keys at all generated to indicate if the app has gotten the signal to begin filling
89 // the key pool from the server.
90 let pool_status = db
91 .get_attestation_pool_status(0 /* date */, &self.km_uuid)
92 .context("In check_rem_prov_enabled: failed to get attestation pool status.")?;
93 Ok(pool_status.total != 0)
94 }
95
Max Bires97f96812021-02-23 23:44:57 -080096 fn is_asymmetric_key(&self, params: &[KeyParameter]) -> bool {
97 params.iter().any(|kp| {
98 matches!(
99 kp,
100 KeyParameter {
101 tag: Tag::ALGORITHM,
102 value: KeyParameterValue::Algorithm(Algorithm::RSA)
103 } | KeyParameter {
104 tag: Tag::ALGORITHM,
105 value: KeyParameterValue::Algorithm(Algorithm::EC)
106 }
107 )
108 })
109 }
110
111 /// Checks to see (1) if the key in question should be attested to based on the algorithm and
112 /// (2) if remote provisioning is present and enabled on the system. If these conditions are
113 /// met, it makes an attempt to fetch the attestation key assigned to the `caller_uid`.
114 ///
115 /// It returns the ResponseCode `OUT_OF_KEYS` if there is not one key currently assigned to the
116 /// `caller_uid` and there are none available to assign.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700117 pub fn get_remotely_provisioned_attestation_key_and_certs(
Max Bires97f96812021-02-23 23:44:57 -0800118 &self,
119 key: &KeyDescriptor,
120 caller_uid: u32,
121 params: &[KeyParameter],
122 db: &mut KeystoreDB,
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700123 ) -> Result<Option<(AttestationKey, Certificate)>> {
Max Bires97f96812021-02-23 23:44:57 -0800124 if !self.is_asymmetric_key(params) || !self.check_rem_prov_enabled(db)? {
125 // There is no remote provisioning component for this security level on the
126 // device. Return None so the underlying KM instance knows to use its
127 // factory provisioned key instead. Alternatively, it's not an asymmetric key
128 // and therefore will not be attested.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700129 Ok(None)
Max Bires97f96812021-02-23 23:44:57 -0800130 } else {
Seth Moore7ee79f92021-12-07 11:42:49 -0800131 match get_rem_prov_attest_key(key.domain, caller_uid, db, &self.km_uuid) {
Max Bires31cdfb82021-07-06 02:59:25 -0700132 Err(e) => {
133 log::error!(
134 concat!(
135 "In get_remote_provisioning_key_and_certs: Failed to get ",
136 "attestation key. {:?}"
137 ),
138 e
139 );
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +0000140 log_rkp_error_stats(MetricsRkpError::FALL_BACK_DURING_HYBRID);
Max Bires31cdfb82021-07-06 02:59:25 -0700141 Ok(None)
142 }
143 Ok(v) => match v {
144 Some(cert_chain) => Ok(Some((
145 AttestationKey {
146 keyBlob: cert_chain.private_key.to_vec(),
147 attestKeyParams: vec![],
148 issuerSubjectName: parse_subject_from_certificate(
149 &cert_chain.batch_cert,
150 )
Max Bires97f96812021-02-23 23:44:57 -0800151 .context(concat!(
Max Bires31cdfb82021-07-06 02:59:25 -0700152 "In get_remote_provisioning_key_and_certs: Failed to ",
153 "parse subject."
154 ))?,
155 },
156 Certificate { encodedCertificate: cert_chain.cert_chain },
157 ))),
158 None => Ok(None),
159 },
Max Bires97f96812021-02-23 23:44:57 -0800160 }
161 }
162 }
163}
Max Bires148c08e2020-10-13 13:41:41 -0700164/// Implementation of the IRemoteProvisioning service.
Max Biresb2e1d032021-02-08 21:35:05 -0800165#[derive(Default)]
Max Bires148c08e2020-10-13 13:41:41 -0700166pub struct RemoteProvisioningService {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -0700167 device_by_sec_level: HashMap<SecurityLevel, Strong<dyn IRemotelyProvisionedComponent>>,
Max Biresd2ce46b2021-07-06 02:54:47 -0700168 curve_by_sec_level: HashMap<SecurityLevel, i32>,
Max Bires148c08e2020-10-13 13:41:41 -0700169}
170
171impl RemoteProvisioningService {
Max Biresb2e1d032021-02-08 21:35:05 -0800172 fn get_dev_by_sec_level(
173 &self,
174 sec_level: &SecurityLevel,
Seth Moore7ee79f92021-12-07 11:42:49 -0800175 ) -> Result<&dyn IRemotelyProvisionedComponent> {
Max Biresb2e1d032021-02-08 21:35:05 -0800176 if let Some(dev) = self.device_by_sec_level.get(sec_level) {
Seth Moore7ee79f92021-12-07 11:42:49 -0800177 Ok(dev.as_ref())
Max Biresb2e1d032021-02-08 21:35:05 -0800178 } else {
179 Err(error::Error::sys()).context(concat!(
180 "In get_dev_by_sec_level: Remote instance for requested security level",
181 " not found."
182 ))
183 }
184 }
185
Seth Moore7ee79f92021-12-07 11:42:49 -0800186 fn get_dev_by_unique_id(
187 &self,
188 unique_id: &str,
189 ) -> Result<(SecurityLevel, &dyn IRemotelyProvisionedComponent)> {
190 for (sec_level, dev) in &self.device_by_sec_level {
191 if dev.getHardwareInfo()?.uniqueId == Some(unique_id.to_string()) {
192 return Ok((*sec_level, dev.as_ref()));
193 }
194 }
195
196 Err(error::Error::sys()).context(format!(
197 "In get_dev_by_unique_id: Instance for requested unique id '{}' not found",
198 unique_id
199 ))
200 }
201
Max Bires148c08e2020-10-13 13:41:41 -0700202 /// Creates a new instance of the remote provisioning service
Stephen Crane221bbb52020-12-16 15:52:10 -0800203 pub fn new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800204 let mut result: Self = Default::default();
205 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
206 .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
Max Biresd2ce46b2021-07-06 02:54:47 -0700207 result.curve_by_sec_level.insert(
208 SecurityLevel::TRUSTED_ENVIRONMENT,
209 dev.getHardwareInfo()
210 .context("In new_native_binder: Failed to get hardware info for the TEE.")?
211 .supportedEekCurve,
212 );
Max Biresb2e1d032021-02-08 21:35:05 -0800213 result.device_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, dev);
214 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
Max Biresd2ce46b2021-07-06 02:54:47 -0700215 result.curve_by_sec_level.insert(
216 SecurityLevel::STRONGBOX,
217 dev.getHardwareInfo()
218 .context("In new_native_binder: Failed to get hardware info for StrongBox.")?
219 .supportedEekCurve,
220 );
Max Biresb2e1d032021-02-08 21:35:05 -0800221 result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
222 }
Andrew Walbrande45c8b2021-04-13 14:42:38 +0000223 Ok(BnRemoteProvisioning::new_binder(result, BinderFeatures::default()))
Max Bires148c08e2020-10-13 13:41:41 -0700224 }
225
Max Bires48fc2e52021-11-17 10:13:04 -0800226 fn extract_payload_from_cose_mac(data: &[u8]) -> Result<Value> {
227 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
228 "In extract_payload_from_cose_mac: COSE_Mac0 returned from IRPC cannot be parsed",
229 )?;
230 if cose_mac0.len() != COSE_MAC0_LEN {
231 return Err(error::Error::sys()).context(format!(
232 "In extract_payload_from_cose_mac: COSE_Mac0 has improper length. \
233 Expected: {}, Actual: {}",
234 COSE_MAC0_LEN,
235 cose_mac0.len(),
236 ));
237 }
238 match &cose_mac0[COSE_MAC0_PAYLOAD] {
239 Value::Bytes(key) => Ok(serde_cbor::from_slice(key)
240 .context("In extract_payload_from_cose_mac: COSE_Mac0 payload is malformed.")?),
241 _ => Err(error::Error::sys()).context(
242 "In extract_payload_from_cose_mac: COSE_Mac0 payload is the wrong type.",
243 )?,
244 }
245 }
246
Max Bires148c08e2020-10-13 13:41:41 -0700247 /// Generates a CBOR blob which will be assembled by the calling code into a larger
248 /// CBOR blob intended for delivery to a provisioning serever. This blob will contain
249 /// `num_csr` certificate signing requests for attestation keys generated in the TEE,
250 /// along with a server provided `eek` and `challenge`. The endpoint encryption key will
251 /// be used to encrypt the sensitive contents being transmitted to the server, and the
252 /// challenge will ensure freshness. A `test_mode` flag will instruct the remote provisioning
253 /// HAL if it is okay to accept EEKs that aren't signed by something that chains back to the
254 /// baked in root of trust in the underlying IRemotelyProvisionedComponent instance.
Max Bires834dd362021-03-23 13:01:57 -0700255 #[allow(clippy::too_many_arguments)]
Max Bires148c08e2020-10-13 13:41:41 -0700256 pub fn generate_csr(
257 &self,
Max Biresb2e1d032021-02-08 21:35:05 -0800258 test_mode: bool,
259 num_csr: i32,
260 eek: &[u8],
261 challenge: &[u8],
262 sec_level: SecurityLevel,
263 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700264 device_info: &mut DeviceInfo,
Max Bires148c08e2020-10-13 13:41:41 -0700265 ) -> Result<Vec<u8>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800266 let dev = self.get_dev_by_sec_level(&sec_level)?;
267 let (_, _, uuid) = get_keymint_device(&sec_level)?;
268 let keys_to_sign = DB.with::<_, Result<Vec<MacedPublicKey>>>(|db| {
269 let mut db = db.borrow_mut();
270 Ok(db
271 .fetch_unsigned_attestation_keys(num_csr, &uuid)?
272 .iter()
273 .map(|key| MacedPublicKey { macedKey: key.to_vec() })
274 .collect())
275 })?;
Max Bires48fc2e52021-11-17 10:13:04 -0800276 let mac = map_rem_prov_error(dev.generateCertificateRequest(
Max Biresb2e1d032021-02-08 21:35:05 -0800277 test_mode,
278 &keys_to_sign,
279 eek,
280 challenge,
Max Bires834dd362021-03-23 13:01:57 -0700281 device_info,
Max Biresb2e1d032021-02-08 21:35:05 -0800282 protected_data,
283 ))
284 .context("In generate_csr: Failed to generate csr")?;
Max Bires48fc2e52021-11-17 10:13:04 -0800285 let mut mac_and_keys: Vec<Value> = vec![Value::from(mac)];
Max Bires97f96812021-02-23 23:44:57 -0800286 for maced_public_key in keys_to_sign {
Max Bires48fc2e52021-11-17 10:13:04 -0800287 mac_and_keys.push(
288 Self::extract_payload_from_cose_mac(&maced_public_key.macedKey)
289 .context("In generate_csr: Failed to get the payload from the COSE_Mac0")?,
290 )
Max Bires97f96812021-02-23 23:44:57 -0800291 }
Max Bires48fc2e52021-11-17 10:13:04 -0800292 let cbor_array: Value = Value::Array(mac_and_keys);
293 serde_cbor::to_vec(&cbor_array)
294 .context("In generate_csr: Failed to serialize the mac and keys array")
Max Bires148c08e2020-10-13 13:41:41 -0700295 }
296
297 /// Provisions a certificate chain for a key whose CSR was included in generate_csr. The
298 /// `public_key` is used to index into the SQL database in order to insert the `certs` blob
299 /// which represents a PEM encoded X.509 certificate chain. The `expiration_date` is provided
300 /// as a convenience from the caller to avoid having to parse the certificates semantically
301 /// here.
302 pub fn provision_cert_chain(
303 &self,
Seth Moore7ee79f92021-12-07 11:42:49 -0800304 db: &mut KeystoreDB,
Max Bires148c08e2020-10-13 13:41:41 -0700305 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800306 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700307 certs: &[u8],
308 expiration_date: i64,
309 sec_level: SecurityLevel,
310 ) -> Result<()> {
Seth Moore7ee79f92021-12-07 11:42:49 -0800311 let (_, _, uuid) = get_keymint_device(&sec_level)?;
312 db.store_signed_attestation_certificate_chain(
313 public_key,
314 batch_cert,
315 certs, /* DER encoded certificate chain */
316 expiration_date,
317 &uuid,
318 )
Max Bires148c08e2020-10-13 13:41:41 -0700319 }
320
Max Bires48fc2e52021-11-17 10:13:04 -0800321 fn parse_cose_mac0_for_coords(data: &[u8]) -> Result<Vec<u8>> {
322 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
323 "In parse_cose_mac0_for_coords: COSE_Mac0 returned from IRPC cannot be parsed",
324 )?;
325 if cose_mac0.len() != COSE_MAC0_LEN {
326 return Err(error::Error::sys()).context(format!(
327 "In parse_cose_mac0_for_coords: COSE_Mac0 has improper length. \
328 Expected: {}, Actual: {}",
329 COSE_MAC0_LEN,
330 cose_mac0.len(),
331 ));
332 }
333 let cose_key: BTreeMap<Value, Value> = match &cose_mac0[COSE_MAC0_PAYLOAD] {
334 Value::Bytes(key) => serde_cbor::from_slice(key)
335 .context("In parse_cose_mac0_for_coords: COSE_Key is malformed.")?,
336 _ => Err(error::Error::sys())
337 .context("In parse_cose_mac0_for_coords: COSE_Mac0 payload is the wrong type.")?,
338 };
339 if !cose_key.contains_key(&COSE_KEY_XCOORD) || !cose_key.contains_key(&COSE_KEY_YCOORD) {
340 return Err(error::Error::sys()).context(
341 "In parse_cose_mac0_for_coords: \
342 COSE_Key returned from IRPC is lacking required fields",
343 );
344 }
345 let mut raw_key: Vec<u8> = vec![0; 64];
346 match &cose_key[&COSE_KEY_XCOORD] {
347 Value::Bytes(x_coord) if x_coord.len() == 32 => {
348 raw_key[0..32].clone_from_slice(x_coord)
349 }
350 Value::Bytes(x_coord) => {
351 return Err(error::Error::sys()).context(format!(
352 "In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not the right length. \
353 Expected: 32; Actual: {}",
354 x_coord.len()
355 ))
356 }
357 _ => {
358 return Err(error::Error::sys())
359 .context("In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not a bstr")
360 }
361 }
362 match &cose_key[&COSE_KEY_YCOORD] {
363 Value::Bytes(y_coord) if y_coord.len() == 32 => {
364 raw_key[32..64].clone_from_slice(y_coord)
365 }
366 Value::Bytes(y_coord) => {
367 return Err(error::Error::sys()).context(format!(
368 "In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not the right length. \
369 Expected: 32; Actual: {}",
370 y_coord.len()
371 ))
372 }
373 _ => {
374 return Err(error::Error::sys())
375 .context("In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not a bstr")
376 }
377 }
378 Ok(raw_key)
379 }
380
Max Bires148c08e2020-10-13 13:41:41 -0700381 /// Submits a request to the Remote Provisioner HAL to generate a signing key pair.
382 /// `is_test_mode` indicates whether or not the returned public key should be marked as being
383 /// for testing in order to differentiate them from private keys. If the call is successful,
384 /// the key pair is then added to the database.
Seth Moore7ee79f92021-12-07 11:42:49 -0800385 pub fn generate_key_pair(
386 &self,
387 db: &mut KeystoreDB,
388 is_test_mode: bool,
389 sec_level: SecurityLevel,
390 ) -> Result<()> {
Max Biresb2e1d032021-02-08 21:35:05 -0800391 let (_, _, uuid) = get_keymint_device(&sec_level)?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800392 let dev = self.get_dev_by_sec_level(&sec_level).context(format!(
393 "In generate_key_pair: Failed to get device for security level {:?}",
394 sec_level
395 ))?;
Max Biresb2e1d032021-02-08 21:35:05 -0800396 let mut maced_key = MacedPublicKey { macedKey: Vec::new() };
397 let priv_key =
398 map_rem_prov_error(dev.generateEcdsaP256KeyPair(is_test_mode, &mut maced_key))
399 .context("In generate_key_pair: Failed to generated ECDSA keypair.")?;
Max Bires48fc2e52021-11-17 10:13:04 -0800400 let raw_key = Self::parse_cose_mac0_for_coords(&maced_key.macedKey)
401 .context("In generate_key_pair: Failed to parse raw key")?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800402 db.create_attestation_key_entry(&maced_key.macedKey, &raw_key, &priv_key, &uuid)
403 .context("In generate_key_pair: Failed to insert attestation key entry")
Max Biresb2e1d032021-02-08 21:35:05 -0800404 }
405
406 /// Checks the security level of each available IRemotelyProvisionedComponent hal and returns
407 /// all levels in an array to the caller.
Max Biresd2ce46b2021-07-06 02:54:47 -0700408 pub fn get_implementation_info(&self) -> Result<Vec<ImplInfo>> {
409 Ok(self
410 .curve_by_sec_level
411 .iter()
412 .map(|(sec_level, curve)| ImplInfo { secLevel: *sec_level, supportedCurve: *curve })
413 .collect())
Max Bires148c08e2020-10-13 13:41:41 -0700414 }
Max Bires60d7ed12021-03-05 15:59:22 -0800415
416 /// Deletes all attestation keys generated by the IRemotelyProvisionedComponent from the device,
417 /// regardless of what state of the attestation key lifecycle they were in.
418 pub fn delete_all_keys(&self) -> Result<i64> {
419 DB.with::<_, Result<i64>>(|db| {
420 let mut db = db.borrow_mut();
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700421 db.delete_all_attestation_keys()
Max Bires60d7ed12021-03-05 15:59:22 -0800422 })
423 }
Seth Moore7ee79f92021-12-07 11:42:49 -0800424
425 /// Fetches a remotely provisioned certificate chain and key for the given client uid that
426 /// was provisioned using the IRemotelyProvisionedComponent with the given id. The same key
427 /// will be returned for a given caller_uid on every request. If there are no attestation keys
428 /// available, `OUT_OF_KEYS` is returned.
429 fn get_attestation_key(
430 &self,
431 db: &mut KeystoreDB,
432 caller_uid: i32,
433 irpc_id: &str,
434 ) -> Result<RemotelyProvisionedKey> {
435 log::info!("get_attestation_key(self, {}, {}", caller_uid, irpc_id);
436
437 let (sec_level, _) = self.get_dev_by_unique_id(irpc_id)?;
438 let (_, _, km_uuid) = get_keymint_device(&sec_level)?;
439
440 let cert_chain = get_rem_prov_attest_key(Domain::APP, caller_uid as u32, db, &km_uuid)
441 .context("In get_attestation_key")?;
442 match cert_chain {
443 Some(chain) => Ok(RemotelyProvisionedKey {
444 keyBlob: chain.private_key.to_vec(),
445 encodedCertChain: chain.cert_chain,
446 }),
447 // It should be impossible to get `None`, but handle it just in case as a
448 // precaution against future behavioral changes in `get_rem_prov_attest_key`.
449 None => Err(error::Error::Rc(ResponseCode::OUT_OF_KEYS))
450 .context("In get_attestation_key: No available attestation keys"),
451 }
452 }
Max Bires148c08e2020-10-13 13:41:41 -0700453}
454
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000455/// Populates the AttestationPoolStatus parcelable with information about how many
456/// certs will be expiring by the date provided in `expired_by` along with how many
457/// keys have not yet been assigned.
458pub fn get_pool_status(expired_by: i64, sec_level: SecurityLevel) -> Result<AttestationPoolStatus> {
459 let (_, _, uuid) = get_keymint_device(&sec_level)?;
460 DB.with::<_, Result<AttestationPoolStatus>>(|db| {
461 let mut db = db.borrow_mut();
462 // delete_expired_attestation_keys is always safe to call, and will remove anything
463 // older than the date at the time of calling. No work should be done on the
464 // attestation keys unless the pool status is checked first, so this call should be
465 // enough to routinely clean out expired keys.
466 db.delete_expired_attestation_keys()?;
467 db.get_attestation_pool_status(expired_by, &uuid)
468 })
469}
470
Seth Moore7ee79f92021-12-07 11:42:49 -0800471/// Fetches a remote provisioning attestation key and certificate chain inside of the
472/// returned `CertificateChain` struct if one exists for the given caller_uid. If one has not
473/// been assigned, this function will assign it. If there are no signed attestation keys
474/// available to be assigned, it will return the ResponseCode `OUT_OF_KEYS`
475fn get_rem_prov_attest_key(
476 domain: Domain,
477 caller_uid: u32,
478 db: &mut KeystoreDB,
479 km_uuid: &Uuid,
480) -> Result<Option<CertificateChain>> {
481 match domain {
482 Domain::APP => {
483 // Attempt to get an Attestation Key once. If it fails, then the app doesn't
484 // have a valid chain assigned to it. The helper function will return None after
485 // attempting to assign a key. An error will be thrown if the pool is simply out
486 // of usable keys. Then another attempt to fetch the just-assigned key will be
487 // made. If this fails too, something is very wrong.
488 get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid)
489 .context("In get_rem_prov_attest_key: Failed to get a key")?
490 .map_or_else(
491 || get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid),
492 |v| Ok(Some(v)),
493 )
494 .context(concat!(
495 "In get_rem_prov_attest_key: Failed to get a key after",
496 "attempting to assign one."
497 ))?
498 .map_or_else(
499 || {
500 Err(Error::sys()).context(concat!(
501 "In get_rem_prov_attest_key: Attempted to assign a ",
502 "key and failed silently. Something is very wrong."
503 ))
504 },
505 |cert_chain| Ok(Some(cert_chain)),
506 )
507 }
508 _ => Ok(None),
509 }
510}
511
512/// Returns None if an AttestationKey fails to be assigned. Errors if no keys are available.
513fn get_rem_prov_attest_key_helper(
514 domain: Domain,
515 caller_uid: u32,
516 db: &mut KeystoreDB,
517 km_uuid: &Uuid,
518) -> Result<Option<CertificateChain>> {
519 let cert_chain = db
520 .retrieve_attestation_key_and_cert_chain(domain, caller_uid as i64, km_uuid)
521 .context("In get_rem_prov_attest_key_helper: Failed to retrieve a key + cert chain")?;
522 match cert_chain {
523 Some(cert_chain) => Ok(Some(cert_chain)),
524 // Either this app needs to be assigned a key, or the pool is empty. An error will
525 // be thrown if there is no key available to assign. This will indicate that the app
526 // should be nudged to provision more keys so keystore can retry.
527 None => {
528 db.assign_attestation_key(domain, caller_uid as i64, km_uuid)
529 .context("In get_rem_prov_attest_key_helper: Failed to assign a key")?;
530 Ok(None)
531 }
532 }
533}
534
Max Bires148c08e2020-10-13 13:41:41 -0700535impl binder::Interface for RemoteProvisioningService {}
536
537// Implementation of IRemoteProvisioning. See AIDL spec at
538// :aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
539impl IRemoteProvisioning for RemoteProvisioningService {
540 fn getPoolStatus(
541 &self,
542 expired_by: i64,
543 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700544 ) -> binder::Result<AttestationPoolStatus> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000545 let _wp = wd::watch_millis("IRemoteProvisioning::getPoolStatus", 500);
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000546 map_or_log_err(get_pool_status(expired_by, sec_level), Ok)
Max Bires148c08e2020-10-13 13:41:41 -0700547 }
548
549 fn generateCsr(
550 &self,
551 test_mode: bool,
552 num_csr: i32,
553 eek: &[u8],
554 challenge: &[u8],
555 sec_level: SecurityLevel,
Max Biresb2e1d032021-02-08 21:35:05 -0800556 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700557 device_info: &mut DeviceInfo,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700558 ) -> binder::Result<Vec<u8>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000559 let _wp = wd::watch_millis("IRemoteProvisioning::generateCsr", 500);
Max Biresb2e1d032021-02-08 21:35:05 -0800560 map_or_log_err(
Max Bires834dd362021-03-23 13:01:57 -0700561 self.generate_csr(
562 test_mode,
563 num_csr,
564 eek,
565 challenge,
566 sec_level,
567 protected_data,
568 device_info,
569 ),
Max Biresb2e1d032021-02-08 21:35:05 -0800570 Ok,
571 )
Max Bires148c08e2020-10-13 13:41:41 -0700572 }
573
574 fn provisionCertChain(
575 &self,
576 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800577 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700578 certs: &[u8],
579 expiration_date: i64,
580 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700581 ) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000582 let _wp = wd::watch_millis("IRemoteProvisioning::provisionCertChain", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800583 DB.with::<_, binder::Result<()>>(|db| {
584 map_or_log_err(
585 self.provision_cert_chain(
586 &mut db.borrow_mut(),
587 public_key,
588 batch_cert,
589 certs,
590 expiration_date,
591 sec_level,
592 ),
593 Ok,
594 )
595 })
Max Bires148c08e2020-10-13 13:41:41 -0700596 }
597
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700598 fn generateKeyPair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000599 let _wp = wd::watch_millis("IRemoteProvisioning::generateKeyPair", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800600 DB.with::<_, binder::Result<()>>(|db| {
601 map_or_log_err(
602 self.generate_key_pair(&mut db.borrow_mut(), is_test_mode, sec_level),
603 Ok,
604 )
605 })
Max Bires148c08e2020-10-13 13:41:41 -0700606 }
Max Biresb2e1d032021-02-08 21:35:05 -0800607
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700608 fn getImplementationInfo(&self) -> binder::Result<Vec<ImplInfo>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000609 let _wp = wd::watch_millis("IRemoteProvisioning::getSecurityLevels", 500);
Max Biresd2ce46b2021-07-06 02:54:47 -0700610 map_or_log_err(self.get_implementation_info(), Ok)
Max Biresb2e1d032021-02-08 21:35:05 -0800611 }
Max Bires60d7ed12021-03-05 15:59:22 -0800612
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700613 fn deleteAllKeys(&self) -> binder::Result<i64> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000614 let _wp = wd::watch_millis("IRemoteProvisioning::deleteAllKeys", 500);
Max Bires60d7ed12021-03-05 15:59:22 -0800615 map_or_log_err(self.delete_all_keys(), Ok)
616 }
Max Bires148c08e2020-10-13 13:41:41 -0700617}
Max Bires48fc2e52021-11-17 10:13:04 -0800618
Seth Moore7ee79f92021-12-07 11:42:49 -0800619// Implementation of IRemotelyProvisionedKeyPool. See AIDL spec at
620// :aidl/android/security/remoteprovisioning/IRemotelyProvisionedKeyPool.aidl
621impl IRemotelyProvisionedKeyPool for RemoteProvisioningService {
622 fn getAttestationKey(
623 &self,
624 caller_uid: i32,
625 irpc_id: &str,
626 ) -> binder::Result<RemotelyProvisionedKey> {
627 let _wp = wd::watch_millis("IRemotelyProvisionedKeyPool::getAttestationKey", 500);
628 map_or_log_err(check_keystore_permission(KeystorePerm::GetAttestationKey), Ok)?;
629 DB.with::<_, binder::Result<RemotelyProvisionedKey>>(|db| {
630 map_or_log_err(self.get_attestation_key(&mut db.borrow_mut(), caller_uid, irpc_id), Ok)
631 })
632 }
633}
634
Max Bires48fc2e52021-11-17 10:13:04 -0800635#[cfg(test)]
636mod tests {
637 use super::*;
638 use serde_cbor::Value;
639 use std::collections::BTreeMap;
Seth Moore7ee79f92021-12-07 11:42:49 -0800640 use std::sync::{Arc, Mutex};
641 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
642 RpcHardwareInfo::RpcHardwareInfo,
643 };
644
645 #[derive(Default)]
646 struct MockRemotelyProvisionedComponentValues {
647 hw_info: RpcHardwareInfo,
648 private_key: Vec<u8>,
649 maced_public_key: Vec<u8>,
650 }
651
652 // binder::Interface requires the Send trait, so we have to use a Mutex even though the test
653 // is single threaded.
654 #[derive(Default)]
655 struct MockRemotelyProvisionedComponent(Arc<Mutex<MockRemotelyProvisionedComponentValues>>);
656
657 impl binder::Interface for MockRemotelyProvisionedComponent {}
658
659 impl IRemotelyProvisionedComponent for MockRemotelyProvisionedComponent {
660 fn getHardwareInfo(&self) -> binder::Result<RpcHardwareInfo> {
661 Ok(self.0.lock().unwrap().hw_info.clone())
662 }
663
664 fn generateEcdsaP256KeyPair(
665 &self,
666 test_mode: bool,
667 maced_public_key: &mut MacedPublicKey,
668 ) -> binder::Result<Vec<u8>> {
669 assert!(test_mode);
670 maced_public_key.macedKey = self.0.lock().unwrap().maced_public_key.clone();
671 Ok(self.0.lock().unwrap().private_key.clone())
672 }
673
674 fn generateCertificateRequest(
675 &self,
676 _test_mode: bool,
677 _keys_to_sign: &[MacedPublicKey],
678 _eek: &[u8],
679 _challenge: &[u8],
680 _device_info: &mut DeviceInfo,
681 _protected_data: &mut ProtectedData,
682 ) -> binder::Result<Vec<u8>> {
683 Err(binder::StatusCode::INVALID_OPERATION.into())
684 }
685 }
686
687 // Hard coded cert that can be parsed -- the content doesn't matter for testing, only that it's valid.
688 fn get_fake_cert() -> Vec<u8> {
689 vec![
690 0x30, 0x82, 0x01, 0xbb, 0x30, 0x82, 0x01, 0x61, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
691 0x14, 0x3a, 0xd5, 0x67, 0xce, 0xfe, 0x93, 0xe1, 0xea, 0xb7, 0xe4, 0xbf, 0x64, 0x19,
692 0xa4, 0x11, 0xe1, 0x87, 0x40, 0x20, 0x37, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
693 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
694 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
695 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
696 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
697 0x6c, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x32, 0x31, 0x30, 0x32, 0x32,
698 0x30, 0x38, 0x35, 0x32, 0x5a, 0x17, 0x0d, 0x34, 0x39, 0x30, 0x34, 0x32, 0x36, 0x32,
699 0x32, 0x30, 0x38, 0x35, 0x32, 0x5a, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
700 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
701 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
702 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f,
703 0x67, 0x6c, 0x65, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
704 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42,
705 0x00, 0x04, 0x1e, 0xac, 0x0c, 0xe0, 0x0d, 0xc5, 0x25, 0x84, 0x1b, 0xd2, 0x77, 0x2d,
706 0xe7, 0xba, 0xf1, 0xde, 0xa7, 0xf6, 0x39, 0x7f, 0x38, 0x91, 0xbf, 0xa4, 0x58, 0xf5,
707 0x62, 0x6b, 0xce, 0x06, 0xcf, 0xb9, 0x73, 0x91, 0x0d, 0x8a, 0x60, 0xa0, 0xc6, 0xa2,
708 0x22, 0xe6, 0x51, 0x2e, 0x58, 0xd6, 0x43, 0x02, 0x80, 0x43, 0x44, 0x29, 0x38, 0x9a,
709 0x99, 0xf3, 0xa4, 0xdd, 0xd0, 0xb4, 0x6f, 0x8b, 0x44, 0x2d, 0xa3, 0x53, 0x30, 0x51,
710 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xdb, 0x13, 0x68,
711 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe, 0x42, 0x3c, 0xd9, 0x3f, 0x1a,
712 0x33, 0xe9, 0xaa, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
713 0x80, 0x14, 0xdb, 0x13, 0x68, 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe,
714 0x42, 0x3c, 0xd9, 0x3f, 0x1a, 0x33, 0xe9, 0xaa, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
715 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06,
716 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45,
717 0x02, 0x20, 0x10, 0xdf, 0x40, 0xc3, 0x20, 0x54, 0x36, 0xb5, 0xc9, 0x3c, 0x70, 0xe3,
718 0x55, 0x37, 0xd2, 0x04, 0x51, 0xeb, 0x0f, 0x18, 0x83, 0xd0, 0x58, 0xa1, 0x08, 0x77,
719 0x8d, 0x4d, 0xa4, 0x20, 0xee, 0x33, 0x02, 0x21, 0x00, 0x8d, 0xe3, 0xa6, 0x6c, 0x0d,
720 0x86, 0x25, 0xdc, 0x59, 0x0d, 0x21, 0x43, 0x22, 0x3a, 0xb9, 0xa1, 0x73, 0x28, 0xc9,
721 0x16, 0x9e, 0x91, 0x15, 0xc4, 0xc3, 0xd7, 0xeb, 0xe5, 0xce, 0xdc, 0x1c, 0x1b,
722 ]
723 }
724
725 // Generate a fake COSE_Mac0 with a key that's just `byte` repeated
726 fn generate_maced_pubkey(byte: u8) -> Vec<u8> {
727 vec![
728 0x84, 0x43, 0xA1, 0x01, 0x05, 0xA0, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20,
729 0x01, 0x21, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
730 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
731 byte, byte, byte, byte, byte, byte, byte, byte, 0x22, 0x58, 0x20, byte, byte, byte,
732 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
733 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
734 byte, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
735 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
736 byte, byte, byte, byte, byte, byte, byte,
737 ]
738 }
Max Bires48fc2e52021-11-17 10:13:04 -0800739
740 #[test]
741 fn test_parse_cose_mac0_for_coords_raw_bytes() -> Result<()> {
742 let cose_mac0: Vec<u8> = vec![
743 0x84, 0x01, 0x02, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
744 0x20, 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9,
745 0x21, 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C,
746 0x43, 0x22, 0xC8, 0xEE, 0x03, 0x22, 0x58, 0x20, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95,
747 0x90, 0xA7, 0x5C, 0x5A, 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A,
748 0xA3, 0xB3, 0x1A, 0xB4, 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC, 0x03,
749 ];
750 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&cose_mac0)?;
751 assert_eq!(
752 raw_key,
753 vec![
754 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9, 0x21,
755 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C, 0x43,
756 0x22, 0xC8, 0xEE, 0x03, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95, 0x90, 0xA7, 0x5C, 0x5A,
757 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A, 0xA3, 0xB3, 0x1A, 0xB4,
758 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC,
759 ]
760 );
761 Ok(())
762 }
763
764 #[test]
765 fn test_parse_cose_mac0_for_coords_constructed_mac() -> Result<()> {
766 let x_coord: Vec<u8> = vec![0; 32];
767 let y_coord: Vec<u8> = vec![1; 32];
768 let mut expected_key: Vec<u8> = Vec::new();
769 expected_key.extend(&x_coord);
770 expected_key.extend(&y_coord);
771 let key_map: BTreeMap<Value, Value> = BTreeMap::from([
772 (Value::Integer(1), Value::Integer(2)),
773 (Value::Integer(3), Value::Integer(-7)),
774 (Value::Integer(-1), Value::Integer(1)),
775 (Value::Integer(-2), Value::Bytes(x_coord)),
776 (Value::Integer(-3), Value::Bytes(y_coord)),
777 ]);
778 let cose_mac0: Vec<Value> = vec![
779 Value::Integer(0),
780 Value::Integer(1),
781 Value::from(serde_cbor::to_vec(&key_map)?),
782 Value::Integer(2),
783 ];
784 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&serde_cbor::to_vec(
785 &Value::from(cose_mac0),
786 )?)?;
787 assert_eq!(expected_key, raw_key);
788 Ok(())
789 }
790
791 #[test]
792 fn test_extract_payload_from_cose_mac() -> Result<()> {
793 let key_map = Value::Map(BTreeMap::from([(Value::Integer(1), Value::Integer(2))]));
794 let payload = Value::Bytes(serde_cbor::to_vec(&key_map)?);
795 let cose_mac0 =
796 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
797 let extracted_map = RemoteProvisioningService::extract_payload_from_cose_mac(
798 &serde_cbor::to_vec(&cose_mac0)?,
799 )?;
800 assert_eq!(key_map, extracted_map);
801 Ok(())
802 }
803
804 #[test]
805 fn test_extract_payload_from_cose_mac_fails_malformed_payload() -> Result<()> {
806 let payload = Value::Bytes(vec![5; 10]);
807 let cose_mac0 =
808 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
809 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
810 &serde_cbor::to_vec(&cose_mac0)?,
811 );
812 assert!(extracted_payload.is_err());
813 Ok(())
814 }
815
816 #[test]
817 fn test_extract_payload_from_cose_mac_fails_type() -> Result<()> {
818 let payload = Value::Integer(1);
819 let cose_mac0 =
820 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
821 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
822 &serde_cbor::to_vec(&cose_mac0)?,
823 );
824 assert!(extracted_payload.is_err());
825 Ok(())
826 }
827
828 #[test]
829 fn test_extract_payload_from_cose_mac_fails_length() -> Result<()> {
830 let cose_mac0 = Value::Array(vec![Value::Integer(0), Value::Integer(1)]);
831 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
832 &serde_cbor::to_vec(&cose_mac0)?,
833 );
834 assert!(extracted_payload.is_err());
835 Ok(())
836 }
Seth Moore7ee79f92021-12-07 11:42:49 -0800837
838 #[test]
839 #[ignore] // b/215746308
840 fn test_get_attestation_key_no_keys_provisioned() {
841 let mut db = crate::database::tests::new_test_db().unwrap();
842 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
843 mock_rpc.0.lock().unwrap().hw_info.uniqueId = Some(String::from("mallory"));
844
845 let mut service: RemoteProvisioningService = Default::default();
846 service
847 .device_by_sec_level
848 .insert(SecurityLevel::TRUSTED_ENVIRONMENT, Strong::new(mock_rpc));
849
850 assert_eq!(
851 service
852 .get_attestation_key(&mut db, 0, "mallory")
853 .unwrap_err()
854 .downcast::<error::Error>()
855 .unwrap(),
856 error::Error::Rc(ResponseCode::OUT_OF_KEYS)
857 );
858 }
859
860 #[test]
861 #[ignore] // b/215746308
862 fn test_get_attestation_key() {
863 let mut db = crate::database::tests::new_test_db().unwrap();
864 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
865 let irpc_id = "paul";
866 let caller_uid = 0;
867
868 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
869 let mock_values = mock_rpc.0.clone();
870 let mut service: RemoteProvisioningService = Default::default();
871 service.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
872
873 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
874 mock_values.lock().unwrap().private_key = vec![8, 6, 7, 5, 3, 0, 9];
875 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
876 service.generate_key_pair(&mut db, true, sec_level).unwrap();
877
878 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
879 mock_values.lock().unwrap().maced_public_key.as_slice(),
880 )
881 .unwrap();
882 let batch_cert = get_fake_cert();
883 let certs = &[5, 6, 7, 8];
884 assert!(service
885 .provision_cert_chain(
886 &mut db,
887 public_key.as_slice(),
888 batch_cert.as_slice(),
889 certs,
890 0,
891 sec_level
892 )
893 .is_ok());
894
895 // ensure we got the key we expected
896 let first_key = service
897 .get_attestation_key(&mut db, caller_uid, irpc_id)
898 .context("get first key")
899 .unwrap();
900 assert_eq!(first_key.keyBlob, mock_values.lock().unwrap().private_key);
901 assert_eq!(first_key.encodedCertChain, certs);
902
903 // ensure that multiple calls get the same key
904 assert_eq!(
905 first_key,
906 service
907 .get_attestation_key(&mut db, caller_uid, irpc_id)
908 .context("get second key")
909 .unwrap()
910 );
911
912 // no more keys for new clients
913 assert_eq!(
914 service
915 .get_attestation_key(&mut db, caller_uid + 1, irpc_id)
916 .unwrap_err()
917 .downcast::<error::Error>()
918 .unwrap(),
919 error::Error::Rc(ResponseCode::OUT_OF_KEYS)
920 );
921 }
922
923 #[test]
924 #[ignore] // b/215746308
925 fn test_get_attestation_key_gets_different_key_for_different_client() {
926 let mut db = crate::database::tests::new_test_db().unwrap();
927 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
928 let irpc_id = "ringo";
929 let first_caller = 0;
930 let second_caller = first_caller + 1;
931
932 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
933 let mock_values = mock_rpc.0.clone();
934 let mut service: RemoteProvisioningService = Default::default();
935 service.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
936
937 // generate two distinct keys and provision them with certs
938 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
939 mock_values.lock().unwrap().private_key = vec![3, 1, 4, 1, 5];
940 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
941 assert!(service.generate_key_pair(&mut db, true, sec_level).is_ok());
942 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
943 mock_values.lock().unwrap().maced_public_key.as_slice(),
944 )
945 .unwrap();
946 assert!(service
947 .provision_cert_chain(
948 &mut db,
949 public_key.as_slice(),
950 get_fake_cert().as_slice(),
951 &[1],
952 0,
953 sec_level
954 )
955 .is_ok());
956
957 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
958 mock_values.lock().unwrap().private_key = vec![9, 0, 2, 1, 0];
959 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x22);
960 assert!(service.generate_key_pair(&mut db, true, sec_level).is_ok());
961 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
962 mock_values.lock().unwrap().maced_public_key.as_slice(),
963 )
964 .unwrap();
965 assert!(service
966 .provision_cert_chain(
967 &mut db,
968 public_key.as_slice(),
969 get_fake_cert().as_slice(),
970 &[2],
971 0,
972 sec_level
973 )
974 .is_ok());
975
976 // make sure each caller gets a distinct key
977 assert_ne!(
978 service
979 .get_attestation_key(&mut db, first_caller, irpc_id)
980 .context("get first key")
981 .unwrap(),
982 service
983 .get_attestation_key(&mut db, second_caller, irpc_id)
984 .context("get second key")
985 .unwrap()
986 );
987
988 // repeated calls should return the same key for a given caller
989 assert_eq!(
990 service
991 .get_attestation_key(&mut db, first_caller, irpc_id)
992 .context("first caller a")
993 .unwrap(),
994 service
995 .get_attestation_key(&mut db, first_caller, irpc_id)
996 .context("first caller b")
997 .unwrap(),
998 );
999
1000 assert_eq!(
1001 service
1002 .get_attestation_key(&mut db, second_caller, irpc_id)
1003 .context("second caller a")
1004 .unwrap(),
1005 service
1006 .get_attestation_key(&mut db, second_caller, irpc_id)
1007 .context("second caller b")
1008 .unwrap()
1009 );
1010 }
Max Bires48fc2e52021-11-17 10:13:04 -08001011}