blob: cb2962a30ac151febc530d105f607d09c3ebfd5b [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,
Seth Moorecd6e9182022-11-04 17:39:05 +000026 KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue, SecurityLevel::SecurityLevel,
Max Bires834dd362021-03-23 13:01:57 -070027 Tag::Tag,
Max Biresb2e1d032021-02-08 21:35:05 -080028};
Seth Moorecd6e9182022-11-04 17:39:05 +000029use android_hardware_security_rkp::aidl::android::hardware::security::keymint::{
30 DeviceInfo::DeviceInfo, IRemotelyProvisionedComponent::IRemotelyProvisionedComponent,
31 MacedPublicKey::MacedPublicKey, ProtectedData::ProtectedData,
32};
Max Bires148c08e2020-10-13 13:41:41 -070033use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
34 AttestationPoolStatus::AttestationPoolStatus, IRemoteProvisioning::BnRemoteProvisioning,
Seth Moore7ee79f92021-12-07 11:42:49 -080035 IRemoteProvisioning::IRemoteProvisioning,
Seth Moore92648b62022-02-02 13:26:18 -080036 IRemotelyProvisionedKeyPool::BnRemotelyProvisionedKeyPool,
Seth Moore7ee79f92021-12-07 11:42:49 -080037 IRemotelyProvisionedKeyPool::IRemotelyProvisionedKeyPool, ImplInfo::ImplInfo,
38 RemotelyProvisionedKey::RemotelyProvisionedKey,
Max Bires148c08e2020-10-13 13:41:41 -070039};
Andrew Walbrande45c8b2021-04-13 14:42:38 +000040use android_security_remoteprovisioning::binder::{BinderFeatures, Strong};
Max Bires97f96812021-02-23 23:44:57 -080041use android_system_keystore2::aidl::android::system::keystore2::{
Seth Moore7ee79f92021-12-07 11:42:49 -080042 Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
Max Bires97f96812021-02-23 23:44:57 -080043};
Max Biresb2e1d032021-02-08 21:35:05 -080044use anyhow::{Context, Result};
Max Bires97f96812021-02-23 23:44:57 -080045use keystore2_crypto::parse_subject_from_certificate;
Max Bires48fc2e52021-11-17 10:13:04 -080046use serde_cbor::Value;
47use std::collections::BTreeMap;
Max Bires97f96812021-02-23 23:44:57 -080048use std::sync::atomic::{AtomicBool, Ordering};
Max Bires148c08e2020-10-13 13:41:41 -070049
Max Bires55620ff2022-02-11 13:34:15 -080050use crate::database::{CertificateChain, KeyIdGuard, KeystoreDB, Uuid};
Max Bires97f96812021-02-23 23:44:57 -080051use crate::error::{self, map_or_log_err, map_rem_prov_error, Error};
Max Biresb2e1d032021-02-08 21:35:05 -080052use crate::globals::{get_keymint_device, get_remotely_provisioned_component, DB};
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +000053use crate::ks_err;
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000054use crate::metrics_store::log_rkp_error_stats;
Seth Moore7ee79f92021-12-07 11:42:49 -080055use crate::permission::KeystorePerm;
Tri Vob5e43d12022-12-21 08:54:14 -080056use crate::rkpd_client::get_rkpd_attestation_key;
Seth Moore7ee79f92021-12-07 11:42:49 -080057use crate::utils::{check_keystore_permission, watchdog as wd};
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000058use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
Max Bires148c08e2020-10-13 13:41:41 -070059
Max Bires97f96812021-02-23 23:44:57 -080060/// Contains helper functions to check if remote provisioning is enabled on the system and, if so,
61/// to assign and retrieve attestation keys and certificate chains.
62#[derive(Default)]
63pub struct RemProvState {
64 security_level: SecurityLevel,
65 km_uuid: Uuid,
66 is_hal_present: AtomicBool,
67}
68
Max Bires48fc2e52021-11-17 10:13:04 -080069static COSE_KEY_XCOORD: Value = Value::Integer(-2);
70static COSE_KEY_YCOORD: Value = Value::Integer(-3);
71static COSE_MAC0_LEN: usize = 4;
72static COSE_MAC0_PAYLOAD: usize = 2;
73
Max Bires97f96812021-02-23 23:44:57 -080074impl RemProvState {
75 /// Creates a RemProvState struct.
76 pub fn new(security_level: SecurityLevel, km_uuid: Uuid) -> Self {
Seth Mooredfdcb872022-04-20 14:33:19 -070077 Self { security_level, km_uuid, is_hal_present: AtomicBool::new(true) }
Max Bires97f96812021-02-23 23:44:57 -080078 }
79
Max Bires55620ff2022-02-11 13:34:15 -080080 /// Returns the uuid for the KM instance attached to this RemProvState struct.
81 pub fn get_uuid(&self) -> Uuid {
82 self.km_uuid
83 }
84
Seth Mooredfdcb872022-04-20 14:33:19 -070085 fn is_rkp_only(&self) -> bool {
Max Bires65207b52022-03-29 23:58:08 -070086 let default_value = false;
87
Seth Mooredfdcb872022-04-20 14:33:19 -070088 let property_name = match self.security_level {
89 SecurityLevel::STRONGBOX => "remote_provisioning.strongbox.rkp_only",
90 SecurityLevel::TRUSTED_ENVIRONMENT => "remote_provisioning.tee.rkp_only",
Max Bires65207b52022-03-29 23:58:08 -070091 _ => return default_value,
92 };
93
94 rustutils::system_properties::read_bool(property_name, default_value)
95 .unwrap_or(default_value)
96 }
97
Max Bires97f96812021-02-23 23:44:57 -080098 /// Checks if remote provisioning is enabled and partially caches the result. On a hybrid system
99 /// remote provisioning can flip from being disabled to enabled depending on responses from the
100 /// server, so unfortunately caching the presence or absence of the HAL is not enough to fully
101 /// make decisions about the state of remote provisioning during runtime.
102 fn check_rem_prov_enabled(&self, db: &mut KeystoreDB) -> Result<bool> {
Seth Mooredfdcb872022-04-20 14:33:19 -0700103 if self.is_rkp_only() {
Seth Moore562aebb2022-04-18 17:03:27 -0700104 return Ok(true);
105 }
Max Bires97f96812021-02-23 23:44:57 -0800106 if !self.is_hal_present.load(Ordering::Relaxed)
107 || get_remotely_provisioned_component(&self.security_level).is_err()
108 {
109 self.is_hal_present.store(false, Ordering::Relaxed);
110 return Ok(false);
111 }
112 // To check if remote provisioning is enabled on a system that supports both remote
113 // provisioning and factory provisioned keys, we only need to check if there are any
114 // keys at all generated to indicate if the app has gotten the signal to begin filling
115 // the key pool from the server.
116 let pool_status = db
117 .get_attestation_pool_status(0 /* date */, &self.km_uuid)
118 .context("In check_rem_prov_enabled: failed to get attestation pool status.")?;
119 Ok(pool_status.total != 0)
120 }
121
Max Bires97f96812021-02-23 23:44:57 -0800122 fn is_asymmetric_key(&self, params: &[KeyParameter]) -> bool {
123 params.iter().any(|kp| {
124 matches!(
125 kp,
126 KeyParameter {
127 tag: Tag::ALGORITHM,
128 value: KeyParameterValue::Algorithm(Algorithm::RSA)
129 } | KeyParameter {
130 tag: Tag::ALGORITHM,
131 value: KeyParameterValue::Algorithm(Algorithm::EC)
132 }
133 )
134 })
135 }
136
137 /// Checks to see (1) if the key in question should be attested to based on the algorithm and
138 /// (2) if remote provisioning is present and enabled on the system. If these conditions are
139 /// met, it makes an attempt to fetch the attestation key assigned to the `caller_uid`.
140 ///
141 /// It returns the ResponseCode `OUT_OF_KEYS` if there is not one key currently assigned to the
142 /// `caller_uid` and there are none available to assign.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700143 pub fn get_remotely_provisioned_attestation_key_and_certs(
Max Bires97f96812021-02-23 23:44:57 -0800144 &self,
145 key: &KeyDescriptor,
146 caller_uid: u32,
147 params: &[KeyParameter],
148 db: &mut KeystoreDB,
Max Bires55620ff2022-02-11 13:34:15 -0800149 ) -> Result<Option<(KeyIdGuard, AttestationKey, Certificate)>> {
Max Bires97f96812021-02-23 23:44:57 -0800150 if !self.is_asymmetric_key(params) || !self.check_rem_prov_enabled(db)? {
151 // There is no remote provisioning component for this security level on the
152 // device. Return None so the underlying KM instance knows to use its
153 // factory provisioned key instead. Alternatively, it's not an asymmetric key
154 // and therefore will not be attested.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700155 Ok(None)
Max Bires97f96812021-02-23 23:44:57 -0800156 } else {
Seth Moore7ee79f92021-12-07 11:42:49 -0800157 match get_rem_prov_attest_key(key.domain, caller_uid, db, &self.km_uuid) {
Max Bires31cdfb82021-07-06 02:59:25 -0700158 Err(e) => {
Seth Mooredfdcb872022-04-20 14:33:19 -0700159 if self.is_rkp_only() {
Shaquille Johnson32bd2672022-10-21 13:18:56 +0100160 log::error!("Error occurred: {:?}", e);
Max Bires65207b52022-03-29 23:58:08 -0700161 return Err(e);
162 }
Shaquille Johnson32bd2672022-10-21 13:18:56 +0100163 log::warn!("Error occurred: {:?}", e);
Shaquille Johnsonbcab6012022-09-02 11:16:24 +0000164 log_rkp_error_stats(
165 MetricsRkpError::FALL_BACK_DURING_HYBRID,
166 &self.security_level,
167 );
Max Bires31cdfb82021-07-06 02:59:25 -0700168 Ok(None)
169 }
170 Ok(v) => match v {
Max Bires55620ff2022-02-11 13:34:15 -0800171 Some((guard, cert_chain)) => Ok(Some((
172 guard,
Max Bires31cdfb82021-07-06 02:59:25 -0700173 AttestationKey {
174 keyBlob: cert_chain.private_key.to_vec(),
175 attestKeyParams: vec![],
176 issuerSubjectName: parse_subject_from_certificate(
177 &cert_chain.batch_cert,
178 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000179 .context(ks_err!("Failed to parse subject."))?,
Max Bires31cdfb82021-07-06 02:59:25 -0700180 },
181 Certificate { encodedCertificate: cert_chain.cert_chain },
182 ))),
183 None => Ok(None),
184 },
Max Bires97f96812021-02-23 23:44:57 -0800185 }
186 }
187 }
Tri Vob5e43d12022-12-21 08:54:14 -0800188
189 /// Fetches attestation key and corresponding certificates from RKPD.
190 pub fn get_rkpd_attestation_key_and_certs(
191 &self,
192 key: &KeyDescriptor,
193 caller_uid: u32,
194 params: &[KeyParameter],
195 ) -> Result<Option<(AttestationKey, Certificate)>> {
196 if !self.is_asymmetric_key(params) || key.domain != Domain::APP {
197 Ok(None)
198 } else {
199 match get_rkpd_attestation_key(&self.security_level, caller_uid) {
200 Err(e) => {
201 if self.is_rkp_only() {
202 log::error!("Error occurred: {:?}", e);
203 return Err(e);
204 }
205 log::warn!("Error occurred: {:?}", e);
206 log_rkp_error_stats(
207 MetricsRkpError::FALL_BACK_DURING_HYBRID,
208 &self.security_level,
209 );
210 Ok(None)
211 }
212 Ok(rkpd_key) => Ok(Some((
213 AttestationKey {
214 keyBlob: rkpd_key.keyBlob,
215 attestKeyParams: vec![],
216 // Batch certificate is at the beginning of the certificate chain.
217 issuerSubjectName: parse_subject_from_certificate(
218 &rkpd_key.encodedCertChain,
219 )
220 .context(ks_err!("Failed to parse subject."))?,
221 },
222 Certificate { encodedCertificate: rkpd_key.encodedCertChain },
223 ))),
224 }
225 }
226 }
Max Bires97f96812021-02-23 23:44:57 -0800227}
Tri Vob5e43d12022-12-21 08:54:14 -0800228
Max Bires148c08e2020-10-13 13:41:41 -0700229/// Implementation of the IRemoteProvisioning service.
Max Biresb2e1d032021-02-08 21:35:05 -0800230#[derive(Default)]
Max Bires148c08e2020-10-13 13:41:41 -0700231pub struct RemoteProvisioningService {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -0700232 device_by_sec_level: HashMap<SecurityLevel, Strong<dyn IRemotelyProvisionedComponent>>,
Max Biresd2ce46b2021-07-06 02:54:47 -0700233 curve_by_sec_level: HashMap<SecurityLevel, i32>,
Max Bires148c08e2020-10-13 13:41:41 -0700234}
235
236impl RemoteProvisioningService {
Max Biresb2e1d032021-02-08 21:35:05 -0800237 fn get_dev_by_sec_level(
238 &self,
239 sec_level: &SecurityLevel,
Seth Moore7ee79f92021-12-07 11:42:49 -0800240 ) -> Result<&dyn IRemotelyProvisionedComponent> {
Max Biresb2e1d032021-02-08 21:35:05 -0800241 if let Some(dev) = self.device_by_sec_level.get(sec_level) {
Seth Moore7ee79f92021-12-07 11:42:49 -0800242 Ok(dev.as_ref())
Max Biresb2e1d032021-02-08 21:35:05 -0800243 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000244 Err(error::Error::sys()).context(ks_err!(
245 "Remote instance for requested security level \
246 not found.",
Max Biresb2e1d032021-02-08 21:35:05 -0800247 ))
248 }
249 }
250
Max Bires148c08e2020-10-13 13:41:41 -0700251 /// Creates a new instance of the remote provisioning service
Stephen Crane221bbb52020-12-16 15:52:10 -0800252 pub fn new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800253 let mut result: Self = Default::default();
254 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000255 .context(ks_err!("Failed to get TEE Remote Provisioner instance."))?;
Max Biresd2ce46b2021-07-06 02:54:47 -0700256 result.curve_by_sec_level.insert(
257 SecurityLevel::TRUSTED_ENVIRONMENT,
258 dev.getHardwareInfo()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000259 .context(ks_err!("Failed to get hardware info for the TEE."))?
Max Biresd2ce46b2021-07-06 02:54:47 -0700260 .supportedEekCurve,
261 );
Max Biresb2e1d032021-02-08 21:35:05 -0800262 result.device_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, dev);
263 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
Max Biresd2ce46b2021-07-06 02:54:47 -0700264 result.curve_by_sec_level.insert(
265 SecurityLevel::STRONGBOX,
266 dev.getHardwareInfo()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000267 .context(ks_err!("Failed to get hardware info for StrongBox."))?
Max Biresd2ce46b2021-07-06 02:54:47 -0700268 .supportedEekCurve,
269 );
Max Biresb2e1d032021-02-08 21:35:05 -0800270 result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
271 }
Andrew Walbrande45c8b2021-04-13 14:42:38 +0000272 Ok(BnRemoteProvisioning::new_binder(result, BinderFeatures::default()))
Max Bires148c08e2020-10-13 13:41:41 -0700273 }
274
Max Bires48fc2e52021-11-17 10:13:04 -0800275 fn extract_payload_from_cose_mac(data: &[u8]) -> Result<Value> {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000276 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data)
277 .context(ks_err!("COSE_Mac0 returned from IRPC cannot be parsed"))?;
Max Bires48fc2e52021-11-17 10:13:04 -0800278 if cose_mac0.len() != COSE_MAC0_LEN {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000279 return Err(error::Error::sys()).context(ks_err!(
280 "COSE_Mac0 has improper length. \
Max Bires48fc2e52021-11-17 10:13:04 -0800281 Expected: {}, Actual: {}",
282 COSE_MAC0_LEN,
283 cose_mac0.len(),
284 ));
285 }
286 match &cose_mac0[COSE_MAC0_PAYLOAD] {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000287 Value::Bytes(key) => {
288 Ok(serde_cbor::from_slice(key)
289 .context(ks_err!("COSE_Mac0 payload is malformed."))?)
290 }
291 _ => {
292 Err(error::Error::sys()).context(ks_err!("COSE_Mac0 payload is the wrong type."))?
293 }
Max Bires48fc2e52021-11-17 10:13:04 -0800294 }
295 }
296
Max Bires148c08e2020-10-13 13:41:41 -0700297 /// Generates a CBOR blob which will be assembled by the calling code into a larger
298 /// CBOR blob intended for delivery to a provisioning serever. This blob will contain
299 /// `num_csr` certificate signing requests for attestation keys generated in the TEE,
300 /// along with a server provided `eek` and `challenge`. The endpoint encryption key will
301 /// be used to encrypt the sensitive contents being transmitted to the server, and the
302 /// challenge will ensure freshness. A `test_mode` flag will instruct the remote provisioning
303 /// HAL if it is okay to accept EEKs that aren't signed by something that chains back to the
304 /// baked in root of trust in the underlying IRemotelyProvisionedComponent instance.
Max Bires834dd362021-03-23 13:01:57 -0700305 #[allow(clippy::too_many_arguments)]
Max Bires148c08e2020-10-13 13:41:41 -0700306 pub fn generate_csr(
307 &self,
Max Biresb2e1d032021-02-08 21:35:05 -0800308 test_mode: bool,
309 num_csr: i32,
310 eek: &[u8],
311 challenge: &[u8],
312 sec_level: SecurityLevel,
313 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700314 device_info: &mut DeviceInfo,
Max Bires148c08e2020-10-13 13:41:41 -0700315 ) -> Result<Vec<u8>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800316 let dev = self.get_dev_by_sec_level(&sec_level)?;
317 let (_, _, uuid) = get_keymint_device(&sec_level)?;
318 let keys_to_sign = DB.with::<_, Result<Vec<MacedPublicKey>>>(|db| {
319 let mut db = db.borrow_mut();
320 Ok(db
321 .fetch_unsigned_attestation_keys(num_csr, &uuid)?
322 .iter()
323 .map(|key| MacedPublicKey { macedKey: key.to_vec() })
324 .collect())
325 })?;
Max Bires48fc2e52021-11-17 10:13:04 -0800326 let mac = map_rem_prov_error(dev.generateCertificateRequest(
Max Biresb2e1d032021-02-08 21:35:05 -0800327 test_mode,
328 &keys_to_sign,
329 eek,
330 challenge,
Max Bires834dd362021-03-23 13:01:57 -0700331 device_info,
Max Biresb2e1d032021-02-08 21:35:05 -0800332 protected_data,
333 ))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000334 .context(ks_err!("Failed to generate csr"))?;
Max Bires48fc2e52021-11-17 10:13:04 -0800335 let mut mac_and_keys: Vec<Value> = vec![Value::from(mac)];
Max Bires97f96812021-02-23 23:44:57 -0800336 for maced_public_key in keys_to_sign {
Max Bires48fc2e52021-11-17 10:13:04 -0800337 mac_and_keys.push(
338 Self::extract_payload_from_cose_mac(&maced_public_key.macedKey)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000339 .context(ks_err!("Failed to get the payload from the COSE_Mac0"))?,
Max Bires48fc2e52021-11-17 10:13:04 -0800340 )
Max Bires97f96812021-02-23 23:44:57 -0800341 }
Max Bires48fc2e52021-11-17 10:13:04 -0800342 let cbor_array: Value = Value::Array(mac_and_keys);
343 serde_cbor::to_vec(&cbor_array)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000344 .context(ks_err!("Failed to serialize the mac and keys array"))
Max Bires148c08e2020-10-13 13:41:41 -0700345 }
346
347 /// Provisions a certificate chain for a key whose CSR was included in generate_csr. The
348 /// `public_key` is used to index into the SQL database in order to insert the `certs` blob
349 /// which represents a PEM encoded X.509 certificate chain. The `expiration_date` is provided
350 /// as a convenience from the caller to avoid having to parse the certificates semantically
351 /// here.
352 pub fn provision_cert_chain(
353 &self,
Seth Moore7ee79f92021-12-07 11:42:49 -0800354 db: &mut KeystoreDB,
Max Bires148c08e2020-10-13 13:41:41 -0700355 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800356 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700357 certs: &[u8],
358 expiration_date: i64,
359 sec_level: SecurityLevel,
360 ) -> Result<()> {
Seth Moore7ee79f92021-12-07 11:42:49 -0800361 let (_, _, uuid) = get_keymint_device(&sec_level)?;
362 db.store_signed_attestation_certificate_chain(
363 public_key,
364 batch_cert,
365 certs, /* DER encoded certificate chain */
366 expiration_date,
367 &uuid,
368 )
Max Bires148c08e2020-10-13 13:41:41 -0700369 }
370
Max Bires48fc2e52021-11-17 10:13:04 -0800371 fn parse_cose_mac0_for_coords(data: &[u8]) -> Result<Vec<u8>> {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000372 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data)
373 .context(ks_err!("COSE_Mac0 returned from IRPC cannot be parsed"))?;
Max Bires48fc2e52021-11-17 10:13:04 -0800374 if cose_mac0.len() != COSE_MAC0_LEN {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000375 return Err(error::Error::sys()).context(ks_err!(
376 "COSE_Mac0 has improper length. \
Max Bires48fc2e52021-11-17 10:13:04 -0800377 Expected: {}, Actual: {}",
378 COSE_MAC0_LEN,
379 cose_mac0.len(),
380 ));
381 }
382 let cose_key: BTreeMap<Value, Value> = match &cose_mac0[COSE_MAC0_PAYLOAD] {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000383 Value::Bytes(key) => {
384 serde_cbor::from_slice(key).context(ks_err!("COSE_Key is malformed."))?
385 }
386 _ => {
387 Err(error::Error::sys()).context(ks_err!("COSE_Mac0 payload is the wrong type."))?
388 }
Max Bires48fc2e52021-11-17 10:13:04 -0800389 };
390 if !cose_key.contains_key(&COSE_KEY_XCOORD) || !cose_key.contains_key(&COSE_KEY_YCOORD) {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000391 return Err(error::Error::sys())
392 .context(ks_err!("COSE_Key returned from IRPC is lacking required fields"));
Max Bires48fc2e52021-11-17 10:13:04 -0800393 }
394 let mut raw_key: Vec<u8> = vec![0; 64];
395 match &cose_key[&COSE_KEY_XCOORD] {
396 Value::Bytes(x_coord) if x_coord.len() == 32 => {
397 raw_key[0..32].clone_from_slice(x_coord)
398 }
399 Value::Bytes(x_coord) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000400 return Err(error::Error::sys()).context(ks_err!(
401 "COSE_Key X-coordinate is not the right length. \
Max Bires48fc2e52021-11-17 10:13:04 -0800402 Expected: 32; Actual: {}",
403 x_coord.len()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000404 ));
Max Bires48fc2e52021-11-17 10:13:04 -0800405 }
406 _ => {
407 return Err(error::Error::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000408 .context(ks_err!("COSE_Key X-coordinate is not a bstr"));
Max Bires48fc2e52021-11-17 10:13:04 -0800409 }
410 }
411 match &cose_key[&COSE_KEY_YCOORD] {
412 Value::Bytes(y_coord) if y_coord.len() == 32 => {
413 raw_key[32..64].clone_from_slice(y_coord)
414 }
415 Value::Bytes(y_coord) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000416 return Err(error::Error::sys()).context(ks_err!(
417 "COSE_Key Y-coordinate is not the right length. \
Max Bires48fc2e52021-11-17 10:13:04 -0800418 Expected: 32; Actual: {}",
419 y_coord.len()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000420 ));
Max Bires48fc2e52021-11-17 10:13:04 -0800421 }
422 _ => {
423 return Err(error::Error::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000424 .context(ks_err!("COSE_Key Y-coordinate is not a bstr"));
Max Bires48fc2e52021-11-17 10:13:04 -0800425 }
426 }
427 Ok(raw_key)
428 }
429
Max Bires148c08e2020-10-13 13:41:41 -0700430 /// Submits a request to the Remote Provisioner HAL to generate a signing key pair.
431 /// `is_test_mode` indicates whether or not the returned public key should be marked as being
432 /// for testing in order to differentiate them from private keys. If the call is successful,
433 /// the key pair is then added to the database.
Seth Moore7ee79f92021-12-07 11:42:49 -0800434 pub fn generate_key_pair(
435 &self,
436 db: &mut KeystoreDB,
437 is_test_mode: bool,
438 sec_level: SecurityLevel,
439 ) -> Result<()> {
Max Biresb2e1d032021-02-08 21:35:05 -0800440 let (_, _, uuid) = get_keymint_device(&sec_level)?;
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000441 let dev = self
442 .get_dev_by_sec_level(&sec_level)
443 .context(ks_err!("Failed to get device for security level {:?}", sec_level))?;
Max Biresb2e1d032021-02-08 21:35:05 -0800444 let mut maced_key = MacedPublicKey { macedKey: Vec::new() };
445 let priv_key =
446 map_rem_prov_error(dev.generateEcdsaP256KeyPair(is_test_mode, &mut maced_key))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000447 .context(ks_err!("Failed to generated ECDSA keypair."))?;
Max Bires48fc2e52021-11-17 10:13:04 -0800448 let raw_key = Self::parse_cose_mac0_for_coords(&maced_key.macedKey)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000449 .context(ks_err!("Failed to parse raw key"))?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800450 db.create_attestation_key_entry(&maced_key.macedKey, &raw_key, &priv_key, &uuid)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000451 .context(ks_err!("Failed to insert attestation key entry"))
Max Biresb2e1d032021-02-08 21:35:05 -0800452 }
453
454 /// Checks the security level of each available IRemotelyProvisionedComponent hal and returns
455 /// all levels in an array to the caller.
Max Biresd2ce46b2021-07-06 02:54:47 -0700456 pub fn get_implementation_info(&self) -> Result<Vec<ImplInfo>> {
457 Ok(self
458 .curve_by_sec_level
459 .iter()
460 .map(|(sec_level, curve)| ImplInfo { secLevel: *sec_level, supportedCurve: *curve })
461 .collect())
Max Bires148c08e2020-10-13 13:41:41 -0700462 }
Max Bires60d7ed12021-03-05 15:59:22 -0800463
464 /// Deletes all attestation keys generated by the IRemotelyProvisionedComponent from the device,
465 /// regardless of what state of the attestation key lifecycle they were in.
466 pub fn delete_all_keys(&self) -> Result<i64> {
467 DB.with::<_, Result<i64>>(|db| {
468 let mut db = db.borrow_mut();
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700469 db.delete_all_attestation_keys()
Max Bires60d7ed12021-03-05 15:59:22 -0800470 })
471 }
Max Bires148c08e2020-10-13 13:41:41 -0700472}
473
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000474/// Populates the AttestationPoolStatus parcelable with information about how many
475/// certs will be expiring by the date provided in `expired_by` along with how many
476/// keys have not yet been assigned.
477pub fn get_pool_status(expired_by: i64, sec_level: SecurityLevel) -> Result<AttestationPoolStatus> {
478 let (_, _, uuid) = get_keymint_device(&sec_level)?;
479 DB.with::<_, Result<AttestationPoolStatus>>(|db| {
480 let mut db = db.borrow_mut();
481 // delete_expired_attestation_keys is always safe to call, and will remove anything
482 // older than the date at the time of calling. No work should be done on the
483 // attestation keys unless the pool status is checked first, so this call should be
484 // enough to routinely clean out expired keys.
485 db.delete_expired_attestation_keys()?;
486 db.get_attestation_pool_status(expired_by, &uuid)
487 })
488}
489
Seth Moore7ee79f92021-12-07 11:42:49 -0800490/// Fetches a remote provisioning attestation key and certificate chain inside of the
491/// returned `CertificateChain` struct if one exists for the given caller_uid. If one has not
492/// been assigned, this function will assign it. If there are no signed attestation keys
493/// available to be assigned, it will return the ResponseCode `OUT_OF_KEYS`
494fn get_rem_prov_attest_key(
495 domain: Domain,
496 caller_uid: u32,
497 db: &mut KeystoreDB,
498 km_uuid: &Uuid,
Max Bires55620ff2022-02-11 13:34:15 -0800499) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
Seth Moore7ee79f92021-12-07 11:42:49 -0800500 match domain {
501 Domain::APP => {
502 // Attempt to get an Attestation Key once. If it fails, then the app doesn't
503 // have a valid chain assigned to it. The helper function will return None after
504 // attempting to assign a key. An error will be thrown if the pool is simply out
505 // of usable keys. Then another attempt to fetch the just-assigned key will be
506 // made. If this fails too, something is very wrong.
507 get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid)
508 .context("In get_rem_prov_attest_key: Failed to get a key")?
509 .map_or_else(
510 || get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid),
511 |v| Ok(Some(v)),
512 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000513 .context(ks_err!(
514 "Failed to get a key after \
515 attempting to assign one.",
Seth Moore7ee79f92021-12-07 11:42:49 -0800516 ))?
517 .map_or_else(
518 || {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000519 Err(Error::sys()).context(ks_err!(
520 "Attempted to assign a \
521 key and failed silently. Something is very wrong.",
Seth Moore7ee79f92021-12-07 11:42:49 -0800522 ))
523 },
Max Bires55620ff2022-02-11 13:34:15 -0800524 |(guard, cert_chain)| Ok(Some((guard, cert_chain))),
Seth Moore7ee79f92021-12-07 11:42:49 -0800525 )
526 }
527 _ => Ok(None),
528 }
529}
530
531/// Returns None if an AttestationKey fails to be assigned. Errors if no keys are available.
532fn get_rem_prov_attest_key_helper(
533 domain: Domain,
534 caller_uid: u32,
535 db: &mut KeystoreDB,
536 km_uuid: &Uuid,
Max Bires55620ff2022-02-11 13:34:15 -0800537) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
538 let guard_and_chain = db
Seth Moore7ee79f92021-12-07 11:42:49 -0800539 .retrieve_attestation_key_and_cert_chain(domain, caller_uid as i64, km_uuid)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000540 .context(ks_err!("Failed to retrieve a key + cert chain"))?;
Max Bires55620ff2022-02-11 13:34:15 -0800541 match guard_and_chain {
542 Some((guard, cert_chain)) => Ok(Some((guard, cert_chain))),
Seth Moore7ee79f92021-12-07 11:42:49 -0800543 // Either this app needs to be assigned a key, or the pool is empty. An error will
544 // be thrown if there is no key available to assign. This will indicate that the app
545 // should be nudged to provision more keys so keystore can retry.
546 None => {
547 db.assign_attestation_key(domain, caller_uid as i64, km_uuid)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000548 .context(ks_err!("Failed to assign a key"))?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800549 Ok(None)
550 }
551 }
552}
553
Max Bires148c08e2020-10-13 13:41:41 -0700554impl binder::Interface for RemoteProvisioningService {}
555
556// Implementation of IRemoteProvisioning. See AIDL spec at
557// :aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
558impl IRemoteProvisioning for RemoteProvisioningService {
559 fn getPoolStatus(
560 &self,
561 expired_by: i64,
562 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700563 ) -> binder::Result<AttestationPoolStatus> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000564 let _wp = wd::watch_millis("IRemoteProvisioning::getPoolStatus", 500);
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000565 map_or_log_err(get_pool_status(expired_by, sec_level), Ok)
Max Bires148c08e2020-10-13 13:41:41 -0700566 }
567
568 fn generateCsr(
569 &self,
570 test_mode: bool,
571 num_csr: i32,
572 eek: &[u8],
573 challenge: &[u8],
574 sec_level: SecurityLevel,
Max Biresb2e1d032021-02-08 21:35:05 -0800575 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700576 device_info: &mut DeviceInfo,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700577 ) -> binder::Result<Vec<u8>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000578 let _wp = wd::watch_millis("IRemoteProvisioning::generateCsr", 500);
Max Biresb2e1d032021-02-08 21:35:05 -0800579 map_or_log_err(
Max Bires834dd362021-03-23 13:01:57 -0700580 self.generate_csr(
581 test_mode,
582 num_csr,
583 eek,
584 challenge,
585 sec_level,
586 protected_data,
587 device_info,
588 ),
Max Biresb2e1d032021-02-08 21:35:05 -0800589 Ok,
590 )
Max Bires148c08e2020-10-13 13:41:41 -0700591 }
592
593 fn provisionCertChain(
594 &self,
595 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800596 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700597 certs: &[u8],
598 expiration_date: i64,
599 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700600 ) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000601 let _wp = wd::watch_millis("IRemoteProvisioning::provisionCertChain", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800602 DB.with::<_, binder::Result<()>>(|db| {
603 map_or_log_err(
604 self.provision_cert_chain(
605 &mut db.borrow_mut(),
606 public_key,
607 batch_cert,
608 certs,
609 expiration_date,
610 sec_level,
611 ),
612 Ok,
613 )
614 })
Max Bires148c08e2020-10-13 13:41:41 -0700615 }
616
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700617 fn generateKeyPair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000618 let _wp = wd::watch_millis("IRemoteProvisioning::generateKeyPair", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800619 DB.with::<_, binder::Result<()>>(|db| {
620 map_or_log_err(
621 self.generate_key_pair(&mut db.borrow_mut(), is_test_mode, sec_level),
622 Ok,
623 )
624 })
Max Bires148c08e2020-10-13 13:41:41 -0700625 }
Max Biresb2e1d032021-02-08 21:35:05 -0800626
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700627 fn getImplementationInfo(&self) -> binder::Result<Vec<ImplInfo>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000628 let _wp = wd::watch_millis("IRemoteProvisioning::getSecurityLevels", 500);
Max Biresd2ce46b2021-07-06 02:54:47 -0700629 map_or_log_err(self.get_implementation_info(), Ok)
Max Biresb2e1d032021-02-08 21:35:05 -0800630 }
Max Bires60d7ed12021-03-05 15:59:22 -0800631
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700632 fn deleteAllKeys(&self) -> binder::Result<i64> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000633 let _wp = wd::watch_millis("IRemoteProvisioning::deleteAllKeys", 500);
Max Bires60d7ed12021-03-05 15:59:22 -0800634 map_or_log_err(self.delete_all_keys(), Ok)
635 }
Max Bires148c08e2020-10-13 13:41:41 -0700636}
Max Bires48fc2e52021-11-17 10:13:04 -0800637
Seth Moore92648b62022-02-02 13:26:18 -0800638/// Implementation of the IRemotelyProvisionedKeyPool service.
639#[derive(Default)]
640pub struct RemotelyProvisionedKeyPoolService {
641 unique_id_to_sec_level: HashMap<String, SecurityLevel>,
642}
643
644impl RemotelyProvisionedKeyPoolService {
645 /// Fetches a remotely provisioned certificate chain and key for the given client uid that
646 /// was provisioned using the IRemotelyProvisionedComponent with the given id. The same key
647 /// will be returned for a given caller_uid on every request. If there are no attestation keys
648 /// available, `OUT_OF_KEYS` is returned.
649 fn get_attestation_key(
650 &self,
651 db: &mut KeystoreDB,
652 caller_uid: i32,
653 irpc_id: &str,
654 ) -> Result<RemotelyProvisionedKey> {
655 log::info!("get_attestation_key(self, {}, {}", caller_uid, irpc_id);
656
657 let sec_level = self
658 .unique_id_to_sec_level
659 .get(irpc_id)
660 .ok_or(Error::Rc(ResponseCode::INVALID_ARGUMENT))
661 .context(format!("In get_attestation_key: unknown irpc id '{}'", irpc_id))?;
662 let (_, _, km_uuid) = get_keymint_device(sec_level)?;
663
Max Bires55620ff2022-02-11 13:34:15 -0800664 let guard_and_cert_chain =
665 get_rem_prov_attest_key(Domain::APP, caller_uid as u32, db, &km_uuid)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000666 .context(ks_err!())?;
Max Bires55620ff2022-02-11 13:34:15 -0800667 match guard_and_cert_chain {
668 Some((_, chain)) => Ok(RemotelyProvisionedKey {
Seth Moore92648b62022-02-02 13:26:18 -0800669 keyBlob: chain.private_key.to_vec(),
670 encodedCertChain: chain.cert_chain,
671 }),
672 // It should be impossible to get `None`, but handle it just in case as a
673 // precaution against future behavioral changes in `get_rem_prov_attest_key`.
674 None => Err(error::Error::Rc(ResponseCode::OUT_OF_KEYS))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000675 .context(ks_err!("No available attestation keys")),
Seth Moore92648b62022-02-02 13:26:18 -0800676 }
677 }
678
679 /// Creates a new instance of the remotely provisioned key pool service, used for fetching
680 /// remotely provisioned attestation keys.
681 pub fn new_native_binder() -> Result<Strong<dyn IRemotelyProvisionedKeyPool>> {
682 let mut result: Self = Default::default();
683
684 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000685 .context(ks_err!("Failed to get TEE Remote Provisioner instance."))?;
Seth Moore92648b62022-02-02 13:26:18 -0800686 if let Some(id) = dev.getHardwareInfo()?.uniqueId {
687 result.unique_id_to_sec_level.insert(id, SecurityLevel::TRUSTED_ENVIRONMENT);
688 }
689
690 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
691 if let Some(id) = dev.getHardwareInfo()?.uniqueId {
692 if result.unique_id_to_sec_level.contains_key(&id) {
693 anyhow::bail!("In new_native_binder: duplicate irpc id found: '{}'", id)
694 }
695 result.unique_id_to_sec_level.insert(id, SecurityLevel::STRONGBOX);
696 }
697 }
698
699 // If none of the remotely provisioned components have unique ids, then we shouldn't
700 // bother publishing the service, as it's impossible to match keys with their backends.
701 if result.unique_id_to_sec_level.is_empty() {
702 anyhow::bail!(
703 "In new_native_binder: No remotely provisioned components have unique ids"
704 )
705 }
706
707 Ok(BnRemotelyProvisionedKeyPool::new_binder(
708 result,
709 BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
710 ))
711 }
712}
713
714impl binder::Interface for RemotelyProvisionedKeyPoolService {}
715
Seth Moore7ee79f92021-12-07 11:42:49 -0800716// Implementation of IRemotelyProvisionedKeyPool. See AIDL spec at
717// :aidl/android/security/remoteprovisioning/IRemotelyProvisionedKeyPool.aidl
Seth Moore92648b62022-02-02 13:26:18 -0800718impl IRemotelyProvisionedKeyPool for RemotelyProvisionedKeyPoolService {
Seth Moore7ee79f92021-12-07 11:42:49 -0800719 fn getAttestationKey(
720 &self,
721 caller_uid: i32,
722 irpc_id: &str,
723 ) -> binder::Result<RemotelyProvisionedKey> {
724 let _wp = wd::watch_millis("IRemotelyProvisionedKeyPool::getAttestationKey", 500);
725 map_or_log_err(check_keystore_permission(KeystorePerm::GetAttestationKey), Ok)?;
726 DB.with::<_, binder::Result<RemotelyProvisionedKey>>(|db| {
727 map_or_log_err(self.get_attestation_key(&mut db.borrow_mut(), caller_uid, irpc_id), Ok)
728 })
729 }
730}
731
Max Bires48fc2e52021-11-17 10:13:04 -0800732#[cfg(test)]
733mod tests {
734 use super::*;
735 use serde_cbor::Value;
736 use std::collections::BTreeMap;
Seth Moore7ee79f92021-12-07 11:42:49 -0800737 use std::sync::{Arc, Mutex};
Seth Moorecd6e9182022-11-04 17:39:05 +0000738 use android_hardware_security_rkp::aidl::android::hardware::security::keymint::{
Seth Moore7ee79f92021-12-07 11:42:49 -0800739 RpcHardwareInfo::RpcHardwareInfo,
740 };
741
742 #[derive(Default)]
743 struct MockRemotelyProvisionedComponentValues {
744 hw_info: RpcHardwareInfo,
745 private_key: Vec<u8>,
746 maced_public_key: Vec<u8>,
747 }
748
749 // binder::Interface requires the Send trait, so we have to use a Mutex even though the test
750 // is single threaded.
751 #[derive(Default)]
752 struct MockRemotelyProvisionedComponent(Arc<Mutex<MockRemotelyProvisionedComponentValues>>);
753
754 impl binder::Interface for MockRemotelyProvisionedComponent {}
755
756 impl IRemotelyProvisionedComponent for MockRemotelyProvisionedComponent {
757 fn getHardwareInfo(&self) -> binder::Result<RpcHardwareInfo> {
758 Ok(self.0.lock().unwrap().hw_info.clone())
759 }
760
761 fn generateEcdsaP256KeyPair(
762 &self,
763 test_mode: bool,
764 maced_public_key: &mut MacedPublicKey,
765 ) -> binder::Result<Vec<u8>> {
766 assert!(test_mode);
767 maced_public_key.macedKey = self.0.lock().unwrap().maced_public_key.clone();
768 Ok(self.0.lock().unwrap().private_key.clone())
769 }
770
771 fn generateCertificateRequest(
772 &self,
773 _test_mode: bool,
774 _keys_to_sign: &[MacedPublicKey],
775 _eek: &[u8],
776 _challenge: &[u8],
777 _device_info: &mut DeviceInfo,
778 _protected_data: &mut ProtectedData,
779 ) -> binder::Result<Vec<u8>> {
780 Err(binder::StatusCode::INVALID_OPERATION.into())
781 }
Tri Vo113a1c92022-10-02 15:23:19 -0700782
783 fn generateCertificateRequestV2(
784 &self,
785 _keys_to_sign: &[MacedPublicKey],
786 _challenge: &[u8],
787 ) -> binder::Result<Vec<u8>> {
788 Err(binder::StatusCode::INVALID_OPERATION.into())
789 }
Seth Moore7ee79f92021-12-07 11:42:49 -0800790 }
791
792 // Hard coded cert that can be parsed -- the content doesn't matter for testing, only that it's valid.
793 fn get_fake_cert() -> Vec<u8> {
794 vec![
795 0x30, 0x82, 0x01, 0xbb, 0x30, 0x82, 0x01, 0x61, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
796 0x14, 0x3a, 0xd5, 0x67, 0xce, 0xfe, 0x93, 0xe1, 0xea, 0xb7, 0xe4, 0xbf, 0x64, 0x19,
797 0xa4, 0x11, 0xe1, 0x87, 0x40, 0x20, 0x37, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
798 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
799 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
800 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
801 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
802 0x6c, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x32, 0x31, 0x30, 0x32, 0x32,
803 0x30, 0x38, 0x35, 0x32, 0x5a, 0x17, 0x0d, 0x34, 0x39, 0x30, 0x34, 0x32, 0x36, 0x32,
804 0x32, 0x30, 0x38, 0x35, 0x32, 0x5a, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
805 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
806 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
807 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f,
808 0x67, 0x6c, 0x65, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
809 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42,
810 0x00, 0x04, 0x1e, 0xac, 0x0c, 0xe0, 0x0d, 0xc5, 0x25, 0x84, 0x1b, 0xd2, 0x77, 0x2d,
811 0xe7, 0xba, 0xf1, 0xde, 0xa7, 0xf6, 0x39, 0x7f, 0x38, 0x91, 0xbf, 0xa4, 0x58, 0xf5,
812 0x62, 0x6b, 0xce, 0x06, 0xcf, 0xb9, 0x73, 0x91, 0x0d, 0x8a, 0x60, 0xa0, 0xc6, 0xa2,
813 0x22, 0xe6, 0x51, 0x2e, 0x58, 0xd6, 0x43, 0x02, 0x80, 0x43, 0x44, 0x29, 0x38, 0x9a,
814 0x99, 0xf3, 0xa4, 0xdd, 0xd0, 0xb4, 0x6f, 0x8b, 0x44, 0x2d, 0xa3, 0x53, 0x30, 0x51,
815 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xdb, 0x13, 0x68,
816 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe, 0x42, 0x3c, 0xd9, 0x3f, 0x1a,
817 0x33, 0xe9, 0xaa, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
818 0x80, 0x14, 0xdb, 0x13, 0x68, 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe,
819 0x42, 0x3c, 0xd9, 0x3f, 0x1a, 0x33, 0xe9, 0xaa, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
820 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06,
821 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45,
822 0x02, 0x20, 0x10, 0xdf, 0x40, 0xc3, 0x20, 0x54, 0x36, 0xb5, 0xc9, 0x3c, 0x70, 0xe3,
823 0x55, 0x37, 0xd2, 0x04, 0x51, 0xeb, 0x0f, 0x18, 0x83, 0xd0, 0x58, 0xa1, 0x08, 0x77,
824 0x8d, 0x4d, 0xa4, 0x20, 0xee, 0x33, 0x02, 0x21, 0x00, 0x8d, 0xe3, 0xa6, 0x6c, 0x0d,
825 0x86, 0x25, 0xdc, 0x59, 0x0d, 0x21, 0x43, 0x22, 0x3a, 0xb9, 0xa1, 0x73, 0x28, 0xc9,
826 0x16, 0x9e, 0x91, 0x15, 0xc4, 0xc3, 0xd7, 0xeb, 0xe5, 0xce, 0xdc, 0x1c, 0x1b,
827 ]
828 }
829
830 // Generate a fake COSE_Mac0 with a key that's just `byte` repeated
831 fn generate_maced_pubkey(byte: u8) -> Vec<u8> {
832 vec![
833 0x84, 0x43, 0xA1, 0x01, 0x05, 0xA0, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20,
834 0x01, 0x21, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
835 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
836 byte, byte, byte, byte, byte, byte, byte, byte, 0x22, 0x58, 0x20, byte, byte, byte,
837 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
838 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
839 byte, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
840 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
841 byte, byte, byte, byte, byte, byte, byte,
842 ]
843 }
Max Bires48fc2e52021-11-17 10:13:04 -0800844
845 #[test]
846 fn test_parse_cose_mac0_for_coords_raw_bytes() -> Result<()> {
847 let cose_mac0: Vec<u8> = vec![
848 0x84, 0x01, 0x02, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
849 0x20, 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9,
850 0x21, 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C,
851 0x43, 0x22, 0xC8, 0xEE, 0x03, 0x22, 0x58, 0x20, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95,
852 0x90, 0xA7, 0x5C, 0x5A, 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A,
853 0xA3, 0xB3, 0x1A, 0xB4, 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC, 0x03,
854 ];
855 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&cose_mac0)?;
856 assert_eq!(
857 raw_key,
858 vec![
859 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9, 0x21,
860 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C, 0x43,
861 0x22, 0xC8, 0xEE, 0x03, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95, 0x90, 0xA7, 0x5C, 0x5A,
862 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A, 0xA3, 0xB3, 0x1A, 0xB4,
863 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC,
864 ]
865 );
866 Ok(())
867 }
868
869 #[test]
870 fn test_parse_cose_mac0_for_coords_constructed_mac() -> Result<()> {
871 let x_coord: Vec<u8> = vec![0; 32];
872 let y_coord: Vec<u8> = vec![1; 32];
873 let mut expected_key: Vec<u8> = Vec::new();
874 expected_key.extend(&x_coord);
875 expected_key.extend(&y_coord);
876 let key_map: BTreeMap<Value, Value> = BTreeMap::from([
877 (Value::Integer(1), Value::Integer(2)),
878 (Value::Integer(3), Value::Integer(-7)),
879 (Value::Integer(-1), Value::Integer(1)),
880 (Value::Integer(-2), Value::Bytes(x_coord)),
881 (Value::Integer(-3), Value::Bytes(y_coord)),
882 ]);
883 let cose_mac0: Vec<Value> = vec![
884 Value::Integer(0),
885 Value::Integer(1),
886 Value::from(serde_cbor::to_vec(&key_map)?),
887 Value::Integer(2),
888 ];
889 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&serde_cbor::to_vec(
890 &Value::from(cose_mac0),
891 )?)?;
892 assert_eq!(expected_key, raw_key);
893 Ok(())
894 }
895
896 #[test]
897 fn test_extract_payload_from_cose_mac() -> Result<()> {
898 let key_map = Value::Map(BTreeMap::from([(Value::Integer(1), Value::Integer(2))]));
899 let payload = Value::Bytes(serde_cbor::to_vec(&key_map)?);
900 let cose_mac0 =
901 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
902 let extracted_map = RemoteProvisioningService::extract_payload_from_cose_mac(
903 &serde_cbor::to_vec(&cose_mac0)?,
904 )?;
905 assert_eq!(key_map, extracted_map);
906 Ok(())
907 }
908
909 #[test]
910 fn test_extract_payload_from_cose_mac_fails_malformed_payload() -> Result<()> {
911 let payload = Value::Bytes(vec![5; 10]);
912 let cose_mac0 =
913 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
914 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
915 &serde_cbor::to_vec(&cose_mac0)?,
916 );
917 assert!(extracted_payload.is_err());
918 Ok(())
919 }
920
921 #[test]
922 fn test_extract_payload_from_cose_mac_fails_type() -> Result<()> {
923 let payload = Value::Integer(1);
924 let cose_mac0 =
925 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
926 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
927 &serde_cbor::to_vec(&cose_mac0)?,
928 );
929 assert!(extracted_payload.is_err());
930 Ok(())
931 }
932
933 #[test]
934 fn test_extract_payload_from_cose_mac_fails_length() -> Result<()> {
935 let cose_mac0 = Value::Array(vec![Value::Integer(0), Value::Integer(1)]);
936 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
937 &serde_cbor::to_vec(&cose_mac0)?,
938 );
939 assert!(extracted_payload.is_err());
940 Ok(())
941 }
Seth Moore7ee79f92021-12-07 11:42:49 -0800942
943 #[test]
944 #[ignore] // b/215746308
945 fn test_get_attestation_key_no_keys_provisioned() {
946 let mut db = crate::database::tests::new_test_db().unwrap();
947 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
948 mock_rpc.0.lock().unwrap().hw_info.uniqueId = Some(String::from("mallory"));
949
Seth Moore92648b62022-02-02 13:26:18 -0800950 let mut service: RemotelyProvisionedKeyPoolService = Default::default();
Seth Moore7ee79f92021-12-07 11:42:49 -0800951 service
Seth Moore92648b62022-02-02 13:26:18 -0800952 .unique_id_to_sec_level
953 .insert(String::from("mallory"), SecurityLevel::TRUSTED_ENVIRONMENT);
Seth Moore7ee79f92021-12-07 11:42:49 -0800954
955 assert_eq!(
956 service
957 .get_attestation_key(&mut db, 0, "mallory")
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() {
968 let mut db = crate::database::tests::new_test_db().unwrap();
969 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
970 let irpc_id = "paul";
971 let caller_uid = 0;
972
973 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
974 let mock_values = mock_rpc.0.clone();
Seth Moore92648b62022-02-02 13:26:18 -0800975 let mut remote_provisioning: RemoteProvisioningService = Default::default();
976 remote_provisioning.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
977 let mut key_pool: RemotelyProvisionedKeyPoolService = Default::default();
978 key_pool.unique_id_to_sec_level.insert(String::from(irpc_id), sec_level);
Seth Moore7ee79f92021-12-07 11:42:49 -0800979
980 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
981 mock_values.lock().unwrap().private_key = vec![8, 6, 7, 5, 3, 0, 9];
982 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
Seth Moore92648b62022-02-02 13:26:18 -0800983 remote_provisioning.generate_key_pair(&mut db, true, sec_level).unwrap();
Seth Moore7ee79f92021-12-07 11:42:49 -0800984
985 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
986 mock_values.lock().unwrap().maced_public_key.as_slice(),
987 )
988 .unwrap();
989 let batch_cert = get_fake_cert();
990 let certs = &[5, 6, 7, 8];
Seth Moore92648b62022-02-02 13:26:18 -0800991 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -0800992 .provision_cert_chain(
993 &mut db,
994 public_key.as_slice(),
995 batch_cert.as_slice(),
996 certs,
997 0,
998 sec_level
999 )
1000 .is_ok());
1001
1002 // ensure we got the key we expected
Seth Moore92648b62022-02-02 13:26:18 -08001003 let first_key = key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001004 .get_attestation_key(&mut db, caller_uid, irpc_id)
1005 .context("get first key")
1006 .unwrap();
1007 assert_eq!(first_key.keyBlob, mock_values.lock().unwrap().private_key);
1008 assert_eq!(first_key.encodedCertChain, certs);
1009
1010 // ensure that multiple calls get the same key
1011 assert_eq!(
1012 first_key,
Seth Moore92648b62022-02-02 13:26:18 -08001013 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001014 .get_attestation_key(&mut db, caller_uid, irpc_id)
1015 .context("get second key")
1016 .unwrap()
1017 );
1018
1019 // no more keys for new clients
1020 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -08001021 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001022 .get_attestation_key(&mut db, caller_uid + 1, irpc_id)
1023 .unwrap_err()
1024 .downcast::<error::Error>()
1025 .unwrap(),
1026 error::Error::Rc(ResponseCode::OUT_OF_KEYS)
1027 );
1028 }
1029
1030 #[test]
1031 #[ignore] // b/215746308
1032 fn test_get_attestation_key_gets_different_key_for_different_client() {
1033 let mut db = crate::database::tests::new_test_db().unwrap();
1034 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
1035 let irpc_id = "ringo";
1036 let first_caller = 0;
1037 let second_caller = first_caller + 1;
1038
1039 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
1040 let mock_values = mock_rpc.0.clone();
Seth Moore92648b62022-02-02 13:26:18 -08001041 let mut remote_provisioning: RemoteProvisioningService = Default::default();
1042 remote_provisioning.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
1043 let mut key_pool: RemotelyProvisionedKeyPoolService = Default::default();
1044 key_pool.unique_id_to_sec_level.insert(String::from(irpc_id), sec_level);
Seth Moore7ee79f92021-12-07 11:42:49 -08001045
1046 // generate two distinct keys and provision them with certs
1047 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
1048 mock_values.lock().unwrap().private_key = vec![3, 1, 4, 1, 5];
1049 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
Seth Moore92648b62022-02-02 13:26:18 -08001050 assert!(remote_provisioning.generate_key_pair(&mut db, true, sec_level).is_ok());
Seth Moore7ee79f92021-12-07 11:42:49 -08001051 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
1052 mock_values.lock().unwrap().maced_public_key.as_slice(),
1053 )
1054 .unwrap();
Seth Moore92648b62022-02-02 13:26:18 -08001055 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -08001056 .provision_cert_chain(
1057 &mut db,
1058 public_key.as_slice(),
1059 get_fake_cert().as_slice(),
1060 &[1],
1061 0,
1062 sec_level
1063 )
1064 .is_ok());
1065
1066 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
1067 mock_values.lock().unwrap().private_key = vec![9, 0, 2, 1, 0];
1068 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x22);
Seth Moore92648b62022-02-02 13:26:18 -08001069 assert!(remote_provisioning.generate_key_pair(&mut db, true, sec_level).is_ok());
Seth Moore7ee79f92021-12-07 11:42:49 -08001070 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
1071 mock_values.lock().unwrap().maced_public_key.as_slice(),
1072 )
1073 .unwrap();
Seth Moore92648b62022-02-02 13:26:18 -08001074 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -08001075 .provision_cert_chain(
1076 &mut db,
1077 public_key.as_slice(),
1078 get_fake_cert().as_slice(),
1079 &[2],
1080 0,
1081 sec_level
1082 )
1083 .is_ok());
1084
1085 // make sure each caller gets a distinct key
1086 assert_ne!(
Seth Moore92648b62022-02-02 13:26:18 -08001087 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001088 .get_attestation_key(&mut db, first_caller, irpc_id)
1089 .context("get first key")
1090 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001091 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001092 .get_attestation_key(&mut db, second_caller, irpc_id)
1093 .context("get second key")
1094 .unwrap()
1095 );
1096
1097 // repeated calls should return the same key for a given caller
1098 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -08001099 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001100 .get_attestation_key(&mut db, first_caller, irpc_id)
1101 .context("first caller a")
1102 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001103 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001104 .get_attestation_key(&mut db, first_caller, irpc_id)
1105 .context("first caller b")
1106 .unwrap(),
1107 );
1108
1109 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -08001110 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001111 .get_attestation_key(&mut db, second_caller, irpc_id)
1112 .context("second caller a")
1113 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001114 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001115 .get_attestation_key(&mut db, second_caller, irpc_id)
1116 .context("second caller b")
1117 .unwrap()
1118 );
1119 }
Max Bires48fc2e52021-11-17 10:13:04 -08001120}