blob: be23ae5bb798c8414016053e38e1177b4246b7bd [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,
Seth Moore92648b62022-02-02 13:26:18 -080034 IRemotelyProvisionedKeyPool::BnRemotelyProvisionedKeyPool,
Seth Moore7ee79f92021-12-07 11:42:49 -080035 IRemotelyProvisionedKeyPool::IRemotelyProvisionedKeyPool, ImplInfo::ImplInfo,
36 RemotelyProvisionedKey::RemotelyProvisionedKey,
Max Bires148c08e2020-10-13 13:41:41 -070037};
Andrew Walbrande45c8b2021-04-13 14:42:38 +000038use android_security_remoteprovisioning::binder::{BinderFeatures, Strong};
Max Bires97f96812021-02-23 23:44:57 -080039use android_system_keystore2::aidl::android::system::keystore2::{
Seth Moore7ee79f92021-12-07 11:42:49 -080040 Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
Max Bires97f96812021-02-23 23:44:57 -080041};
Max Biresb2e1d032021-02-08 21:35:05 -080042use anyhow::{Context, Result};
Max Bires97f96812021-02-23 23:44:57 -080043use keystore2_crypto::parse_subject_from_certificate;
Max Bires48fc2e52021-11-17 10:13:04 -080044use serde_cbor::Value;
45use std::collections::BTreeMap;
Max Bires97f96812021-02-23 23:44:57 -080046use std::sync::atomic::{AtomicBool, Ordering};
Max Bires148c08e2020-10-13 13:41:41 -070047
Max Bires55620ff2022-02-11 13:34:15 -080048use crate::database::{CertificateChain, KeyIdGuard, KeystoreDB, Uuid};
Max Bires97f96812021-02-23 23:44:57 -080049use crate::error::{self, map_or_log_err, map_rem_prov_error, Error};
Max Biresb2e1d032021-02-08 21:35:05 -080050use crate::globals::{get_keymint_device, get_remotely_provisioned_component, DB};
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000051use crate::metrics_store::log_rkp_error_stats;
Seth Moore7ee79f92021-12-07 11:42:49 -080052use crate::permission::KeystorePerm;
53use crate::utils::{check_keystore_permission, watchdog as wd};
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000054use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
Max Bires148c08e2020-10-13 13:41:41 -070055
Max Bires97f96812021-02-23 23:44:57 -080056/// Contains helper functions to check if remote provisioning is enabled on the system and, if so,
57/// to assign and retrieve attestation keys and certificate chains.
58#[derive(Default)]
59pub struct RemProvState {
60 security_level: SecurityLevel,
61 km_uuid: Uuid,
62 is_hal_present: AtomicBool,
63}
64
Max Bires48fc2e52021-11-17 10:13:04 -080065static COSE_KEY_XCOORD: Value = Value::Integer(-2);
66static COSE_KEY_YCOORD: Value = Value::Integer(-3);
67static COSE_MAC0_LEN: usize = 4;
68static COSE_MAC0_PAYLOAD: usize = 2;
69
Max Bires97f96812021-02-23 23:44:57 -080070impl RemProvState {
71 /// Creates a RemProvState struct.
72 pub fn new(security_level: SecurityLevel, km_uuid: Uuid) -> Self {
73 Self { security_level, km_uuid, is_hal_present: AtomicBool::new(true) }
74 }
75
Max Bires55620ff2022-02-11 13:34:15 -080076 /// Returns the uuid for the KM instance attached to this RemProvState struct.
77 pub fn get_uuid(&self) -> Uuid {
78 self.km_uuid
79 }
80
Max Bires97f96812021-02-23 23:44:57 -080081 /// Checks if remote provisioning is enabled and partially caches the result. On a hybrid system
82 /// remote provisioning can flip from being disabled to enabled depending on responses from the
83 /// server, so unfortunately caching the presence or absence of the HAL is not enough to fully
84 /// make decisions about the state of remote provisioning during runtime.
85 fn check_rem_prov_enabled(&self, db: &mut KeystoreDB) -> Result<bool> {
86 if !self.is_hal_present.load(Ordering::Relaxed)
87 || get_remotely_provisioned_component(&self.security_level).is_err()
88 {
89 self.is_hal_present.store(false, Ordering::Relaxed);
90 return Ok(false);
91 }
92 // To check if remote provisioning is enabled on a system that supports both remote
93 // provisioning and factory provisioned keys, we only need to check if there are any
94 // keys at all generated to indicate if the app has gotten the signal to begin filling
95 // the key pool from the server.
96 let pool_status = db
97 .get_attestation_pool_status(0 /* date */, &self.km_uuid)
98 .context("In check_rem_prov_enabled: failed to get attestation pool status.")?;
99 Ok(pool_status.total != 0)
100 }
101
Max Bires97f96812021-02-23 23:44:57 -0800102 fn is_asymmetric_key(&self, params: &[KeyParameter]) -> bool {
103 params.iter().any(|kp| {
104 matches!(
105 kp,
106 KeyParameter {
107 tag: Tag::ALGORITHM,
108 value: KeyParameterValue::Algorithm(Algorithm::RSA)
109 } | KeyParameter {
110 tag: Tag::ALGORITHM,
111 value: KeyParameterValue::Algorithm(Algorithm::EC)
112 }
113 )
114 })
115 }
116
117 /// Checks to see (1) if the key in question should be attested to based on the algorithm and
118 /// (2) if remote provisioning is present and enabled on the system. If these conditions are
119 /// met, it makes an attempt to fetch the attestation key assigned to the `caller_uid`.
120 ///
121 /// It returns the ResponseCode `OUT_OF_KEYS` if there is not one key currently assigned to the
122 /// `caller_uid` and there are none available to assign.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700123 pub fn get_remotely_provisioned_attestation_key_and_certs(
Max Bires97f96812021-02-23 23:44:57 -0800124 &self,
125 key: &KeyDescriptor,
126 caller_uid: u32,
127 params: &[KeyParameter],
128 db: &mut KeystoreDB,
Max Bires55620ff2022-02-11 13:34:15 -0800129 ) -> Result<Option<(KeyIdGuard, AttestationKey, Certificate)>> {
Max Bires97f96812021-02-23 23:44:57 -0800130 if !self.is_asymmetric_key(params) || !self.check_rem_prov_enabled(db)? {
131 // There is no remote provisioning component for this security level on the
132 // device. Return None so the underlying KM instance knows to use its
133 // factory provisioned key instead. Alternatively, it's not an asymmetric key
134 // and therefore will not be attested.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700135 Ok(None)
Max Bires97f96812021-02-23 23:44:57 -0800136 } else {
Seth Moore7ee79f92021-12-07 11:42:49 -0800137 match get_rem_prov_attest_key(key.domain, caller_uid, db, &self.km_uuid) {
Max Bires31cdfb82021-07-06 02:59:25 -0700138 Err(e) => {
139 log::error!(
140 concat!(
141 "In get_remote_provisioning_key_and_certs: Failed to get ",
142 "attestation key. {:?}"
143 ),
144 e
145 );
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +0000146 log_rkp_error_stats(MetricsRkpError::FALL_BACK_DURING_HYBRID);
Max Bires31cdfb82021-07-06 02:59:25 -0700147 Ok(None)
148 }
149 Ok(v) => match v {
Max Bires55620ff2022-02-11 13:34:15 -0800150 Some((guard, cert_chain)) => Ok(Some((
151 guard,
Max Bires31cdfb82021-07-06 02:59:25 -0700152 AttestationKey {
153 keyBlob: cert_chain.private_key.to_vec(),
154 attestKeyParams: vec![],
155 issuerSubjectName: parse_subject_from_certificate(
156 &cert_chain.batch_cert,
157 )
Max Bires97f96812021-02-23 23:44:57 -0800158 .context(concat!(
Max Bires31cdfb82021-07-06 02:59:25 -0700159 "In get_remote_provisioning_key_and_certs: Failed to ",
160 "parse subject."
161 ))?,
162 },
163 Certificate { encodedCertificate: cert_chain.cert_chain },
164 ))),
165 None => Ok(None),
166 },
Max Bires97f96812021-02-23 23:44:57 -0800167 }
168 }
169 }
170}
Max Bires148c08e2020-10-13 13:41:41 -0700171/// Implementation of the IRemoteProvisioning service.
Max Biresb2e1d032021-02-08 21:35:05 -0800172#[derive(Default)]
Max Bires148c08e2020-10-13 13:41:41 -0700173pub struct RemoteProvisioningService {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -0700174 device_by_sec_level: HashMap<SecurityLevel, Strong<dyn IRemotelyProvisionedComponent>>,
Max Biresd2ce46b2021-07-06 02:54:47 -0700175 curve_by_sec_level: HashMap<SecurityLevel, i32>,
Max Bires148c08e2020-10-13 13:41:41 -0700176}
177
178impl RemoteProvisioningService {
Max Biresb2e1d032021-02-08 21:35:05 -0800179 fn get_dev_by_sec_level(
180 &self,
181 sec_level: &SecurityLevel,
Seth Moore7ee79f92021-12-07 11:42:49 -0800182 ) -> Result<&dyn IRemotelyProvisionedComponent> {
Max Biresb2e1d032021-02-08 21:35:05 -0800183 if let Some(dev) = self.device_by_sec_level.get(sec_level) {
Seth Moore7ee79f92021-12-07 11:42:49 -0800184 Ok(dev.as_ref())
Max Biresb2e1d032021-02-08 21:35:05 -0800185 } else {
186 Err(error::Error::sys()).context(concat!(
187 "In get_dev_by_sec_level: Remote instance for requested security level",
188 " not found."
189 ))
190 }
191 }
192
Max Bires148c08e2020-10-13 13:41:41 -0700193 /// Creates a new instance of the remote provisioning service
Stephen Crane221bbb52020-12-16 15:52:10 -0800194 pub fn new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800195 let mut result: Self = Default::default();
196 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
197 .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
Max Biresd2ce46b2021-07-06 02:54:47 -0700198 result.curve_by_sec_level.insert(
199 SecurityLevel::TRUSTED_ENVIRONMENT,
200 dev.getHardwareInfo()
201 .context("In new_native_binder: Failed to get hardware info for the TEE.")?
202 .supportedEekCurve,
203 );
Max Biresb2e1d032021-02-08 21:35:05 -0800204 result.device_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, dev);
205 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
Max Biresd2ce46b2021-07-06 02:54:47 -0700206 result.curve_by_sec_level.insert(
207 SecurityLevel::STRONGBOX,
208 dev.getHardwareInfo()
209 .context("In new_native_binder: Failed to get hardware info for StrongBox.")?
210 .supportedEekCurve,
211 );
Max Biresb2e1d032021-02-08 21:35:05 -0800212 result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
213 }
Andrew Walbrande45c8b2021-04-13 14:42:38 +0000214 Ok(BnRemoteProvisioning::new_binder(result, BinderFeatures::default()))
Max Bires148c08e2020-10-13 13:41:41 -0700215 }
216
Max Bires48fc2e52021-11-17 10:13:04 -0800217 fn extract_payload_from_cose_mac(data: &[u8]) -> Result<Value> {
218 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
219 "In extract_payload_from_cose_mac: COSE_Mac0 returned from IRPC cannot be parsed",
220 )?;
221 if cose_mac0.len() != COSE_MAC0_LEN {
222 return Err(error::Error::sys()).context(format!(
223 "In extract_payload_from_cose_mac: COSE_Mac0 has improper length. \
224 Expected: {}, Actual: {}",
225 COSE_MAC0_LEN,
226 cose_mac0.len(),
227 ));
228 }
229 match &cose_mac0[COSE_MAC0_PAYLOAD] {
230 Value::Bytes(key) => Ok(serde_cbor::from_slice(key)
231 .context("In extract_payload_from_cose_mac: COSE_Mac0 payload is malformed.")?),
232 _ => Err(error::Error::sys()).context(
233 "In extract_payload_from_cose_mac: COSE_Mac0 payload is the wrong type.",
234 )?,
235 }
236 }
237
Max Bires148c08e2020-10-13 13:41:41 -0700238 /// Generates a CBOR blob which will be assembled by the calling code into a larger
239 /// CBOR blob intended for delivery to a provisioning serever. This blob will contain
240 /// `num_csr` certificate signing requests for attestation keys generated in the TEE,
241 /// along with a server provided `eek` and `challenge`. The endpoint encryption key will
242 /// be used to encrypt the sensitive contents being transmitted to the server, and the
243 /// challenge will ensure freshness. A `test_mode` flag will instruct the remote provisioning
244 /// HAL if it is okay to accept EEKs that aren't signed by something that chains back to the
245 /// baked in root of trust in the underlying IRemotelyProvisionedComponent instance.
Max Bires834dd362021-03-23 13:01:57 -0700246 #[allow(clippy::too_many_arguments)]
Max Bires148c08e2020-10-13 13:41:41 -0700247 pub fn generate_csr(
248 &self,
Max Biresb2e1d032021-02-08 21:35:05 -0800249 test_mode: bool,
250 num_csr: i32,
251 eek: &[u8],
252 challenge: &[u8],
253 sec_level: SecurityLevel,
254 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700255 device_info: &mut DeviceInfo,
Max Bires148c08e2020-10-13 13:41:41 -0700256 ) -> Result<Vec<u8>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800257 let dev = self.get_dev_by_sec_level(&sec_level)?;
258 let (_, _, uuid) = get_keymint_device(&sec_level)?;
259 let keys_to_sign = DB.with::<_, Result<Vec<MacedPublicKey>>>(|db| {
260 let mut db = db.borrow_mut();
261 Ok(db
262 .fetch_unsigned_attestation_keys(num_csr, &uuid)?
263 .iter()
264 .map(|key| MacedPublicKey { macedKey: key.to_vec() })
265 .collect())
266 })?;
Max Bires48fc2e52021-11-17 10:13:04 -0800267 let mac = map_rem_prov_error(dev.generateCertificateRequest(
Max Biresb2e1d032021-02-08 21:35:05 -0800268 test_mode,
269 &keys_to_sign,
270 eek,
271 challenge,
Max Bires834dd362021-03-23 13:01:57 -0700272 device_info,
Max Biresb2e1d032021-02-08 21:35:05 -0800273 protected_data,
274 ))
275 .context("In generate_csr: Failed to generate csr")?;
Max Bires48fc2e52021-11-17 10:13:04 -0800276 let mut mac_and_keys: Vec<Value> = vec![Value::from(mac)];
Max Bires97f96812021-02-23 23:44:57 -0800277 for maced_public_key in keys_to_sign {
Max Bires48fc2e52021-11-17 10:13:04 -0800278 mac_and_keys.push(
279 Self::extract_payload_from_cose_mac(&maced_public_key.macedKey)
280 .context("In generate_csr: Failed to get the payload from the COSE_Mac0")?,
281 )
Max Bires97f96812021-02-23 23:44:57 -0800282 }
Max Bires48fc2e52021-11-17 10:13:04 -0800283 let cbor_array: Value = Value::Array(mac_and_keys);
284 serde_cbor::to_vec(&cbor_array)
285 .context("In generate_csr: Failed to serialize the mac and keys array")
Max Bires148c08e2020-10-13 13:41:41 -0700286 }
287
288 /// Provisions a certificate chain for a key whose CSR was included in generate_csr. The
289 /// `public_key` is used to index into the SQL database in order to insert the `certs` blob
290 /// which represents a PEM encoded X.509 certificate chain. The `expiration_date` is provided
291 /// as a convenience from the caller to avoid having to parse the certificates semantically
292 /// here.
293 pub fn provision_cert_chain(
294 &self,
Seth Moore7ee79f92021-12-07 11:42:49 -0800295 db: &mut KeystoreDB,
Max Bires148c08e2020-10-13 13:41:41 -0700296 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800297 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700298 certs: &[u8],
299 expiration_date: i64,
300 sec_level: SecurityLevel,
301 ) -> Result<()> {
Seth Moore7ee79f92021-12-07 11:42:49 -0800302 let (_, _, uuid) = get_keymint_device(&sec_level)?;
303 db.store_signed_attestation_certificate_chain(
304 public_key,
305 batch_cert,
306 certs, /* DER encoded certificate chain */
307 expiration_date,
308 &uuid,
309 )
Max Bires148c08e2020-10-13 13:41:41 -0700310 }
311
Max Bires48fc2e52021-11-17 10:13:04 -0800312 fn parse_cose_mac0_for_coords(data: &[u8]) -> Result<Vec<u8>> {
313 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
314 "In parse_cose_mac0_for_coords: COSE_Mac0 returned from IRPC cannot be parsed",
315 )?;
316 if cose_mac0.len() != COSE_MAC0_LEN {
317 return Err(error::Error::sys()).context(format!(
318 "In parse_cose_mac0_for_coords: COSE_Mac0 has improper length. \
319 Expected: {}, Actual: {}",
320 COSE_MAC0_LEN,
321 cose_mac0.len(),
322 ));
323 }
324 let cose_key: BTreeMap<Value, Value> = match &cose_mac0[COSE_MAC0_PAYLOAD] {
325 Value::Bytes(key) => serde_cbor::from_slice(key)
326 .context("In parse_cose_mac0_for_coords: COSE_Key is malformed.")?,
327 _ => Err(error::Error::sys())
328 .context("In parse_cose_mac0_for_coords: COSE_Mac0 payload is the wrong type.")?,
329 };
330 if !cose_key.contains_key(&COSE_KEY_XCOORD) || !cose_key.contains_key(&COSE_KEY_YCOORD) {
331 return Err(error::Error::sys()).context(
332 "In parse_cose_mac0_for_coords: \
333 COSE_Key returned from IRPC is lacking required fields",
334 );
335 }
336 let mut raw_key: Vec<u8> = vec![0; 64];
337 match &cose_key[&COSE_KEY_XCOORD] {
338 Value::Bytes(x_coord) if x_coord.len() == 32 => {
339 raw_key[0..32].clone_from_slice(x_coord)
340 }
341 Value::Bytes(x_coord) => {
342 return Err(error::Error::sys()).context(format!(
343 "In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not the right length. \
344 Expected: 32; Actual: {}",
345 x_coord.len()
346 ))
347 }
348 _ => {
349 return Err(error::Error::sys())
350 .context("In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not a bstr")
351 }
352 }
353 match &cose_key[&COSE_KEY_YCOORD] {
354 Value::Bytes(y_coord) if y_coord.len() == 32 => {
355 raw_key[32..64].clone_from_slice(y_coord)
356 }
357 Value::Bytes(y_coord) => {
358 return Err(error::Error::sys()).context(format!(
359 "In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not the right length. \
360 Expected: 32; Actual: {}",
361 y_coord.len()
362 ))
363 }
364 _ => {
365 return Err(error::Error::sys())
366 .context("In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not a bstr")
367 }
368 }
369 Ok(raw_key)
370 }
371
Max Bires148c08e2020-10-13 13:41:41 -0700372 /// Submits a request to the Remote Provisioner HAL to generate a signing key pair.
373 /// `is_test_mode` indicates whether or not the returned public key should be marked as being
374 /// for testing in order to differentiate them from private keys. If the call is successful,
375 /// the key pair is then added to the database.
Seth Moore7ee79f92021-12-07 11:42:49 -0800376 pub fn generate_key_pair(
377 &self,
378 db: &mut KeystoreDB,
379 is_test_mode: bool,
380 sec_level: SecurityLevel,
381 ) -> Result<()> {
Max Biresb2e1d032021-02-08 21:35:05 -0800382 let (_, _, uuid) = get_keymint_device(&sec_level)?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800383 let dev = self.get_dev_by_sec_level(&sec_level).context(format!(
384 "In generate_key_pair: Failed to get device for security level {:?}",
385 sec_level
386 ))?;
Max Biresb2e1d032021-02-08 21:35:05 -0800387 let mut maced_key = MacedPublicKey { macedKey: Vec::new() };
388 let priv_key =
389 map_rem_prov_error(dev.generateEcdsaP256KeyPair(is_test_mode, &mut maced_key))
390 .context("In generate_key_pair: Failed to generated ECDSA keypair.")?;
Max Bires48fc2e52021-11-17 10:13:04 -0800391 let raw_key = Self::parse_cose_mac0_for_coords(&maced_key.macedKey)
392 .context("In generate_key_pair: Failed to parse raw key")?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800393 db.create_attestation_key_entry(&maced_key.macedKey, &raw_key, &priv_key, &uuid)
394 .context("In generate_key_pair: Failed to insert attestation key entry")
Max Biresb2e1d032021-02-08 21:35:05 -0800395 }
396
397 /// Checks the security level of each available IRemotelyProvisionedComponent hal and returns
398 /// all levels in an array to the caller.
Max Biresd2ce46b2021-07-06 02:54:47 -0700399 pub fn get_implementation_info(&self) -> Result<Vec<ImplInfo>> {
400 Ok(self
401 .curve_by_sec_level
402 .iter()
403 .map(|(sec_level, curve)| ImplInfo { secLevel: *sec_level, supportedCurve: *curve })
404 .collect())
Max Bires148c08e2020-10-13 13:41:41 -0700405 }
Max Bires60d7ed12021-03-05 15:59:22 -0800406
407 /// Deletes all attestation keys generated by the IRemotelyProvisionedComponent from the device,
408 /// regardless of what state of the attestation key lifecycle they were in.
409 pub fn delete_all_keys(&self) -> Result<i64> {
410 DB.with::<_, Result<i64>>(|db| {
411 let mut db = db.borrow_mut();
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700412 db.delete_all_attestation_keys()
Max Bires60d7ed12021-03-05 15:59:22 -0800413 })
414 }
Max Bires148c08e2020-10-13 13:41:41 -0700415}
416
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000417/// Populates the AttestationPoolStatus parcelable with information about how many
418/// certs will be expiring by the date provided in `expired_by` along with how many
419/// keys have not yet been assigned.
420pub fn get_pool_status(expired_by: i64, sec_level: SecurityLevel) -> Result<AttestationPoolStatus> {
421 let (_, _, uuid) = get_keymint_device(&sec_level)?;
422 DB.with::<_, Result<AttestationPoolStatus>>(|db| {
423 let mut db = db.borrow_mut();
424 // delete_expired_attestation_keys is always safe to call, and will remove anything
425 // older than the date at the time of calling. No work should be done on the
426 // attestation keys unless the pool status is checked first, so this call should be
427 // enough to routinely clean out expired keys.
428 db.delete_expired_attestation_keys()?;
429 db.get_attestation_pool_status(expired_by, &uuid)
430 })
431}
432
Seth Moore7ee79f92021-12-07 11:42:49 -0800433/// Fetches a remote provisioning attestation key and certificate chain inside of the
434/// returned `CertificateChain` struct if one exists for the given caller_uid. If one has not
435/// been assigned, this function will assign it. If there are no signed attestation keys
436/// available to be assigned, it will return the ResponseCode `OUT_OF_KEYS`
437fn get_rem_prov_attest_key(
438 domain: Domain,
439 caller_uid: u32,
440 db: &mut KeystoreDB,
441 km_uuid: &Uuid,
Max Bires55620ff2022-02-11 13:34:15 -0800442) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
Seth Moore7ee79f92021-12-07 11:42:49 -0800443 match domain {
444 Domain::APP => {
445 // Attempt to get an Attestation Key once. If it fails, then the app doesn't
446 // have a valid chain assigned to it. The helper function will return None after
447 // attempting to assign a key. An error will be thrown if the pool is simply out
448 // of usable keys. Then another attempt to fetch the just-assigned key will be
449 // made. If this fails too, something is very wrong.
450 get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid)
451 .context("In get_rem_prov_attest_key: Failed to get a key")?
452 .map_or_else(
453 || get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid),
454 |v| Ok(Some(v)),
455 )
456 .context(concat!(
457 "In get_rem_prov_attest_key: Failed to get a key after",
458 "attempting to assign one."
459 ))?
460 .map_or_else(
461 || {
462 Err(Error::sys()).context(concat!(
463 "In get_rem_prov_attest_key: Attempted to assign a ",
464 "key and failed silently. Something is very wrong."
465 ))
466 },
Max Bires55620ff2022-02-11 13:34:15 -0800467 |(guard, cert_chain)| Ok(Some((guard, cert_chain))),
Seth Moore7ee79f92021-12-07 11:42:49 -0800468 )
469 }
470 _ => Ok(None),
471 }
472}
473
474/// Returns None if an AttestationKey fails to be assigned. Errors if no keys are available.
475fn get_rem_prov_attest_key_helper(
476 domain: Domain,
477 caller_uid: u32,
478 db: &mut KeystoreDB,
479 km_uuid: &Uuid,
Max Bires55620ff2022-02-11 13:34:15 -0800480) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
481 let guard_and_chain = db
Seth Moore7ee79f92021-12-07 11:42:49 -0800482 .retrieve_attestation_key_and_cert_chain(domain, caller_uid as i64, km_uuid)
483 .context("In get_rem_prov_attest_key_helper: Failed to retrieve a key + cert chain")?;
Max Bires55620ff2022-02-11 13:34:15 -0800484 match guard_and_chain {
485 Some((guard, cert_chain)) => Ok(Some((guard, cert_chain))),
Seth Moore7ee79f92021-12-07 11:42:49 -0800486 // Either this app needs to be assigned a key, or the pool is empty. An error will
487 // be thrown if there is no key available to assign. This will indicate that the app
488 // should be nudged to provision more keys so keystore can retry.
489 None => {
490 db.assign_attestation_key(domain, caller_uid as i64, km_uuid)
491 .context("In get_rem_prov_attest_key_helper: Failed to assign a key")?;
492 Ok(None)
493 }
494 }
495}
496
Max Bires148c08e2020-10-13 13:41:41 -0700497impl binder::Interface for RemoteProvisioningService {}
498
499// Implementation of IRemoteProvisioning. See AIDL spec at
500// :aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
501impl IRemoteProvisioning for RemoteProvisioningService {
502 fn getPoolStatus(
503 &self,
504 expired_by: i64,
505 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700506 ) -> binder::Result<AttestationPoolStatus> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000507 let _wp = wd::watch_millis("IRemoteProvisioning::getPoolStatus", 500);
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000508 map_or_log_err(get_pool_status(expired_by, sec_level), Ok)
Max Bires148c08e2020-10-13 13:41:41 -0700509 }
510
511 fn generateCsr(
512 &self,
513 test_mode: bool,
514 num_csr: i32,
515 eek: &[u8],
516 challenge: &[u8],
517 sec_level: SecurityLevel,
Max Biresb2e1d032021-02-08 21:35:05 -0800518 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700519 device_info: &mut DeviceInfo,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700520 ) -> binder::Result<Vec<u8>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000521 let _wp = wd::watch_millis("IRemoteProvisioning::generateCsr", 500);
Max Biresb2e1d032021-02-08 21:35:05 -0800522 map_or_log_err(
Max Bires834dd362021-03-23 13:01:57 -0700523 self.generate_csr(
524 test_mode,
525 num_csr,
526 eek,
527 challenge,
528 sec_level,
529 protected_data,
530 device_info,
531 ),
Max Biresb2e1d032021-02-08 21:35:05 -0800532 Ok,
533 )
Max Bires148c08e2020-10-13 13:41:41 -0700534 }
535
536 fn provisionCertChain(
537 &self,
538 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800539 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700540 certs: &[u8],
541 expiration_date: i64,
542 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700543 ) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000544 let _wp = wd::watch_millis("IRemoteProvisioning::provisionCertChain", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800545 DB.with::<_, binder::Result<()>>(|db| {
546 map_or_log_err(
547 self.provision_cert_chain(
548 &mut db.borrow_mut(),
549 public_key,
550 batch_cert,
551 certs,
552 expiration_date,
553 sec_level,
554 ),
555 Ok,
556 )
557 })
Max Bires148c08e2020-10-13 13:41:41 -0700558 }
559
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700560 fn generateKeyPair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000561 let _wp = wd::watch_millis("IRemoteProvisioning::generateKeyPair", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800562 DB.with::<_, binder::Result<()>>(|db| {
563 map_or_log_err(
564 self.generate_key_pair(&mut db.borrow_mut(), is_test_mode, sec_level),
565 Ok,
566 )
567 })
Max Bires148c08e2020-10-13 13:41:41 -0700568 }
Max Biresb2e1d032021-02-08 21:35:05 -0800569
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700570 fn getImplementationInfo(&self) -> binder::Result<Vec<ImplInfo>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000571 let _wp = wd::watch_millis("IRemoteProvisioning::getSecurityLevels", 500);
Max Biresd2ce46b2021-07-06 02:54:47 -0700572 map_or_log_err(self.get_implementation_info(), Ok)
Max Biresb2e1d032021-02-08 21:35:05 -0800573 }
Max Bires60d7ed12021-03-05 15:59:22 -0800574
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700575 fn deleteAllKeys(&self) -> binder::Result<i64> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000576 let _wp = wd::watch_millis("IRemoteProvisioning::deleteAllKeys", 500);
Max Bires60d7ed12021-03-05 15:59:22 -0800577 map_or_log_err(self.delete_all_keys(), Ok)
578 }
Max Bires148c08e2020-10-13 13:41:41 -0700579}
Max Bires48fc2e52021-11-17 10:13:04 -0800580
Seth Moore92648b62022-02-02 13:26:18 -0800581/// Implementation of the IRemotelyProvisionedKeyPool service.
582#[derive(Default)]
583pub struct RemotelyProvisionedKeyPoolService {
584 unique_id_to_sec_level: HashMap<String, SecurityLevel>,
585}
586
587impl RemotelyProvisionedKeyPoolService {
588 /// Fetches a remotely provisioned certificate chain and key for the given client uid that
589 /// was provisioned using the IRemotelyProvisionedComponent with the given id. The same key
590 /// will be returned for a given caller_uid on every request. If there are no attestation keys
591 /// available, `OUT_OF_KEYS` is returned.
592 fn get_attestation_key(
593 &self,
594 db: &mut KeystoreDB,
595 caller_uid: i32,
596 irpc_id: &str,
597 ) -> Result<RemotelyProvisionedKey> {
598 log::info!("get_attestation_key(self, {}, {}", caller_uid, irpc_id);
599
600 let sec_level = self
601 .unique_id_to_sec_level
602 .get(irpc_id)
603 .ok_or(Error::Rc(ResponseCode::INVALID_ARGUMENT))
604 .context(format!("In get_attestation_key: unknown irpc id '{}'", irpc_id))?;
605 let (_, _, km_uuid) = get_keymint_device(sec_level)?;
606
Max Bires55620ff2022-02-11 13:34:15 -0800607 let guard_and_cert_chain =
608 get_rem_prov_attest_key(Domain::APP, caller_uid as u32, db, &km_uuid)
609 .context("In get_attestation_key")?;
610 match guard_and_cert_chain {
611 Some((_, chain)) => Ok(RemotelyProvisionedKey {
Seth Moore92648b62022-02-02 13:26:18 -0800612 keyBlob: chain.private_key.to_vec(),
613 encodedCertChain: chain.cert_chain,
614 }),
615 // It should be impossible to get `None`, but handle it just in case as a
616 // precaution against future behavioral changes in `get_rem_prov_attest_key`.
617 None => Err(error::Error::Rc(ResponseCode::OUT_OF_KEYS))
618 .context("In get_attestation_key: No available attestation keys"),
619 }
620 }
621
622 /// Creates a new instance of the remotely provisioned key pool service, used for fetching
623 /// remotely provisioned attestation keys.
624 pub fn new_native_binder() -> Result<Strong<dyn IRemotelyProvisionedKeyPool>> {
625 let mut result: Self = Default::default();
626
627 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
628 .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
629 if let Some(id) = dev.getHardwareInfo()?.uniqueId {
630 result.unique_id_to_sec_level.insert(id, SecurityLevel::TRUSTED_ENVIRONMENT);
631 }
632
633 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
634 if let Some(id) = dev.getHardwareInfo()?.uniqueId {
635 if result.unique_id_to_sec_level.contains_key(&id) {
636 anyhow::bail!("In new_native_binder: duplicate irpc id found: '{}'", id)
637 }
638 result.unique_id_to_sec_level.insert(id, SecurityLevel::STRONGBOX);
639 }
640 }
641
642 // If none of the remotely provisioned components have unique ids, then we shouldn't
643 // bother publishing the service, as it's impossible to match keys with their backends.
644 if result.unique_id_to_sec_level.is_empty() {
645 anyhow::bail!(
646 "In new_native_binder: No remotely provisioned components have unique ids"
647 )
648 }
649
650 Ok(BnRemotelyProvisionedKeyPool::new_binder(
651 result,
652 BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
653 ))
654 }
655}
656
657impl binder::Interface for RemotelyProvisionedKeyPoolService {}
658
Seth Moore7ee79f92021-12-07 11:42:49 -0800659// Implementation of IRemotelyProvisionedKeyPool. See AIDL spec at
660// :aidl/android/security/remoteprovisioning/IRemotelyProvisionedKeyPool.aidl
Seth Moore92648b62022-02-02 13:26:18 -0800661impl IRemotelyProvisionedKeyPool for RemotelyProvisionedKeyPoolService {
Seth Moore7ee79f92021-12-07 11:42:49 -0800662 fn getAttestationKey(
663 &self,
664 caller_uid: i32,
665 irpc_id: &str,
666 ) -> binder::Result<RemotelyProvisionedKey> {
667 let _wp = wd::watch_millis("IRemotelyProvisionedKeyPool::getAttestationKey", 500);
668 map_or_log_err(check_keystore_permission(KeystorePerm::GetAttestationKey), Ok)?;
669 DB.with::<_, binder::Result<RemotelyProvisionedKey>>(|db| {
670 map_or_log_err(self.get_attestation_key(&mut db.borrow_mut(), caller_uid, irpc_id), Ok)
671 })
672 }
673}
674
Max Bires48fc2e52021-11-17 10:13:04 -0800675#[cfg(test)]
676mod tests {
677 use super::*;
678 use serde_cbor::Value;
679 use std::collections::BTreeMap;
Seth Moore7ee79f92021-12-07 11:42:49 -0800680 use std::sync::{Arc, Mutex};
681 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
682 RpcHardwareInfo::RpcHardwareInfo,
683 };
684
685 #[derive(Default)]
686 struct MockRemotelyProvisionedComponentValues {
687 hw_info: RpcHardwareInfo,
688 private_key: Vec<u8>,
689 maced_public_key: Vec<u8>,
690 }
691
692 // binder::Interface requires the Send trait, so we have to use a Mutex even though the test
693 // is single threaded.
694 #[derive(Default)]
695 struct MockRemotelyProvisionedComponent(Arc<Mutex<MockRemotelyProvisionedComponentValues>>);
696
697 impl binder::Interface for MockRemotelyProvisionedComponent {}
698
699 impl IRemotelyProvisionedComponent for MockRemotelyProvisionedComponent {
700 fn getHardwareInfo(&self) -> binder::Result<RpcHardwareInfo> {
701 Ok(self.0.lock().unwrap().hw_info.clone())
702 }
703
704 fn generateEcdsaP256KeyPair(
705 &self,
706 test_mode: bool,
707 maced_public_key: &mut MacedPublicKey,
708 ) -> binder::Result<Vec<u8>> {
709 assert!(test_mode);
710 maced_public_key.macedKey = self.0.lock().unwrap().maced_public_key.clone();
711 Ok(self.0.lock().unwrap().private_key.clone())
712 }
713
714 fn generateCertificateRequest(
715 &self,
716 _test_mode: bool,
717 _keys_to_sign: &[MacedPublicKey],
718 _eek: &[u8],
719 _challenge: &[u8],
720 _device_info: &mut DeviceInfo,
721 _protected_data: &mut ProtectedData,
722 ) -> binder::Result<Vec<u8>> {
723 Err(binder::StatusCode::INVALID_OPERATION.into())
724 }
725 }
726
727 // Hard coded cert that can be parsed -- the content doesn't matter for testing, only that it's valid.
728 fn get_fake_cert() -> Vec<u8> {
729 vec![
730 0x30, 0x82, 0x01, 0xbb, 0x30, 0x82, 0x01, 0x61, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
731 0x14, 0x3a, 0xd5, 0x67, 0xce, 0xfe, 0x93, 0xe1, 0xea, 0xb7, 0xe4, 0xbf, 0x64, 0x19,
732 0xa4, 0x11, 0xe1, 0x87, 0x40, 0x20, 0x37, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
733 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
734 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
735 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
736 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
737 0x6c, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x32, 0x31, 0x30, 0x32, 0x32,
738 0x30, 0x38, 0x35, 0x32, 0x5a, 0x17, 0x0d, 0x34, 0x39, 0x30, 0x34, 0x32, 0x36, 0x32,
739 0x32, 0x30, 0x38, 0x35, 0x32, 0x5a, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
740 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
741 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
742 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f,
743 0x67, 0x6c, 0x65, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
744 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42,
745 0x00, 0x04, 0x1e, 0xac, 0x0c, 0xe0, 0x0d, 0xc5, 0x25, 0x84, 0x1b, 0xd2, 0x77, 0x2d,
746 0xe7, 0xba, 0xf1, 0xde, 0xa7, 0xf6, 0x39, 0x7f, 0x38, 0x91, 0xbf, 0xa4, 0x58, 0xf5,
747 0x62, 0x6b, 0xce, 0x06, 0xcf, 0xb9, 0x73, 0x91, 0x0d, 0x8a, 0x60, 0xa0, 0xc6, 0xa2,
748 0x22, 0xe6, 0x51, 0x2e, 0x58, 0xd6, 0x43, 0x02, 0x80, 0x43, 0x44, 0x29, 0x38, 0x9a,
749 0x99, 0xf3, 0xa4, 0xdd, 0xd0, 0xb4, 0x6f, 0x8b, 0x44, 0x2d, 0xa3, 0x53, 0x30, 0x51,
750 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xdb, 0x13, 0x68,
751 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe, 0x42, 0x3c, 0xd9, 0x3f, 0x1a,
752 0x33, 0xe9, 0xaa, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
753 0x80, 0x14, 0xdb, 0x13, 0x68, 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe,
754 0x42, 0x3c, 0xd9, 0x3f, 0x1a, 0x33, 0xe9, 0xaa, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
755 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06,
756 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45,
757 0x02, 0x20, 0x10, 0xdf, 0x40, 0xc3, 0x20, 0x54, 0x36, 0xb5, 0xc9, 0x3c, 0x70, 0xe3,
758 0x55, 0x37, 0xd2, 0x04, 0x51, 0xeb, 0x0f, 0x18, 0x83, 0xd0, 0x58, 0xa1, 0x08, 0x77,
759 0x8d, 0x4d, 0xa4, 0x20, 0xee, 0x33, 0x02, 0x21, 0x00, 0x8d, 0xe3, 0xa6, 0x6c, 0x0d,
760 0x86, 0x25, 0xdc, 0x59, 0x0d, 0x21, 0x43, 0x22, 0x3a, 0xb9, 0xa1, 0x73, 0x28, 0xc9,
761 0x16, 0x9e, 0x91, 0x15, 0xc4, 0xc3, 0xd7, 0xeb, 0xe5, 0xce, 0xdc, 0x1c, 0x1b,
762 ]
763 }
764
765 // Generate a fake COSE_Mac0 with a key that's just `byte` repeated
766 fn generate_maced_pubkey(byte: u8) -> Vec<u8> {
767 vec![
768 0x84, 0x43, 0xA1, 0x01, 0x05, 0xA0, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20,
769 0x01, 0x21, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
770 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
771 byte, byte, byte, byte, byte, byte, byte, byte, 0x22, 0x58, 0x20, byte, byte, byte,
772 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
773 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
774 byte, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
775 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
776 byte, byte, byte, byte, byte, byte, byte,
777 ]
778 }
Max Bires48fc2e52021-11-17 10:13:04 -0800779
780 #[test]
781 fn test_parse_cose_mac0_for_coords_raw_bytes() -> Result<()> {
782 let cose_mac0: Vec<u8> = vec![
783 0x84, 0x01, 0x02, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
784 0x20, 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9,
785 0x21, 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C,
786 0x43, 0x22, 0xC8, 0xEE, 0x03, 0x22, 0x58, 0x20, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95,
787 0x90, 0xA7, 0x5C, 0x5A, 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A,
788 0xA3, 0xB3, 0x1A, 0xB4, 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC, 0x03,
789 ];
790 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&cose_mac0)?;
791 assert_eq!(
792 raw_key,
793 vec![
794 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9, 0x21,
795 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C, 0x43,
796 0x22, 0xC8, 0xEE, 0x03, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95, 0x90, 0xA7, 0x5C, 0x5A,
797 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A, 0xA3, 0xB3, 0x1A, 0xB4,
798 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC,
799 ]
800 );
801 Ok(())
802 }
803
804 #[test]
805 fn test_parse_cose_mac0_for_coords_constructed_mac() -> Result<()> {
806 let x_coord: Vec<u8> = vec![0; 32];
807 let y_coord: Vec<u8> = vec![1; 32];
808 let mut expected_key: Vec<u8> = Vec::new();
809 expected_key.extend(&x_coord);
810 expected_key.extend(&y_coord);
811 let key_map: BTreeMap<Value, Value> = BTreeMap::from([
812 (Value::Integer(1), Value::Integer(2)),
813 (Value::Integer(3), Value::Integer(-7)),
814 (Value::Integer(-1), Value::Integer(1)),
815 (Value::Integer(-2), Value::Bytes(x_coord)),
816 (Value::Integer(-3), Value::Bytes(y_coord)),
817 ]);
818 let cose_mac0: Vec<Value> = vec![
819 Value::Integer(0),
820 Value::Integer(1),
821 Value::from(serde_cbor::to_vec(&key_map)?),
822 Value::Integer(2),
823 ];
824 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&serde_cbor::to_vec(
825 &Value::from(cose_mac0),
826 )?)?;
827 assert_eq!(expected_key, raw_key);
828 Ok(())
829 }
830
831 #[test]
832 fn test_extract_payload_from_cose_mac() -> Result<()> {
833 let key_map = Value::Map(BTreeMap::from([(Value::Integer(1), Value::Integer(2))]));
834 let payload = Value::Bytes(serde_cbor::to_vec(&key_map)?);
835 let cose_mac0 =
836 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
837 let extracted_map = RemoteProvisioningService::extract_payload_from_cose_mac(
838 &serde_cbor::to_vec(&cose_mac0)?,
839 )?;
840 assert_eq!(key_map, extracted_map);
841 Ok(())
842 }
843
844 #[test]
845 fn test_extract_payload_from_cose_mac_fails_malformed_payload() -> Result<()> {
846 let payload = Value::Bytes(vec![5; 10]);
847 let cose_mac0 =
848 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
849 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
850 &serde_cbor::to_vec(&cose_mac0)?,
851 );
852 assert!(extracted_payload.is_err());
853 Ok(())
854 }
855
856 #[test]
857 fn test_extract_payload_from_cose_mac_fails_type() -> Result<()> {
858 let payload = Value::Integer(1);
859 let cose_mac0 =
860 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
861 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
862 &serde_cbor::to_vec(&cose_mac0)?,
863 );
864 assert!(extracted_payload.is_err());
865 Ok(())
866 }
867
868 #[test]
869 fn test_extract_payload_from_cose_mac_fails_length() -> Result<()> {
870 let cose_mac0 = Value::Array(vec![Value::Integer(0), Value::Integer(1)]);
871 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
872 &serde_cbor::to_vec(&cose_mac0)?,
873 );
874 assert!(extracted_payload.is_err());
875 Ok(())
876 }
Seth Moore7ee79f92021-12-07 11:42:49 -0800877
878 #[test]
879 #[ignore] // b/215746308
880 fn test_get_attestation_key_no_keys_provisioned() {
881 let mut db = crate::database::tests::new_test_db().unwrap();
882 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
883 mock_rpc.0.lock().unwrap().hw_info.uniqueId = Some(String::from("mallory"));
884
Seth Moore92648b62022-02-02 13:26:18 -0800885 let mut service: RemotelyProvisionedKeyPoolService = Default::default();
Seth Moore7ee79f92021-12-07 11:42:49 -0800886 service
Seth Moore92648b62022-02-02 13:26:18 -0800887 .unique_id_to_sec_level
888 .insert(String::from("mallory"), SecurityLevel::TRUSTED_ENVIRONMENT);
Seth Moore7ee79f92021-12-07 11:42:49 -0800889
890 assert_eq!(
891 service
892 .get_attestation_key(&mut db, 0, "mallory")
893 .unwrap_err()
894 .downcast::<error::Error>()
895 .unwrap(),
896 error::Error::Rc(ResponseCode::OUT_OF_KEYS)
897 );
898 }
899
900 #[test]
901 #[ignore] // b/215746308
902 fn test_get_attestation_key() {
903 let mut db = crate::database::tests::new_test_db().unwrap();
904 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
905 let irpc_id = "paul";
906 let caller_uid = 0;
907
908 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
909 let mock_values = mock_rpc.0.clone();
Seth Moore92648b62022-02-02 13:26:18 -0800910 let mut remote_provisioning: RemoteProvisioningService = Default::default();
911 remote_provisioning.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
912 let mut key_pool: RemotelyProvisionedKeyPoolService = Default::default();
913 key_pool.unique_id_to_sec_level.insert(String::from(irpc_id), sec_level);
Seth Moore7ee79f92021-12-07 11:42:49 -0800914
915 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
916 mock_values.lock().unwrap().private_key = vec![8, 6, 7, 5, 3, 0, 9];
917 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
Seth Moore92648b62022-02-02 13:26:18 -0800918 remote_provisioning.generate_key_pair(&mut db, true, sec_level).unwrap();
Seth Moore7ee79f92021-12-07 11:42:49 -0800919
920 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
921 mock_values.lock().unwrap().maced_public_key.as_slice(),
922 )
923 .unwrap();
924 let batch_cert = get_fake_cert();
925 let certs = &[5, 6, 7, 8];
Seth Moore92648b62022-02-02 13:26:18 -0800926 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -0800927 .provision_cert_chain(
928 &mut db,
929 public_key.as_slice(),
930 batch_cert.as_slice(),
931 certs,
932 0,
933 sec_level
934 )
935 .is_ok());
936
937 // ensure we got the key we expected
Seth Moore92648b62022-02-02 13:26:18 -0800938 let first_key = key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -0800939 .get_attestation_key(&mut db, caller_uid, irpc_id)
940 .context("get first key")
941 .unwrap();
942 assert_eq!(first_key.keyBlob, mock_values.lock().unwrap().private_key);
943 assert_eq!(first_key.encodedCertChain, certs);
944
945 // ensure that multiple calls get the same key
946 assert_eq!(
947 first_key,
Seth Moore92648b62022-02-02 13:26:18 -0800948 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -0800949 .get_attestation_key(&mut db, caller_uid, irpc_id)
950 .context("get second key")
951 .unwrap()
952 );
953
954 // no more keys for new clients
955 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -0800956 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -0800957 .get_attestation_key(&mut db, caller_uid + 1, irpc_id)
958 .unwrap_err()
959 .downcast::<error::Error>()
960 .unwrap(),
961 error::Error::Rc(ResponseCode::OUT_OF_KEYS)
962 );
963 }
964
965 #[test]
966 #[ignore] // b/215746308
967 fn test_get_attestation_key_gets_different_key_for_different_client() {
968 let mut db = crate::database::tests::new_test_db().unwrap();
969 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
970 let irpc_id = "ringo";
971 let first_caller = 0;
972 let second_caller = first_caller + 1;
973
974 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
975 let mock_values = mock_rpc.0.clone();
Seth Moore92648b62022-02-02 13:26:18 -0800976 let mut remote_provisioning: RemoteProvisioningService = Default::default();
977 remote_provisioning.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
978 let mut key_pool: RemotelyProvisionedKeyPoolService = Default::default();
979 key_pool.unique_id_to_sec_level.insert(String::from(irpc_id), sec_level);
Seth Moore7ee79f92021-12-07 11:42:49 -0800980
981 // generate two distinct keys and provision them with certs
982 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
983 mock_values.lock().unwrap().private_key = vec![3, 1, 4, 1, 5];
984 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
Seth Moore92648b62022-02-02 13:26:18 -0800985 assert!(remote_provisioning.generate_key_pair(&mut db, true, sec_level).is_ok());
Seth Moore7ee79f92021-12-07 11:42:49 -0800986 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
987 mock_values.lock().unwrap().maced_public_key.as_slice(),
988 )
989 .unwrap();
Seth Moore92648b62022-02-02 13:26:18 -0800990 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -0800991 .provision_cert_chain(
992 &mut db,
993 public_key.as_slice(),
994 get_fake_cert().as_slice(),
995 &[1],
996 0,
997 sec_level
998 )
999 .is_ok());
1000
1001 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
1002 mock_values.lock().unwrap().private_key = vec![9, 0, 2, 1, 0];
1003 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x22);
Seth Moore92648b62022-02-02 13:26:18 -08001004 assert!(remote_provisioning.generate_key_pair(&mut db, true, sec_level).is_ok());
Seth Moore7ee79f92021-12-07 11:42:49 -08001005 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
1006 mock_values.lock().unwrap().maced_public_key.as_slice(),
1007 )
1008 .unwrap();
Seth Moore92648b62022-02-02 13:26:18 -08001009 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -08001010 .provision_cert_chain(
1011 &mut db,
1012 public_key.as_slice(),
1013 get_fake_cert().as_slice(),
1014 &[2],
1015 0,
1016 sec_level
1017 )
1018 .is_ok());
1019
1020 // make sure each caller gets a distinct key
1021 assert_ne!(
Seth Moore92648b62022-02-02 13:26:18 -08001022 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001023 .get_attestation_key(&mut db, first_caller, irpc_id)
1024 .context("get first key")
1025 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001026 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001027 .get_attestation_key(&mut db, second_caller, irpc_id)
1028 .context("get second key")
1029 .unwrap()
1030 );
1031
1032 // repeated calls should return the same key for a given caller
1033 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -08001034 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001035 .get_attestation_key(&mut db, first_caller, irpc_id)
1036 .context("first caller a")
1037 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001038 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001039 .get_attestation_key(&mut db, first_caller, irpc_id)
1040 .context("first caller b")
1041 .unwrap(),
1042 );
1043
1044 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -08001045 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001046 .get_attestation_key(&mut db, second_caller, irpc_id)
1047 .context("second caller a")
1048 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001049 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001050 .get_attestation_key(&mut db, second_caller, irpc_id)
1051 .context("second caller b")
1052 .unwrap()
1053 );
1054 }
Max Bires48fc2e52021-11-17 10:13:04 -08001055}