blob: 8837d1c096378b9dbddf99f149b7434c1bc409a7 [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,
Max Bires65207b52022-03-29 23:58:08 -070063 is_rkp_only: bool,
Max Bires97f96812021-02-23 23:44:57 -080064}
65
Max Bires48fc2e52021-11-17 10:13:04 -080066static COSE_KEY_XCOORD: Value = Value::Integer(-2);
67static COSE_KEY_YCOORD: Value = Value::Integer(-3);
68static COSE_MAC0_LEN: usize = 4;
69static COSE_MAC0_PAYLOAD: usize = 2;
70
Max Bires97f96812021-02-23 23:44:57 -080071impl RemProvState {
72 /// Creates a RemProvState struct.
73 pub fn new(security_level: SecurityLevel, km_uuid: Uuid) -> Self {
Max Bires65207b52022-03-29 23:58:08 -070074 Self {
75 security_level,
76 km_uuid,
77 is_hal_present: AtomicBool::new(true),
78 is_rkp_only: Self::read_is_rkp_only_property(security_level),
79 }
Max Bires97f96812021-02-23 23:44:57 -080080 }
81
Max Bires55620ff2022-02-11 13:34:15 -080082 /// Returns the uuid for the KM instance attached to this RemProvState struct.
83 pub fn get_uuid(&self) -> Uuid {
84 self.km_uuid
85 }
86
Max Bires65207b52022-03-29 23:58:08 -070087 fn read_is_rkp_only_property(security_level: SecurityLevel) -> bool {
88 let default_value = false;
89
90 let property_name = match security_level {
91 SecurityLevel::STRONGBOX => "ro.remote_provisioning.strongbox.rkp_only",
92 SecurityLevel::TRUSTED_ENVIRONMENT => "ro.remote_provisioning.tee.rkp_only",
93 _ => return default_value,
94 };
95
96 rustutils::system_properties::read_bool(property_name, default_value)
97 .unwrap_or(default_value)
98 }
99
Max Bires97f96812021-02-23 23:44:57 -0800100 /// Checks if remote provisioning is enabled and partially caches the result. On a hybrid system
101 /// remote provisioning can flip from being disabled to enabled depending on responses from the
102 /// server, so unfortunately caching the presence or absence of the HAL is not enough to fully
103 /// make decisions about the state of remote provisioning during runtime.
104 fn check_rem_prov_enabled(&self, db: &mut KeystoreDB) -> Result<bool> {
Seth Moore562aebb2022-04-18 17:03:27 -0700105 if self.is_rkp_only {
106 return Ok(true);
107 }
Max Bires97f96812021-02-23 23:44:57 -0800108 if !self.is_hal_present.load(Ordering::Relaxed)
109 || get_remotely_provisioned_component(&self.security_level).is_err()
110 {
111 self.is_hal_present.store(false, Ordering::Relaxed);
112 return Ok(false);
113 }
114 // To check if remote provisioning is enabled on a system that supports both remote
115 // provisioning and factory provisioned keys, we only need to check if there are any
116 // keys at all generated to indicate if the app has gotten the signal to begin filling
117 // the key pool from the server.
118 let pool_status = db
119 .get_attestation_pool_status(0 /* date */, &self.km_uuid)
120 .context("In check_rem_prov_enabled: failed to get attestation pool status.")?;
121 Ok(pool_status.total != 0)
122 }
123
Max Bires97f96812021-02-23 23:44:57 -0800124 fn is_asymmetric_key(&self, params: &[KeyParameter]) -> bool {
125 params.iter().any(|kp| {
126 matches!(
127 kp,
128 KeyParameter {
129 tag: Tag::ALGORITHM,
130 value: KeyParameterValue::Algorithm(Algorithm::RSA)
131 } | KeyParameter {
132 tag: Tag::ALGORITHM,
133 value: KeyParameterValue::Algorithm(Algorithm::EC)
134 }
135 )
136 })
137 }
138
139 /// Checks to see (1) if the key in question should be attested to based on the algorithm and
140 /// (2) if remote provisioning is present and enabled on the system. If these conditions are
141 /// met, it makes an attempt to fetch the attestation key assigned to the `caller_uid`.
142 ///
143 /// It returns the ResponseCode `OUT_OF_KEYS` if there is not one key currently assigned to the
144 /// `caller_uid` and there are none available to assign.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700145 pub fn get_remotely_provisioned_attestation_key_and_certs(
Max Bires97f96812021-02-23 23:44:57 -0800146 &self,
147 key: &KeyDescriptor,
148 caller_uid: u32,
149 params: &[KeyParameter],
150 db: &mut KeystoreDB,
Max Bires55620ff2022-02-11 13:34:15 -0800151 ) -> Result<Option<(KeyIdGuard, AttestationKey, Certificate)>> {
Max Bires97f96812021-02-23 23:44:57 -0800152 if !self.is_asymmetric_key(params) || !self.check_rem_prov_enabled(db)? {
153 // There is no remote provisioning component for this security level on the
154 // device. Return None so the underlying KM instance knows to use its
155 // factory provisioned key instead. Alternatively, it's not an asymmetric key
156 // and therefore will not be attested.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700157 Ok(None)
Max Bires97f96812021-02-23 23:44:57 -0800158 } else {
Seth Moore7ee79f92021-12-07 11:42:49 -0800159 match get_rem_prov_attest_key(key.domain, caller_uid, db, &self.km_uuid) {
Max Bires31cdfb82021-07-06 02:59:25 -0700160 Err(e) => {
161 log::error!(
Max Bires65207b52022-03-29 23:58:08 -0700162 "In get_remote_provisioning_key_and_certs: Error occurred: {:?}",
Max Bires31cdfb82021-07-06 02:59:25 -0700163 e
164 );
Max Bires65207b52022-03-29 23:58:08 -0700165 if self.is_rkp_only {
166 return Err(e);
167 }
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +0000168 log_rkp_error_stats(MetricsRkpError::FALL_BACK_DURING_HYBRID);
Max Bires31cdfb82021-07-06 02:59:25 -0700169 Ok(None)
170 }
171 Ok(v) => match v {
Max Bires55620ff2022-02-11 13:34:15 -0800172 Some((guard, cert_chain)) => Ok(Some((
173 guard,
Max Bires31cdfb82021-07-06 02:59:25 -0700174 AttestationKey {
175 keyBlob: cert_chain.private_key.to_vec(),
176 attestKeyParams: vec![],
177 issuerSubjectName: parse_subject_from_certificate(
178 &cert_chain.batch_cert,
179 )
Max Bires97f96812021-02-23 23:44:57 -0800180 .context(concat!(
Max Bires31cdfb82021-07-06 02:59:25 -0700181 "In get_remote_provisioning_key_and_certs: Failed to ",
182 "parse subject."
183 ))?,
184 },
185 Certificate { encodedCertificate: cert_chain.cert_chain },
186 ))),
187 None => Ok(None),
188 },
Max Bires97f96812021-02-23 23:44:57 -0800189 }
190 }
191 }
192}
Max Bires148c08e2020-10-13 13:41:41 -0700193/// Implementation of the IRemoteProvisioning service.
Max Biresb2e1d032021-02-08 21:35:05 -0800194#[derive(Default)]
Max Bires148c08e2020-10-13 13:41:41 -0700195pub struct RemoteProvisioningService {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -0700196 device_by_sec_level: HashMap<SecurityLevel, Strong<dyn IRemotelyProvisionedComponent>>,
Max Biresd2ce46b2021-07-06 02:54:47 -0700197 curve_by_sec_level: HashMap<SecurityLevel, i32>,
Max Bires148c08e2020-10-13 13:41:41 -0700198}
199
200impl RemoteProvisioningService {
Max Biresb2e1d032021-02-08 21:35:05 -0800201 fn get_dev_by_sec_level(
202 &self,
203 sec_level: &SecurityLevel,
Seth Moore7ee79f92021-12-07 11:42:49 -0800204 ) -> Result<&dyn IRemotelyProvisionedComponent> {
Max Biresb2e1d032021-02-08 21:35:05 -0800205 if let Some(dev) = self.device_by_sec_level.get(sec_level) {
Seth Moore7ee79f92021-12-07 11:42:49 -0800206 Ok(dev.as_ref())
Max Biresb2e1d032021-02-08 21:35:05 -0800207 } else {
208 Err(error::Error::sys()).context(concat!(
209 "In get_dev_by_sec_level: Remote instance for requested security level",
210 " not found."
211 ))
212 }
213 }
214
Max Bires148c08e2020-10-13 13:41:41 -0700215 /// Creates a new instance of the remote provisioning service
Stephen Crane221bbb52020-12-16 15:52:10 -0800216 pub fn new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800217 let mut result: Self = Default::default();
218 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
219 .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
Max Biresd2ce46b2021-07-06 02:54:47 -0700220 result.curve_by_sec_level.insert(
221 SecurityLevel::TRUSTED_ENVIRONMENT,
222 dev.getHardwareInfo()
223 .context("In new_native_binder: Failed to get hardware info for the TEE.")?
224 .supportedEekCurve,
225 );
Max Biresb2e1d032021-02-08 21:35:05 -0800226 result.device_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, dev);
227 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
Max Biresd2ce46b2021-07-06 02:54:47 -0700228 result.curve_by_sec_level.insert(
229 SecurityLevel::STRONGBOX,
230 dev.getHardwareInfo()
231 .context("In new_native_binder: Failed to get hardware info for StrongBox.")?
232 .supportedEekCurve,
233 );
Max Biresb2e1d032021-02-08 21:35:05 -0800234 result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
235 }
Andrew Walbrande45c8b2021-04-13 14:42:38 +0000236 Ok(BnRemoteProvisioning::new_binder(result, BinderFeatures::default()))
Max Bires148c08e2020-10-13 13:41:41 -0700237 }
238
Max Bires48fc2e52021-11-17 10:13:04 -0800239 fn extract_payload_from_cose_mac(data: &[u8]) -> Result<Value> {
240 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
241 "In extract_payload_from_cose_mac: COSE_Mac0 returned from IRPC cannot be parsed",
242 )?;
243 if cose_mac0.len() != COSE_MAC0_LEN {
244 return Err(error::Error::sys()).context(format!(
245 "In extract_payload_from_cose_mac: COSE_Mac0 has improper length. \
246 Expected: {}, Actual: {}",
247 COSE_MAC0_LEN,
248 cose_mac0.len(),
249 ));
250 }
251 match &cose_mac0[COSE_MAC0_PAYLOAD] {
252 Value::Bytes(key) => Ok(serde_cbor::from_slice(key)
253 .context("In extract_payload_from_cose_mac: COSE_Mac0 payload is malformed.")?),
254 _ => Err(error::Error::sys()).context(
255 "In extract_payload_from_cose_mac: COSE_Mac0 payload is the wrong type.",
256 )?,
257 }
258 }
259
Max Bires148c08e2020-10-13 13:41:41 -0700260 /// Generates a CBOR blob which will be assembled by the calling code into a larger
261 /// CBOR blob intended for delivery to a provisioning serever. This blob will contain
262 /// `num_csr` certificate signing requests for attestation keys generated in the TEE,
263 /// along with a server provided `eek` and `challenge`. The endpoint encryption key will
264 /// be used to encrypt the sensitive contents being transmitted to the server, and the
265 /// challenge will ensure freshness. A `test_mode` flag will instruct the remote provisioning
266 /// HAL if it is okay to accept EEKs that aren't signed by something that chains back to the
267 /// baked in root of trust in the underlying IRemotelyProvisionedComponent instance.
Max Bires834dd362021-03-23 13:01:57 -0700268 #[allow(clippy::too_many_arguments)]
Max Bires148c08e2020-10-13 13:41:41 -0700269 pub fn generate_csr(
270 &self,
Max Biresb2e1d032021-02-08 21:35:05 -0800271 test_mode: bool,
272 num_csr: i32,
273 eek: &[u8],
274 challenge: &[u8],
275 sec_level: SecurityLevel,
276 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700277 device_info: &mut DeviceInfo,
Max Bires148c08e2020-10-13 13:41:41 -0700278 ) -> Result<Vec<u8>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800279 let dev = self.get_dev_by_sec_level(&sec_level)?;
280 let (_, _, uuid) = get_keymint_device(&sec_level)?;
281 let keys_to_sign = DB.with::<_, Result<Vec<MacedPublicKey>>>(|db| {
282 let mut db = db.borrow_mut();
283 Ok(db
284 .fetch_unsigned_attestation_keys(num_csr, &uuid)?
285 .iter()
286 .map(|key| MacedPublicKey { macedKey: key.to_vec() })
287 .collect())
288 })?;
Max Bires48fc2e52021-11-17 10:13:04 -0800289 let mac = map_rem_prov_error(dev.generateCertificateRequest(
Max Biresb2e1d032021-02-08 21:35:05 -0800290 test_mode,
291 &keys_to_sign,
292 eek,
293 challenge,
Max Bires834dd362021-03-23 13:01:57 -0700294 device_info,
Max Biresb2e1d032021-02-08 21:35:05 -0800295 protected_data,
296 ))
297 .context("In generate_csr: Failed to generate csr")?;
Max Bires48fc2e52021-11-17 10:13:04 -0800298 let mut mac_and_keys: Vec<Value> = vec![Value::from(mac)];
Max Bires97f96812021-02-23 23:44:57 -0800299 for maced_public_key in keys_to_sign {
Max Bires48fc2e52021-11-17 10:13:04 -0800300 mac_and_keys.push(
301 Self::extract_payload_from_cose_mac(&maced_public_key.macedKey)
302 .context("In generate_csr: Failed to get the payload from the COSE_Mac0")?,
303 )
Max Bires97f96812021-02-23 23:44:57 -0800304 }
Max Bires48fc2e52021-11-17 10:13:04 -0800305 let cbor_array: Value = Value::Array(mac_and_keys);
306 serde_cbor::to_vec(&cbor_array)
307 .context("In generate_csr: Failed to serialize the mac and keys array")
Max Bires148c08e2020-10-13 13:41:41 -0700308 }
309
310 /// Provisions a certificate chain for a key whose CSR was included in generate_csr. The
311 /// `public_key` is used to index into the SQL database in order to insert the `certs` blob
312 /// which represents a PEM encoded X.509 certificate chain. The `expiration_date` is provided
313 /// as a convenience from the caller to avoid having to parse the certificates semantically
314 /// here.
315 pub fn provision_cert_chain(
316 &self,
Seth Moore7ee79f92021-12-07 11:42:49 -0800317 db: &mut KeystoreDB,
Max Bires148c08e2020-10-13 13:41:41 -0700318 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800319 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700320 certs: &[u8],
321 expiration_date: i64,
322 sec_level: SecurityLevel,
323 ) -> Result<()> {
Seth Moore7ee79f92021-12-07 11:42:49 -0800324 let (_, _, uuid) = get_keymint_device(&sec_level)?;
325 db.store_signed_attestation_certificate_chain(
326 public_key,
327 batch_cert,
328 certs, /* DER encoded certificate chain */
329 expiration_date,
330 &uuid,
331 )
Max Bires148c08e2020-10-13 13:41:41 -0700332 }
333
Max Bires48fc2e52021-11-17 10:13:04 -0800334 fn parse_cose_mac0_for_coords(data: &[u8]) -> Result<Vec<u8>> {
335 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
336 "In parse_cose_mac0_for_coords: COSE_Mac0 returned from IRPC cannot be parsed",
337 )?;
338 if cose_mac0.len() != COSE_MAC0_LEN {
339 return Err(error::Error::sys()).context(format!(
340 "In parse_cose_mac0_for_coords: COSE_Mac0 has improper length. \
341 Expected: {}, Actual: {}",
342 COSE_MAC0_LEN,
343 cose_mac0.len(),
344 ));
345 }
346 let cose_key: BTreeMap<Value, Value> = match &cose_mac0[COSE_MAC0_PAYLOAD] {
347 Value::Bytes(key) => serde_cbor::from_slice(key)
348 .context("In parse_cose_mac0_for_coords: COSE_Key is malformed.")?,
349 _ => Err(error::Error::sys())
350 .context("In parse_cose_mac0_for_coords: COSE_Mac0 payload is the wrong type.")?,
351 };
352 if !cose_key.contains_key(&COSE_KEY_XCOORD) || !cose_key.contains_key(&COSE_KEY_YCOORD) {
353 return Err(error::Error::sys()).context(
354 "In parse_cose_mac0_for_coords: \
355 COSE_Key returned from IRPC is lacking required fields",
356 );
357 }
358 let mut raw_key: Vec<u8> = vec![0; 64];
359 match &cose_key[&COSE_KEY_XCOORD] {
360 Value::Bytes(x_coord) if x_coord.len() == 32 => {
361 raw_key[0..32].clone_from_slice(x_coord)
362 }
363 Value::Bytes(x_coord) => {
364 return Err(error::Error::sys()).context(format!(
365 "In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not the right length. \
366 Expected: 32; Actual: {}",
367 x_coord.len()
368 ))
369 }
370 _ => {
371 return Err(error::Error::sys())
372 .context("In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not a bstr")
373 }
374 }
375 match &cose_key[&COSE_KEY_YCOORD] {
376 Value::Bytes(y_coord) if y_coord.len() == 32 => {
377 raw_key[32..64].clone_from_slice(y_coord)
378 }
379 Value::Bytes(y_coord) => {
380 return Err(error::Error::sys()).context(format!(
381 "In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not the right length. \
382 Expected: 32; Actual: {}",
383 y_coord.len()
384 ))
385 }
386 _ => {
387 return Err(error::Error::sys())
388 .context("In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not a bstr")
389 }
390 }
391 Ok(raw_key)
392 }
393
Max Bires148c08e2020-10-13 13:41:41 -0700394 /// Submits a request to the Remote Provisioner HAL to generate a signing key pair.
395 /// `is_test_mode` indicates whether or not the returned public key should be marked as being
396 /// for testing in order to differentiate them from private keys. If the call is successful,
397 /// the key pair is then added to the database.
Seth Moore7ee79f92021-12-07 11:42:49 -0800398 pub fn generate_key_pair(
399 &self,
400 db: &mut KeystoreDB,
401 is_test_mode: bool,
402 sec_level: SecurityLevel,
403 ) -> Result<()> {
Max Biresb2e1d032021-02-08 21:35:05 -0800404 let (_, _, uuid) = get_keymint_device(&sec_level)?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800405 let dev = self.get_dev_by_sec_level(&sec_level).context(format!(
406 "In generate_key_pair: Failed to get device for security level {:?}",
407 sec_level
408 ))?;
Max Biresb2e1d032021-02-08 21:35:05 -0800409 let mut maced_key = MacedPublicKey { macedKey: Vec::new() };
410 let priv_key =
411 map_rem_prov_error(dev.generateEcdsaP256KeyPair(is_test_mode, &mut maced_key))
412 .context("In generate_key_pair: Failed to generated ECDSA keypair.")?;
Max Bires48fc2e52021-11-17 10:13:04 -0800413 let raw_key = Self::parse_cose_mac0_for_coords(&maced_key.macedKey)
414 .context("In generate_key_pair: Failed to parse raw key")?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800415 db.create_attestation_key_entry(&maced_key.macedKey, &raw_key, &priv_key, &uuid)
416 .context("In generate_key_pair: Failed to insert attestation key entry")
Max Biresb2e1d032021-02-08 21:35:05 -0800417 }
418
419 /// Checks the security level of each available IRemotelyProvisionedComponent hal and returns
420 /// all levels in an array to the caller.
Max Biresd2ce46b2021-07-06 02:54:47 -0700421 pub fn get_implementation_info(&self) -> Result<Vec<ImplInfo>> {
422 Ok(self
423 .curve_by_sec_level
424 .iter()
425 .map(|(sec_level, curve)| ImplInfo { secLevel: *sec_level, supportedCurve: *curve })
426 .collect())
Max Bires148c08e2020-10-13 13:41:41 -0700427 }
Max Bires60d7ed12021-03-05 15:59:22 -0800428
429 /// Deletes all attestation keys generated by the IRemotelyProvisionedComponent from the device,
430 /// regardless of what state of the attestation key lifecycle they were in.
431 pub fn delete_all_keys(&self) -> Result<i64> {
432 DB.with::<_, Result<i64>>(|db| {
433 let mut db = db.borrow_mut();
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700434 db.delete_all_attestation_keys()
Max Bires60d7ed12021-03-05 15:59:22 -0800435 })
436 }
Max Bires148c08e2020-10-13 13:41:41 -0700437}
438
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000439/// Populates the AttestationPoolStatus parcelable with information about how many
440/// certs will be expiring by the date provided in `expired_by` along with how many
441/// keys have not yet been assigned.
442pub fn get_pool_status(expired_by: i64, sec_level: SecurityLevel) -> Result<AttestationPoolStatus> {
443 let (_, _, uuid) = get_keymint_device(&sec_level)?;
444 DB.with::<_, Result<AttestationPoolStatus>>(|db| {
445 let mut db = db.borrow_mut();
446 // delete_expired_attestation_keys is always safe to call, and will remove anything
447 // older than the date at the time of calling. No work should be done on the
448 // attestation keys unless the pool status is checked first, so this call should be
449 // enough to routinely clean out expired keys.
450 db.delete_expired_attestation_keys()?;
451 db.get_attestation_pool_status(expired_by, &uuid)
452 })
453}
454
Seth Moore7ee79f92021-12-07 11:42:49 -0800455/// Fetches a remote provisioning attestation key and certificate chain inside of the
456/// returned `CertificateChain` struct if one exists for the given caller_uid. If one has not
457/// been assigned, this function will assign it. If there are no signed attestation keys
458/// available to be assigned, it will return the ResponseCode `OUT_OF_KEYS`
459fn get_rem_prov_attest_key(
460 domain: Domain,
461 caller_uid: u32,
462 db: &mut KeystoreDB,
463 km_uuid: &Uuid,
Max Bires55620ff2022-02-11 13:34:15 -0800464) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
Seth Moore7ee79f92021-12-07 11:42:49 -0800465 match domain {
466 Domain::APP => {
467 // Attempt to get an Attestation Key once. If it fails, then the app doesn't
468 // have a valid chain assigned to it. The helper function will return None after
469 // attempting to assign a key. An error will be thrown if the pool is simply out
470 // of usable keys. Then another attempt to fetch the just-assigned key will be
471 // made. If this fails too, something is very wrong.
472 get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid)
473 .context("In get_rem_prov_attest_key: Failed to get a key")?
474 .map_or_else(
475 || get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid),
476 |v| Ok(Some(v)),
477 )
478 .context(concat!(
479 "In get_rem_prov_attest_key: Failed to get a key after",
480 "attempting to assign one."
481 ))?
482 .map_or_else(
483 || {
484 Err(Error::sys()).context(concat!(
485 "In get_rem_prov_attest_key: Attempted to assign a ",
486 "key and failed silently. Something is very wrong."
487 ))
488 },
Max Bires55620ff2022-02-11 13:34:15 -0800489 |(guard, cert_chain)| Ok(Some((guard, cert_chain))),
Seth Moore7ee79f92021-12-07 11:42:49 -0800490 )
491 }
492 _ => Ok(None),
493 }
494}
495
496/// Returns None if an AttestationKey fails to be assigned. Errors if no keys are available.
497fn get_rem_prov_attest_key_helper(
498 domain: Domain,
499 caller_uid: u32,
500 db: &mut KeystoreDB,
501 km_uuid: &Uuid,
Max Bires55620ff2022-02-11 13:34:15 -0800502) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
503 let guard_and_chain = db
Seth Moore7ee79f92021-12-07 11:42:49 -0800504 .retrieve_attestation_key_and_cert_chain(domain, caller_uid as i64, km_uuid)
505 .context("In get_rem_prov_attest_key_helper: Failed to retrieve a key + cert chain")?;
Max Bires55620ff2022-02-11 13:34:15 -0800506 match guard_and_chain {
507 Some((guard, cert_chain)) => Ok(Some((guard, cert_chain))),
Seth Moore7ee79f92021-12-07 11:42:49 -0800508 // Either this app needs to be assigned a key, or the pool is empty. An error will
509 // be thrown if there is no key available to assign. This will indicate that the app
510 // should be nudged to provision more keys so keystore can retry.
511 None => {
512 db.assign_attestation_key(domain, caller_uid as i64, km_uuid)
513 .context("In get_rem_prov_attest_key_helper: Failed to assign a key")?;
514 Ok(None)
515 }
516 }
517}
518
Max Bires148c08e2020-10-13 13:41:41 -0700519impl binder::Interface for RemoteProvisioningService {}
520
521// Implementation of IRemoteProvisioning. See AIDL spec at
522// :aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
523impl IRemoteProvisioning for RemoteProvisioningService {
524 fn getPoolStatus(
525 &self,
526 expired_by: i64,
527 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700528 ) -> binder::Result<AttestationPoolStatus> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000529 let _wp = wd::watch_millis("IRemoteProvisioning::getPoolStatus", 500);
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000530 map_or_log_err(get_pool_status(expired_by, sec_level), Ok)
Max Bires148c08e2020-10-13 13:41:41 -0700531 }
532
533 fn generateCsr(
534 &self,
535 test_mode: bool,
536 num_csr: i32,
537 eek: &[u8],
538 challenge: &[u8],
539 sec_level: SecurityLevel,
Max Biresb2e1d032021-02-08 21:35:05 -0800540 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700541 device_info: &mut DeviceInfo,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700542 ) -> binder::Result<Vec<u8>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000543 let _wp = wd::watch_millis("IRemoteProvisioning::generateCsr", 500);
Max Biresb2e1d032021-02-08 21:35:05 -0800544 map_or_log_err(
Max Bires834dd362021-03-23 13:01:57 -0700545 self.generate_csr(
546 test_mode,
547 num_csr,
548 eek,
549 challenge,
550 sec_level,
551 protected_data,
552 device_info,
553 ),
Max Biresb2e1d032021-02-08 21:35:05 -0800554 Ok,
555 )
Max Bires148c08e2020-10-13 13:41:41 -0700556 }
557
558 fn provisionCertChain(
559 &self,
560 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800561 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700562 certs: &[u8],
563 expiration_date: i64,
564 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700565 ) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000566 let _wp = wd::watch_millis("IRemoteProvisioning::provisionCertChain", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800567 DB.with::<_, binder::Result<()>>(|db| {
568 map_or_log_err(
569 self.provision_cert_chain(
570 &mut db.borrow_mut(),
571 public_key,
572 batch_cert,
573 certs,
574 expiration_date,
575 sec_level,
576 ),
577 Ok,
578 )
579 })
Max Bires148c08e2020-10-13 13:41:41 -0700580 }
581
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700582 fn generateKeyPair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000583 let _wp = wd::watch_millis("IRemoteProvisioning::generateKeyPair", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800584 DB.with::<_, binder::Result<()>>(|db| {
585 map_or_log_err(
586 self.generate_key_pair(&mut db.borrow_mut(), is_test_mode, sec_level),
587 Ok,
588 )
589 })
Max Bires148c08e2020-10-13 13:41:41 -0700590 }
Max Biresb2e1d032021-02-08 21:35:05 -0800591
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700592 fn getImplementationInfo(&self) -> binder::Result<Vec<ImplInfo>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000593 let _wp = wd::watch_millis("IRemoteProvisioning::getSecurityLevels", 500);
Max Biresd2ce46b2021-07-06 02:54:47 -0700594 map_or_log_err(self.get_implementation_info(), Ok)
Max Biresb2e1d032021-02-08 21:35:05 -0800595 }
Max Bires60d7ed12021-03-05 15:59:22 -0800596
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700597 fn deleteAllKeys(&self) -> binder::Result<i64> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000598 let _wp = wd::watch_millis("IRemoteProvisioning::deleteAllKeys", 500);
Max Bires60d7ed12021-03-05 15:59:22 -0800599 map_or_log_err(self.delete_all_keys(), Ok)
600 }
Max Bires148c08e2020-10-13 13:41:41 -0700601}
Max Bires48fc2e52021-11-17 10:13:04 -0800602
Seth Moore92648b62022-02-02 13:26:18 -0800603/// Implementation of the IRemotelyProvisionedKeyPool service.
604#[derive(Default)]
605pub struct RemotelyProvisionedKeyPoolService {
606 unique_id_to_sec_level: HashMap<String, SecurityLevel>,
607}
608
609impl RemotelyProvisionedKeyPoolService {
610 /// Fetches a remotely provisioned certificate chain and key for the given client uid that
611 /// was provisioned using the IRemotelyProvisionedComponent with the given id. The same key
612 /// will be returned for a given caller_uid on every request. If there are no attestation keys
613 /// available, `OUT_OF_KEYS` is returned.
614 fn get_attestation_key(
615 &self,
616 db: &mut KeystoreDB,
617 caller_uid: i32,
618 irpc_id: &str,
619 ) -> Result<RemotelyProvisionedKey> {
620 log::info!("get_attestation_key(self, {}, {}", caller_uid, irpc_id);
621
622 let sec_level = self
623 .unique_id_to_sec_level
624 .get(irpc_id)
625 .ok_or(Error::Rc(ResponseCode::INVALID_ARGUMENT))
626 .context(format!("In get_attestation_key: unknown irpc id '{}'", irpc_id))?;
627 let (_, _, km_uuid) = get_keymint_device(sec_level)?;
628
Max Bires55620ff2022-02-11 13:34:15 -0800629 let guard_and_cert_chain =
630 get_rem_prov_attest_key(Domain::APP, caller_uid as u32, db, &km_uuid)
631 .context("In get_attestation_key")?;
632 match guard_and_cert_chain {
633 Some((_, chain)) => Ok(RemotelyProvisionedKey {
Seth Moore92648b62022-02-02 13:26:18 -0800634 keyBlob: chain.private_key.to_vec(),
635 encodedCertChain: chain.cert_chain,
636 }),
637 // It should be impossible to get `None`, but handle it just in case as a
638 // precaution against future behavioral changes in `get_rem_prov_attest_key`.
639 None => Err(error::Error::Rc(ResponseCode::OUT_OF_KEYS))
640 .context("In get_attestation_key: No available attestation keys"),
641 }
642 }
643
644 /// Creates a new instance of the remotely provisioned key pool service, used for fetching
645 /// remotely provisioned attestation keys.
646 pub fn new_native_binder() -> Result<Strong<dyn IRemotelyProvisionedKeyPool>> {
647 let mut result: Self = Default::default();
648
649 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
650 .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
651 if let Some(id) = dev.getHardwareInfo()?.uniqueId {
652 result.unique_id_to_sec_level.insert(id, SecurityLevel::TRUSTED_ENVIRONMENT);
653 }
654
655 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
656 if let Some(id) = dev.getHardwareInfo()?.uniqueId {
657 if result.unique_id_to_sec_level.contains_key(&id) {
658 anyhow::bail!("In new_native_binder: duplicate irpc id found: '{}'", id)
659 }
660 result.unique_id_to_sec_level.insert(id, SecurityLevel::STRONGBOX);
661 }
662 }
663
664 // If none of the remotely provisioned components have unique ids, then we shouldn't
665 // bother publishing the service, as it's impossible to match keys with their backends.
666 if result.unique_id_to_sec_level.is_empty() {
667 anyhow::bail!(
668 "In new_native_binder: No remotely provisioned components have unique ids"
669 )
670 }
671
672 Ok(BnRemotelyProvisionedKeyPool::new_binder(
673 result,
674 BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
675 ))
676 }
677}
678
679impl binder::Interface for RemotelyProvisionedKeyPoolService {}
680
Seth Moore7ee79f92021-12-07 11:42:49 -0800681// Implementation of IRemotelyProvisionedKeyPool. See AIDL spec at
682// :aidl/android/security/remoteprovisioning/IRemotelyProvisionedKeyPool.aidl
Seth Moore92648b62022-02-02 13:26:18 -0800683impl IRemotelyProvisionedKeyPool for RemotelyProvisionedKeyPoolService {
Seth Moore7ee79f92021-12-07 11:42:49 -0800684 fn getAttestationKey(
685 &self,
686 caller_uid: i32,
687 irpc_id: &str,
688 ) -> binder::Result<RemotelyProvisionedKey> {
689 let _wp = wd::watch_millis("IRemotelyProvisionedKeyPool::getAttestationKey", 500);
690 map_or_log_err(check_keystore_permission(KeystorePerm::GetAttestationKey), Ok)?;
691 DB.with::<_, binder::Result<RemotelyProvisionedKey>>(|db| {
692 map_or_log_err(self.get_attestation_key(&mut db.borrow_mut(), caller_uid, irpc_id), Ok)
693 })
694 }
695}
696
Max Bires48fc2e52021-11-17 10:13:04 -0800697#[cfg(test)]
698mod tests {
699 use super::*;
700 use serde_cbor::Value;
701 use std::collections::BTreeMap;
Seth Moore7ee79f92021-12-07 11:42:49 -0800702 use std::sync::{Arc, Mutex};
703 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
704 RpcHardwareInfo::RpcHardwareInfo,
705 };
706
707 #[derive(Default)]
708 struct MockRemotelyProvisionedComponentValues {
709 hw_info: RpcHardwareInfo,
710 private_key: Vec<u8>,
711 maced_public_key: Vec<u8>,
712 }
713
714 // binder::Interface requires the Send trait, so we have to use a Mutex even though the test
715 // is single threaded.
716 #[derive(Default)]
717 struct MockRemotelyProvisionedComponent(Arc<Mutex<MockRemotelyProvisionedComponentValues>>);
718
719 impl binder::Interface for MockRemotelyProvisionedComponent {}
720
721 impl IRemotelyProvisionedComponent for MockRemotelyProvisionedComponent {
722 fn getHardwareInfo(&self) -> binder::Result<RpcHardwareInfo> {
723 Ok(self.0.lock().unwrap().hw_info.clone())
724 }
725
726 fn generateEcdsaP256KeyPair(
727 &self,
728 test_mode: bool,
729 maced_public_key: &mut MacedPublicKey,
730 ) -> binder::Result<Vec<u8>> {
731 assert!(test_mode);
732 maced_public_key.macedKey = self.0.lock().unwrap().maced_public_key.clone();
733 Ok(self.0.lock().unwrap().private_key.clone())
734 }
735
736 fn generateCertificateRequest(
737 &self,
738 _test_mode: bool,
739 _keys_to_sign: &[MacedPublicKey],
740 _eek: &[u8],
741 _challenge: &[u8],
742 _device_info: &mut DeviceInfo,
743 _protected_data: &mut ProtectedData,
744 ) -> binder::Result<Vec<u8>> {
745 Err(binder::StatusCode::INVALID_OPERATION.into())
746 }
747 }
748
749 // Hard coded cert that can be parsed -- the content doesn't matter for testing, only that it's valid.
750 fn get_fake_cert() -> Vec<u8> {
751 vec![
752 0x30, 0x82, 0x01, 0xbb, 0x30, 0x82, 0x01, 0x61, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
753 0x14, 0x3a, 0xd5, 0x67, 0xce, 0xfe, 0x93, 0xe1, 0xea, 0xb7, 0xe4, 0xbf, 0x64, 0x19,
754 0xa4, 0x11, 0xe1, 0x87, 0x40, 0x20, 0x37, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
755 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
756 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
757 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
758 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
759 0x6c, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x32, 0x31, 0x30, 0x32, 0x32,
760 0x30, 0x38, 0x35, 0x32, 0x5a, 0x17, 0x0d, 0x34, 0x39, 0x30, 0x34, 0x32, 0x36, 0x32,
761 0x32, 0x30, 0x38, 0x35, 0x32, 0x5a, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
762 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
763 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
764 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f,
765 0x67, 0x6c, 0x65, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
766 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42,
767 0x00, 0x04, 0x1e, 0xac, 0x0c, 0xe0, 0x0d, 0xc5, 0x25, 0x84, 0x1b, 0xd2, 0x77, 0x2d,
768 0xe7, 0xba, 0xf1, 0xde, 0xa7, 0xf6, 0x39, 0x7f, 0x38, 0x91, 0xbf, 0xa4, 0x58, 0xf5,
769 0x62, 0x6b, 0xce, 0x06, 0xcf, 0xb9, 0x73, 0x91, 0x0d, 0x8a, 0x60, 0xa0, 0xc6, 0xa2,
770 0x22, 0xe6, 0x51, 0x2e, 0x58, 0xd6, 0x43, 0x02, 0x80, 0x43, 0x44, 0x29, 0x38, 0x9a,
771 0x99, 0xf3, 0xa4, 0xdd, 0xd0, 0xb4, 0x6f, 0x8b, 0x44, 0x2d, 0xa3, 0x53, 0x30, 0x51,
772 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xdb, 0x13, 0x68,
773 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe, 0x42, 0x3c, 0xd9, 0x3f, 0x1a,
774 0x33, 0xe9, 0xaa, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
775 0x80, 0x14, 0xdb, 0x13, 0x68, 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe,
776 0x42, 0x3c, 0xd9, 0x3f, 0x1a, 0x33, 0xe9, 0xaa, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
777 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06,
778 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45,
779 0x02, 0x20, 0x10, 0xdf, 0x40, 0xc3, 0x20, 0x54, 0x36, 0xb5, 0xc9, 0x3c, 0x70, 0xe3,
780 0x55, 0x37, 0xd2, 0x04, 0x51, 0xeb, 0x0f, 0x18, 0x83, 0xd0, 0x58, 0xa1, 0x08, 0x77,
781 0x8d, 0x4d, 0xa4, 0x20, 0xee, 0x33, 0x02, 0x21, 0x00, 0x8d, 0xe3, 0xa6, 0x6c, 0x0d,
782 0x86, 0x25, 0xdc, 0x59, 0x0d, 0x21, 0x43, 0x22, 0x3a, 0xb9, 0xa1, 0x73, 0x28, 0xc9,
783 0x16, 0x9e, 0x91, 0x15, 0xc4, 0xc3, 0xd7, 0xeb, 0xe5, 0xce, 0xdc, 0x1c, 0x1b,
784 ]
785 }
786
787 // Generate a fake COSE_Mac0 with a key that's just `byte` repeated
788 fn generate_maced_pubkey(byte: u8) -> Vec<u8> {
789 vec![
790 0x84, 0x43, 0xA1, 0x01, 0x05, 0xA0, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20,
791 0x01, 0x21, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
792 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
793 byte, byte, byte, byte, byte, byte, byte, byte, 0x22, 0x58, 0x20, byte, byte, byte,
794 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
795 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
796 byte, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
797 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
798 byte, byte, byte, byte, byte, byte, byte,
799 ]
800 }
Max Bires48fc2e52021-11-17 10:13:04 -0800801
802 #[test]
803 fn test_parse_cose_mac0_for_coords_raw_bytes() -> Result<()> {
804 let cose_mac0: Vec<u8> = vec![
805 0x84, 0x01, 0x02, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
806 0x20, 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9,
807 0x21, 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C,
808 0x43, 0x22, 0xC8, 0xEE, 0x03, 0x22, 0x58, 0x20, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95,
809 0x90, 0xA7, 0x5C, 0x5A, 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A,
810 0xA3, 0xB3, 0x1A, 0xB4, 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC, 0x03,
811 ];
812 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&cose_mac0)?;
813 assert_eq!(
814 raw_key,
815 vec![
816 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9, 0x21,
817 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C, 0x43,
818 0x22, 0xC8, 0xEE, 0x03, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95, 0x90, 0xA7, 0x5C, 0x5A,
819 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A, 0xA3, 0xB3, 0x1A, 0xB4,
820 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC,
821 ]
822 );
823 Ok(())
824 }
825
826 #[test]
827 fn test_parse_cose_mac0_for_coords_constructed_mac() -> Result<()> {
828 let x_coord: Vec<u8> = vec![0; 32];
829 let y_coord: Vec<u8> = vec![1; 32];
830 let mut expected_key: Vec<u8> = Vec::new();
831 expected_key.extend(&x_coord);
832 expected_key.extend(&y_coord);
833 let key_map: BTreeMap<Value, Value> = BTreeMap::from([
834 (Value::Integer(1), Value::Integer(2)),
835 (Value::Integer(3), Value::Integer(-7)),
836 (Value::Integer(-1), Value::Integer(1)),
837 (Value::Integer(-2), Value::Bytes(x_coord)),
838 (Value::Integer(-3), Value::Bytes(y_coord)),
839 ]);
840 let cose_mac0: Vec<Value> = vec![
841 Value::Integer(0),
842 Value::Integer(1),
843 Value::from(serde_cbor::to_vec(&key_map)?),
844 Value::Integer(2),
845 ];
846 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&serde_cbor::to_vec(
847 &Value::from(cose_mac0),
848 )?)?;
849 assert_eq!(expected_key, raw_key);
850 Ok(())
851 }
852
853 #[test]
854 fn test_extract_payload_from_cose_mac() -> Result<()> {
855 let key_map = Value::Map(BTreeMap::from([(Value::Integer(1), Value::Integer(2))]));
856 let payload = Value::Bytes(serde_cbor::to_vec(&key_map)?);
857 let cose_mac0 =
858 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
859 let extracted_map = RemoteProvisioningService::extract_payload_from_cose_mac(
860 &serde_cbor::to_vec(&cose_mac0)?,
861 )?;
862 assert_eq!(key_map, extracted_map);
863 Ok(())
864 }
865
866 #[test]
867 fn test_extract_payload_from_cose_mac_fails_malformed_payload() -> Result<()> {
868 let payload = Value::Bytes(vec![5; 10]);
869 let cose_mac0 =
870 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
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 }
877
878 #[test]
879 fn test_extract_payload_from_cose_mac_fails_type() -> Result<()> {
880 let payload = Value::Integer(1);
881 let cose_mac0 =
882 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
883 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
884 &serde_cbor::to_vec(&cose_mac0)?,
885 );
886 assert!(extracted_payload.is_err());
887 Ok(())
888 }
889
890 #[test]
891 fn test_extract_payload_from_cose_mac_fails_length() -> Result<()> {
892 let cose_mac0 = Value::Array(vec![Value::Integer(0), Value::Integer(1)]);
893 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
894 &serde_cbor::to_vec(&cose_mac0)?,
895 );
896 assert!(extracted_payload.is_err());
897 Ok(())
898 }
Seth Moore7ee79f92021-12-07 11:42:49 -0800899
900 #[test]
901 #[ignore] // b/215746308
902 fn test_get_attestation_key_no_keys_provisioned() {
903 let mut db = crate::database::tests::new_test_db().unwrap();
904 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
905 mock_rpc.0.lock().unwrap().hw_info.uniqueId = Some(String::from("mallory"));
906
Seth Moore92648b62022-02-02 13:26:18 -0800907 let mut service: RemotelyProvisionedKeyPoolService = Default::default();
Seth Moore7ee79f92021-12-07 11:42:49 -0800908 service
Seth Moore92648b62022-02-02 13:26:18 -0800909 .unique_id_to_sec_level
910 .insert(String::from("mallory"), SecurityLevel::TRUSTED_ENVIRONMENT);
Seth Moore7ee79f92021-12-07 11:42:49 -0800911
912 assert_eq!(
913 service
914 .get_attestation_key(&mut db, 0, "mallory")
915 .unwrap_err()
916 .downcast::<error::Error>()
917 .unwrap(),
918 error::Error::Rc(ResponseCode::OUT_OF_KEYS)
919 );
920 }
921
922 #[test]
923 #[ignore] // b/215746308
924 fn test_get_attestation_key() {
925 let mut db = crate::database::tests::new_test_db().unwrap();
926 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
927 let irpc_id = "paul";
928 let caller_uid = 0;
929
930 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
931 let mock_values = mock_rpc.0.clone();
Seth Moore92648b62022-02-02 13:26:18 -0800932 let mut remote_provisioning: RemoteProvisioningService = Default::default();
933 remote_provisioning.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
934 let mut key_pool: RemotelyProvisionedKeyPoolService = Default::default();
935 key_pool.unique_id_to_sec_level.insert(String::from(irpc_id), sec_level);
Seth Moore7ee79f92021-12-07 11:42:49 -0800936
937 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
938 mock_values.lock().unwrap().private_key = vec![8, 6, 7, 5, 3, 0, 9];
939 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
Seth Moore92648b62022-02-02 13:26:18 -0800940 remote_provisioning.generate_key_pair(&mut db, true, sec_level).unwrap();
Seth Moore7ee79f92021-12-07 11:42:49 -0800941
942 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
943 mock_values.lock().unwrap().maced_public_key.as_slice(),
944 )
945 .unwrap();
946 let batch_cert = get_fake_cert();
947 let certs = &[5, 6, 7, 8];
Seth Moore92648b62022-02-02 13:26:18 -0800948 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -0800949 .provision_cert_chain(
950 &mut db,
951 public_key.as_slice(),
952 batch_cert.as_slice(),
953 certs,
954 0,
955 sec_level
956 )
957 .is_ok());
958
959 // ensure we got the key we expected
Seth Moore92648b62022-02-02 13:26:18 -0800960 let first_key = key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -0800961 .get_attestation_key(&mut db, caller_uid, irpc_id)
962 .context("get first key")
963 .unwrap();
964 assert_eq!(first_key.keyBlob, mock_values.lock().unwrap().private_key);
965 assert_eq!(first_key.encodedCertChain, certs);
966
967 // ensure that multiple calls get the same key
968 assert_eq!(
969 first_key,
Seth Moore92648b62022-02-02 13:26:18 -0800970 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -0800971 .get_attestation_key(&mut db, caller_uid, irpc_id)
972 .context("get second key")
973 .unwrap()
974 );
975
976 // no more keys for new clients
977 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -0800978 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -0800979 .get_attestation_key(&mut db, caller_uid + 1, irpc_id)
980 .unwrap_err()
981 .downcast::<error::Error>()
982 .unwrap(),
983 error::Error::Rc(ResponseCode::OUT_OF_KEYS)
984 );
985 }
986
987 #[test]
988 #[ignore] // b/215746308
989 fn test_get_attestation_key_gets_different_key_for_different_client() {
990 let mut db = crate::database::tests::new_test_db().unwrap();
991 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
992 let irpc_id = "ringo";
993 let first_caller = 0;
994 let second_caller = first_caller + 1;
995
996 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
997 let mock_values = mock_rpc.0.clone();
Seth Moore92648b62022-02-02 13:26:18 -0800998 let mut remote_provisioning: RemoteProvisioningService = Default::default();
999 remote_provisioning.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
1000 let mut key_pool: RemotelyProvisionedKeyPoolService = Default::default();
1001 key_pool.unique_id_to_sec_level.insert(String::from(irpc_id), sec_level);
Seth Moore7ee79f92021-12-07 11:42:49 -08001002
1003 // generate two distinct keys and provision them with certs
1004 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
1005 mock_values.lock().unwrap().private_key = vec![3, 1, 4, 1, 5];
1006 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
Seth Moore92648b62022-02-02 13:26:18 -08001007 assert!(remote_provisioning.generate_key_pair(&mut db, true, sec_level).is_ok());
Seth Moore7ee79f92021-12-07 11:42:49 -08001008 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
1009 mock_values.lock().unwrap().maced_public_key.as_slice(),
1010 )
1011 .unwrap();
Seth Moore92648b62022-02-02 13:26:18 -08001012 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -08001013 .provision_cert_chain(
1014 &mut db,
1015 public_key.as_slice(),
1016 get_fake_cert().as_slice(),
1017 &[1],
1018 0,
1019 sec_level
1020 )
1021 .is_ok());
1022
1023 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
1024 mock_values.lock().unwrap().private_key = vec![9, 0, 2, 1, 0];
1025 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x22);
Seth Moore92648b62022-02-02 13:26:18 -08001026 assert!(remote_provisioning.generate_key_pair(&mut db, true, sec_level).is_ok());
Seth Moore7ee79f92021-12-07 11:42:49 -08001027 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
1028 mock_values.lock().unwrap().maced_public_key.as_slice(),
1029 )
1030 .unwrap();
Seth Moore92648b62022-02-02 13:26:18 -08001031 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -08001032 .provision_cert_chain(
1033 &mut db,
1034 public_key.as_slice(),
1035 get_fake_cert().as_slice(),
1036 &[2],
1037 0,
1038 sec_level
1039 )
1040 .is_ok());
1041
1042 // make sure each caller gets a distinct key
1043 assert_ne!(
Seth Moore92648b62022-02-02 13:26:18 -08001044 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001045 .get_attestation_key(&mut db, first_caller, irpc_id)
1046 .context("get first key")
1047 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001048 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001049 .get_attestation_key(&mut db, second_caller, irpc_id)
1050 .context("get second key")
1051 .unwrap()
1052 );
1053
1054 // repeated calls should return the same key for a given caller
1055 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -08001056 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001057 .get_attestation_key(&mut db, first_caller, irpc_id)
1058 .context("first caller a")
1059 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001060 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001061 .get_attestation_key(&mut db, first_caller, irpc_id)
1062 .context("first caller b")
1063 .unwrap(),
1064 );
1065
1066 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -08001067 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001068 .get_attestation_key(&mut db, second_caller, irpc_id)
1069 .context("second caller a")
1070 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001071 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001072 .get_attestation_key(&mut db, second_caller, irpc_id)
1073 .context("second caller b")
1074 .unwrap()
1075 );
1076 }
Max Bires48fc2e52021-11-17 10:13:04 -08001077}