blob: 0331295e2b7785132eeb30eb7a37f992316fed83 [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};
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +000051use crate::ks_err;
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000052use crate::metrics_store::log_rkp_error_stats;
Seth Moore7ee79f92021-12-07 11:42:49 -080053use crate::permission::KeystorePerm;
54use crate::utils::{check_keystore_permission, watchdog as wd};
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000055use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
Max Bires148c08e2020-10-13 13:41:41 -070056
Max Bires97f96812021-02-23 23:44:57 -080057/// Contains helper functions to check if remote provisioning is enabled on the system and, if so,
58/// to assign and retrieve attestation keys and certificate chains.
59#[derive(Default)]
60pub struct RemProvState {
61 security_level: SecurityLevel,
62 km_uuid: Uuid,
63 is_hal_present: AtomicBool,
64}
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 {
Seth Mooredfdcb872022-04-20 14:33:19 -070074 Self { security_level, km_uuid, is_hal_present: AtomicBool::new(true) }
Max Bires97f96812021-02-23 23:44:57 -080075 }
76
Max Bires55620ff2022-02-11 13:34:15 -080077 /// Returns the uuid for the KM instance attached to this RemProvState struct.
78 pub fn get_uuid(&self) -> Uuid {
79 self.km_uuid
80 }
81
Seth Mooredfdcb872022-04-20 14:33:19 -070082 fn is_rkp_only(&self) -> bool {
Max Bires65207b52022-03-29 23:58:08 -070083 let default_value = false;
84
Seth Mooredfdcb872022-04-20 14:33:19 -070085 let property_name = match self.security_level {
86 SecurityLevel::STRONGBOX => "remote_provisioning.strongbox.rkp_only",
87 SecurityLevel::TRUSTED_ENVIRONMENT => "remote_provisioning.tee.rkp_only",
Max Bires65207b52022-03-29 23:58:08 -070088 _ => return default_value,
89 };
90
91 rustutils::system_properties::read_bool(property_name, default_value)
92 .unwrap_or(default_value)
93 }
94
Max Bires97f96812021-02-23 23:44:57 -080095 /// Checks if remote provisioning is enabled and partially caches the result. On a hybrid system
96 /// remote provisioning can flip from being disabled to enabled depending on responses from the
97 /// server, so unfortunately caching the presence or absence of the HAL is not enough to fully
98 /// make decisions about the state of remote provisioning during runtime.
99 fn check_rem_prov_enabled(&self, db: &mut KeystoreDB) -> Result<bool> {
Seth Mooredfdcb872022-04-20 14:33:19 -0700100 if self.is_rkp_only() {
Seth Moore562aebb2022-04-18 17:03:27 -0700101 return Ok(true);
102 }
Max Bires97f96812021-02-23 23:44:57 -0800103 if !self.is_hal_present.load(Ordering::Relaxed)
104 || get_remotely_provisioned_component(&self.security_level).is_err()
105 {
106 self.is_hal_present.store(false, Ordering::Relaxed);
107 return Ok(false);
108 }
109 // To check if remote provisioning is enabled on a system that supports both remote
110 // provisioning and factory provisioned keys, we only need to check if there are any
111 // keys at all generated to indicate if the app has gotten the signal to begin filling
112 // the key pool from the server.
113 let pool_status = db
114 .get_attestation_pool_status(0 /* date */, &self.km_uuid)
115 .context("In check_rem_prov_enabled: failed to get attestation pool status.")?;
116 Ok(pool_status.total != 0)
117 }
118
Max Bires97f96812021-02-23 23:44:57 -0800119 fn is_asymmetric_key(&self, params: &[KeyParameter]) -> bool {
120 params.iter().any(|kp| {
121 matches!(
122 kp,
123 KeyParameter {
124 tag: Tag::ALGORITHM,
125 value: KeyParameterValue::Algorithm(Algorithm::RSA)
126 } | KeyParameter {
127 tag: Tag::ALGORITHM,
128 value: KeyParameterValue::Algorithm(Algorithm::EC)
129 }
130 )
131 })
132 }
133
134 /// Checks to see (1) if the key in question should be attested to based on the algorithm and
135 /// (2) if remote provisioning is present and enabled on the system. If these conditions are
136 /// met, it makes an attempt to fetch the attestation key assigned to the `caller_uid`.
137 ///
138 /// It returns the ResponseCode `OUT_OF_KEYS` if there is not one key currently assigned to the
139 /// `caller_uid` and there are none available to assign.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700140 pub fn get_remotely_provisioned_attestation_key_and_certs(
Max Bires97f96812021-02-23 23:44:57 -0800141 &self,
142 key: &KeyDescriptor,
143 caller_uid: u32,
144 params: &[KeyParameter],
145 db: &mut KeystoreDB,
Max Bires55620ff2022-02-11 13:34:15 -0800146 ) -> Result<Option<(KeyIdGuard, AttestationKey, Certificate)>> {
Max Bires97f96812021-02-23 23:44:57 -0800147 if !self.is_asymmetric_key(params) || !self.check_rem_prov_enabled(db)? {
148 // There is no remote provisioning component for this security level on the
149 // device. Return None so the underlying KM instance knows to use its
150 // factory provisioned key instead. Alternatively, it's not an asymmetric key
151 // and therefore will not be attested.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700152 Ok(None)
Max Bires97f96812021-02-23 23:44:57 -0800153 } else {
Seth Moore7ee79f92021-12-07 11:42:49 -0800154 match get_rem_prov_attest_key(key.domain, caller_uid, db, &self.km_uuid) {
Max Bires31cdfb82021-07-06 02:59:25 -0700155 Err(e) => {
156 log::error!(
Max Bires65207b52022-03-29 23:58:08 -0700157 "In get_remote_provisioning_key_and_certs: Error occurred: {:?}",
Max Bires31cdfb82021-07-06 02:59:25 -0700158 e
159 );
Seth Mooredfdcb872022-04-20 14:33:19 -0700160 if self.is_rkp_only() {
Max Bires65207b52022-03-29 23:58:08 -0700161 return Err(e);
162 }
Shaquille Johnsonbcab6012022-09-02 11:16:24 +0000163 log_rkp_error_stats(
164 MetricsRkpError::FALL_BACK_DURING_HYBRID,
165 &self.security_level,
166 );
Max Bires31cdfb82021-07-06 02:59:25 -0700167 Ok(None)
168 }
169 Ok(v) => match v {
Max Bires55620ff2022-02-11 13:34:15 -0800170 Some((guard, cert_chain)) => Ok(Some((
171 guard,
Max Bires31cdfb82021-07-06 02:59:25 -0700172 AttestationKey {
173 keyBlob: cert_chain.private_key.to_vec(),
174 attestKeyParams: vec![],
175 issuerSubjectName: parse_subject_from_certificate(
176 &cert_chain.batch_cert,
177 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000178 .context(ks_err!("Failed to parse subject."))?,
Max Bires31cdfb82021-07-06 02:59:25 -0700179 },
180 Certificate { encodedCertificate: cert_chain.cert_chain },
181 ))),
182 None => Ok(None),
183 },
Max Bires97f96812021-02-23 23:44:57 -0800184 }
185 }
186 }
187}
Max Bires148c08e2020-10-13 13:41:41 -0700188/// Implementation of the IRemoteProvisioning service.
Max Biresb2e1d032021-02-08 21:35:05 -0800189#[derive(Default)]
Max Bires148c08e2020-10-13 13:41:41 -0700190pub struct RemoteProvisioningService {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -0700191 device_by_sec_level: HashMap<SecurityLevel, Strong<dyn IRemotelyProvisionedComponent>>,
Max Biresd2ce46b2021-07-06 02:54:47 -0700192 curve_by_sec_level: HashMap<SecurityLevel, i32>,
Max Bires148c08e2020-10-13 13:41:41 -0700193}
194
195impl RemoteProvisioningService {
Max Biresb2e1d032021-02-08 21:35:05 -0800196 fn get_dev_by_sec_level(
197 &self,
198 sec_level: &SecurityLevel,
Seth Moore7ee79f92021-12-07 11:42:49 -0800199 ) -> Result<&dyn IRemotelyProvisionedComponent> {
Max Biresb2e1d032021-02-08 21:35:05 -0800200 if let Some(dev) = self.device_by_sec_level.get(sec_level) {
Seth Moore7ee79f92021-12-07 11:42:49 -0800201 Ok(dev.as_ref())
Max Biresb2e1d032021-02-08 21:35:05 -0800202 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000203 Err(error::Error::sys()).context(ks_err!(
204 "Remote instance for requested security level \
205 not found.",
Max Biresb2e1d032021-02-08 21:35:05 -0800206 ))
207 }
208 }
209
Max Bires148c08e2020-10-13 13:41:41 -0700210 /// Creates a new instance of the remote provisioning service
Stephen Crane221bbb52020-12-16 15:52:10 -0800211 pub fn new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800212 let mut result: Self = Default::default();
213 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000214 .context(ks_err!("Failed to get TEE Remote Provisioner instance."))?;
Max Biresd2ce46b2021-07-06 02:54:47 -0700215 result.curve_by_sec_level.insert(
216 SecurityLevel::TRUSTED_ENVIRONMENT,
217 dev.getHardwareInfo()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000218 .context(ks_err!("Failed to get hardware info for the TEE."))?
Max Biresd2ce46b2021-07-06 02:54:47 -0700219 .supportedEekCurve,
220 );
Max Biresb2e1d032021-02-08 21:35:05 -0800221 result.device_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, dev);
222 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
Max Biresd2ce46b2021-07-06 02:54:47 -0700223 result.curve_by_sec_level.insert(
224 SecurityLevel::STRONGBOX,
225 dev.getHardwareInfo()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000226 .context(ks_err!("Failed to get hardware info for StrongBox."))?
Max Biresd2ce46b2021-07-06 02:54:47 -0700227 .supportedEekCurve,
228 );
Max Biresb2e1d032021-02-08 21:35:05 -0800229 result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
230 }
Andrew Walbrande45c8b2021-04-13 14:42:38 +0000231 Ok(BnRemoteProvisioning::new_binder(result, BinderFeatures::default()))
Max Bires148c08e2020-10-13 13:41:41 -0700232 }
233
Max Bires48fc2e52021-11-17 10:13:04 -0800234 fn extract_payload_from_cose_mac(data: &[u8]) -> Result<Value> {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000235 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data)
236 .context(ks_err!("COSE_Mac0 returned from IRPC cannot be parsed"))?;
Max Bires48fc2e52021-11-17 10:13:04 -0800237 if cose_mac0.len() != COSE_MAC0_LEN {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000238 return Err(error::Error::sys()).context(ks_err!(
239 "COSE_Mac0 has improper length. \
Max Bires48fc2e52021-11-17 10:13:04 -0800240 Expected: {}, Actual: {}",
241 COSE_MAC0_LEN,
242 cose_mac0.len(),
243 ));
244 }
245 match &cose_mac0[COSE_MAC0_PAYLOAD] {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000246 Value::Bytes(key) => {
247 Ok(serde_cbor::from_slice(key)
248 .context(ks_err!("COSE_Mac0 payload is malformed."))?)
249 }
250 _ => {
251 Err(error::Error::sys()).context(ks_err!("COSE_Mac0 payload is the wrong type."))?
252 }
Max Bires48fc2e52021-11-17 10:13:04 -0800253 }
254 }
255
Max Bires148c08e2020-10-13 13:41:41 -0700256 /// Generates a CBOR blob which will be assembled by the calling code into a larger
257 /// CBOR blob intended for delivery to a provisioning serever. This blob will contain
258 /// `num_csr` certificate signing requests for attestation keys generated in the TEE,
259 /// along with a server provided `eek` and `challenge`. The endpoint encryption key will
260 /// be used to encrypt the sensitive contents being transmitted to the server, and the
261 /// challenge will ensure freshness. A `test_mode` flag will instruct the remote provisioning
262 /// HAL if it is okay to accept EEKs that aren't signed by something that chains back to the
263 /// baked in root of trust in the underlying IRemotelyProvisionedComponent instance.
Max Bires834dd362021-03-23 13:01:57 -0700264 #[allow(clippy::too_many_arguments)]
Max Bires148c08e2020-10-13 13:41:41 -0700265 pub fn generate_csr(
266 &self,
Max Biresb2e1d032021-02-08 21:35:05 -0800267 test_mode: bool,
268 num_csr: i32,
269 eek: &[u8],
270 challenge: &[u8],
271 sec_level: SecurityLevel,
272 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700273 device_info: &mut DeviceInfo,
Max Bires148c08e2020-10-13 13:41:41 -0700274 ) -> Result<Vec<u8>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800275 let dev = self.get_dev_by_sec_level(&sec_level)?;
276 let (_, _, uuid) = get_keymint_device(&sec_level)?;
277 let keys_to_sign = DB.with::<_, Result<Vec<MacedPublicKey>>>(|db| {
278 let mut db = db.borrow_mut();
279 Ok(db
280 .fetch_unsigned_attestation_keys(num_csr, &uuid)?
281 .iter()
282 .map(|key| MacedPublicKey { macedKey: key.to_vec() })
283 .collect())
284 })?;
Max Bires48fc2e52021-11-17 10:13:04 -0800285 let mac = map_rem_prov_error(dev.generateCertificateRequest(
Max Biresb2e1d032021-02-08 21:35:05 -0800286 test_mode,
287 &keys_to_sign,
288 eek,
289 challenge,
Max Bires834dd362021-03-23 13:01:57 -0700290 device_info,
Max Biresb2e1d032021-02-08 21:35:05 -0800291 protected_data,
292 ))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000293 .context(ks_err!("Failed to generate csr"))?;
Max Bires48fc2e52021-11-17 10:13:04 -0800294 let mut mac_and_keys: Vec<Value> = vec![Value::from(mac)];
Max Bires97f96812021-02-23 23:44:57 -0800295 for maced_public_key in keys_to_sign {
Max Bires48fc2e52021-11-17 10:13:04 -0800296 mac_and_keys.push(
297 Self::extract_payload_from_cose_mac(&maced_public_key.macedKey)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000298 .context(ks_err!("Failed to get the payload from the COSE_Mac0"))?,
Max Bires48fc2e52021-11-17 10:13:04 -0800299 )
Max Bires97f96812021-02-23 23:44:57 -0800300 }
Max Bires48fc2e52021-11-17 10:13:04 -0800301 let cbor_array: Value = Value::Array(mac_and_keys);
302 serde_cbor::to_vec(&cbor_array)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000303 .context(ks_err!("Failed to serialize the mac and keys array"))
Max Bires148c08e2020-10-13 13:41:41 -0700304 }
305
306 /// Provisions a certificate chain for a key whose CSR was included in generate_csr. The
307 /// `public_key` is used to index into the SQL database in order to insert the `certs` blob
308 /// which represents a PEM encoded X.509 certificate chain. The `expiration_date` is provided
309 /// as a convenience from the caller to avoid having to parse the certificates semantically
310 /// here.
311 pub fn provision_cert_chain(
312 &self,
Seth Moore7ee79f92021-12-07 11:42:49 -0800313 db: &mut KeystoreDB,
Max Bires148c08e2020-10-13 13:41:41 -0700314 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800315 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700316 certs: &[u8],
317 expiration_date: i64,
318 sec_level: SecurityLevel,
319 ) -> Result<()> {
Seth Moore7ee79f92021-12-07 11:42:49 -0800320 let (_, _, uuid) = get_keymint_device(&sec_level)?;
321 db.store_signed_attestation_certificate_chain(
322 public_key,
323 batch_cert,
324 certs, /* DER encoded certificate chain */
325 expiration_date,
326 &uuid,
327 )
Max Bires148c08e2020-10-13 13:41:41 -0700328 }
329
Max Bires48fc2e52021-11-17 10:13:04 -0800330 fn parse_cose_mac0_for_coords(data: &[u8]) -> Result<Vec<u8>> {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000331 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data)
332 .context(ks_err!("COSE_Mac0 returned from IRPC cannot be parsed"))?;
Max Bires48fc2e52021-11-17 10:13:04 -0800333 if cose_mac0.len() != COSE_MAC0_LEN {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000334 return Err(error::Error::sys()).context(ks_err!(
335 "COSE_Mac0 has improper length. \
Max Bires48fc2e52021-11-17 10:13:04 -0800336 Expected: {}, Actual: {}",
337 COSE_MAC0_LEN,
338 cose_mac0.len(),
339 ));
340 }
341 let cose_key: BTreeMap<Value, Value> = match &cose_mac0[COSE_MAC0_PAYLOAD] {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000342 Value::Bytes(key) => {
343 serde_cbor::from_slice(key).context(ks_err!("COSE_Key is malformed."))?
344 }
345 _ => {
346 Err(error::Error::sys()).context(ks_err!("COSE_Mac0 payload is the wrong type."))?
347 }
Max Bires48fc2e52021-11-17 10:13:04 -0800348 };
349 if !cose_key.contains_key(&COSE_KEY_XCOORD) || !cose_key.contains_key(&COSE_KEY_YCOORD) {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000350 return Err(error::Error::sys())
351 .context(ks_err!("COSE_Key returned from IRPC is lacking required fields"));
Max Bires48fc2e52021-11-17 10:13:04 -0800352 }
353 let mut raw_key: Vec<u8> = vec![0; 64];
354 match &cose_key[&COSE_KEY_XCOORD] {
355 Value::Bytes(x_coord) if x_coord.len() == 32 => {
356 raw_key[0..32].clone_from_slice(x_coord)
357 }
358 Value::Bytes(x_coord) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000359 return Err(error::Error::sys()).context(ks_err!(
360 "COSE_Key X-coordinate is not the right length. \
Max Bires48fc2e52021-11-17 10:13:04 -0800361 Expected: 32; Actual: {}",
362 x_coord.len()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000363 ));
Max Bires48fc2e52021-11-17 10:13:04 -0800364 }
365 _ => {
366 return Err(error::Error::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000367 .context(ks_err!("COSE_Key X-coordinate is not a bstr"));
Max Bires48fc2e52021-11-17 10:13:04 -0800368 }
369 }
370 match &cose_key[&COSE_KEY_YCOORD] {
371 Value::Bytes(y_coord) if y_coord.len() == 32 => {
372 raw_key[32..64].clone_from_slice(y_coord)
373 }
374 Value::Bytes(y_coord) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000375 return Err(error::Error::sys()).context(ks_err!(
376 "COSE_Key Y-coordinate is not the right length. \
Max Bires48fc2e52021-11-17 10:13:04 -0800377 Expected: 32; Actual: {}",
378 y_coord.len()
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000379 ));
Max Bires48fc2e52021-11-17 10:13:04 -0800380 }
381 _ => {
382 return Err(error::Error::sys())
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000383 .context(ks_err!("COSE_Key Y-coordinate is not a bstr"));
Max Bires48fc2e52021-11-17 10:13:04 -0800384 }
385 }
386 Ok(raw_key)
387 }
388
Max Bires148c08e2020-10-13 13:41:41 -0700389 /// Submits a request to the Remote Provisioner HAL to generate a signing key pair.
390 /// `is_test_mode` indicates whether or not the returned public key should be marked as being
391 /// for testing in order to differentiate them from private keys. If the call is successful,
392 /// the key pair is then added to the database.
Seth Moore7ee79f92021-12-07 11:42:49 -0800393 pub fn generate_key_pair(
394 &self,
395 db: &mut KeystoreDB,
396 is_test_mode: bool,
397 sec_level: SecurityLevel,
398 ) -> Result<()> {
Max Biresb2e1d032021-02-08 21:35:05 -0800399 let (_, _, uuid) = get_keymint_device(&sec_level)?;
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000400 let dev = self
401 .get_dev_by_sec_level(&sec_level)
402 .context(ks_err!("Failed to get device for security level {:?}", sec_level))?;
Max Biresb2e1d032021-02-08 21:35:05 -0800403 let mut maced_key = MacedPublicKey { macedKey: Vec::new() };
404 let priv_key =
405 map_rem_prov_error(dev.generateEcdsaP256KeyPair(is_test_mode, &mut maced_key))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000406 .context(ks_err!("Failed to generated ECDSA keypair."))?;
Max Bires48fc2e52021-11-17 10:13:04 -0800407 let raw_key = Self::parse_cose_mac0_for_coords(&maced_key.macedKey)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000408 .context(ks_err!("Failed to parse raw key"))?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800409 db.create_attestation_key_entry(&maced_key.macedKey, &raw_key, &priv_key, &uuid)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000410 .context(ks_err!("Failed to insert attestation key entry"))
Max Biresb2e1d032021-02-08 21:35:05 -0800411 }
412
413 /// Checks the security level of each available IRemotelyProvisionedComponent hal and returns
414 /// all levels in an array to the caller.
Max Biresd2ce46b2021-07-06 02:54:47 -0700415 pub fn get_implementation_info(&self) -> Result<Vec<ImplInfo>> {
416 Ok(self
417 .curve_by_sec_level
418 .iter()
419 .map(|(sec_level, curve)| ImplInfo { secLevel: *sec_level, supportedCurve: *curve })
420 .collect())
Max Bires148c08e2020-10-13 13:41:41 -0700421 }
Max Bires60d7ed12021-03-05 15:59:22 -0800422
423 /// Deletes all attestation keys generated by the IRemotelyProvisionedComponent from the device,
424 /// regardless of what state of the attestation key lifecycle they were in.
425 pub fn delete_all_keys(&self) -> Result<i64> {
426 DB.with::<_, Result<i64>>(|db| {
427 let mut db = db.borrow_mut();
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700428 db.delete_all_attestation_keys()
Max Bires60d7ed12021-03-05 15:59:22 -0800429 })
430 }
Max Bires148c08e2020-10-13 13:41:41 -0700431}
432
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000433/// Populates the AttestationPoolStatus parcelable with information about how many
434/// certs will be expiring by the date provided in `expired_by` along with how many
435/// keys have not yet been assigned.
436pub fn get_pool_status(expired_by: i64, sec_level: SecurityLevel) -> Result<AttestationPoolStatus> {
437 let (_, _, uuid) = get_keymint_device(&sec_level)?;
438 DB.with::<_, Result<AttestationPoolStatus>>(|db| {
439 let mut db = db.borrow_mut();
440 // delete_expired_attestation_keys is always safe to call, and will remove anything
441 // older than the date at the time of calling. No work should be done on the
442 // attestation keys unless the pool status is checked first, so this call should be
443 // enough to routinely clean out expired keys.
444 db.delete_expired_attestation_keys()?;
445 db.get_attestation_pool_status(expired_by, &uuid)
446 })
447}
448
Seth Moore7ee79f92021-12-07 11:42:49 -0800449/// Fetches a remote provisioning attestation key and certificate chain inside of the
450/// returned `CertificateChain` struct if one exists for the given caller_uid. If one has not
451/// been assigned, this function will assign it. If there are no signed attestation keys
452/// available to be assigned, it will return the ResponseCode `OUT_OF_KEYS`
453fn get_rem_prov_attest_key(
454 domain: Domain,
455 caller_uid: u32,
456 db: &mut KeystoreDB,
457 km_uuid: &Uuid,
Max Bires55620ff2022-02-11 13:34:15 -0800458) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
Seth Moore7ee79f92021-12-07 11:42:49 -0800459 match domain {
460 Domain::APP => {
461 // Attempt to get an Attestation Key once. If it fails, then the app doesn't
462 // have a valid chain assigned to it. The helper function will return None after
463 // attempting to assign a key. An error will be thrown if the pool is simply out
464 // of usable keys. Then another attempt to fetch the just-assigned key will be
465 // made. If this fails too, something is very wrong.
466 get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid)
467 .context("In get_rem_prov_attest_key: Failed to get a key")?
468 .map_or_else(
469 || get_rem_prov_attest_key_helper(domain, caller_uid, db, km_uuid),
470 |v| Ok(Some(v)),
471 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000472 .context(ks_err!(
473 "Failed to get a key after \
474 attempting to assign one.",
Seth Moore7ee79f92021-12-07 11:42:49 -0800475 ))?
476 .map_or_else(
477 || {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000478 Err(Error::sys()).context(ks_err!(
479 "Attempted to assign a \
480 key and failed silently. Something is very wrong.",
Seth Moore7ee79f92021-12-07 11:42:49 -0800481 ))
482 },
Max Bires55620ff2022-02-11 13:34:15 -0800483 |(guard, cert_chain)| Ok(Some((guard, cert_chain))),
Seth Moore7ee79f92021-12-07 11:42:49 -0800484 )
485 }
486 _ => Ok(None),
487 }
488}
489
490/// Returns None if an AttestationKey fails to be assigned. Errors if no keys are available.
491fn get_rem_prov_attest_key_helper(
492 domain: Domain,
493 caller_uid: u32,
494 db: &mut KeystoreDB,
495 km_uuid: &Uuid,
Max Bires55620ff2022-02-11 13:34:15 -0800496) -> Result<Option<(KeyIdGuard, CertificateChain)>> {
497 let guard_and_chain = db
Seth Moore7ee79f92021-12-07 11:42:49 -0800498 .retrieve_attestation_key_and_cert_chain(domain, caller_uid as i64, km_uuid)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000499 .context(ks_err!("Failed to retrieve a key + cert chain"))?;
Max Bires55620ff2022-02-11 13:34:15 -0800500 match guard_and_chain {
501 Some((guard, cert_chain)) => Ok(Some((guard, cert_chain))),
Seth Moore7ee79f92021-12-07 11:42:49 -0800502 // Either this app needs to be assigned a key, or the pool is empty. An error will
503 // be thrown if there is no key available to assign. This will indicate that the app
504 // should be nudged to provision more keys so keystore can retry.
505 None => {
506 db.assign_attestation_key(domain, caller_uid as i64, km_uuid)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000507 .context(ks_err!("Failed to assign a key"))?;
Seth Moore7ee79f92021-12-07 11:42:49 -0800508 Ok(None)
509 }
510 }
511}
512
Max Bires148c08e2020-10-13 13:41:41 -0700513impl binder::Interface for RemoteProvisioningService {}
514
515// Implementation of IRemoteProvisioning. See AIDL spec at
516// :aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
517impl IRemoteProvisioning for RemoteProvisioningService {
518 fn getPoolStatus(
519 &self,
520 expired_by: i64,
521 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700522 ) -> binder::Result<AttestationPoolStatus> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000523 let _wp = wd::watch_millis("IRemoteProvisioning::getPoolStatus", 500);
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000524 map_or_log_err(get_pool_status(expired_by, sec_level), Ok)
Max Bires148c08e2020-10-13 13:41:41 -0700525 }
526
527 fn generateCsr(
528 &self,
529 test_mode: bool,
530 num_csr: i32,
531 eek: &[u8],
532 challenge: &[u8],
533 sec_level: SecurityLevel,
Max Biresb2e1d032021-02-08 21:35:05 -0800534 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700535 device_info: &mut DeviceInfo,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700536 ) -> binder::Result<Vec<u8>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000537 let _wp = wd::watch_millis("IRemoteProvisioning::generateCsr", 500);
Max Biresb2e1d032021-02-08 21:35:05 -0800538 map_or_log_err(
Max Bires834dd362021-03-23 13:01:57 -0700539 self.generate_csr(
540 test_mode,
541 num_csr,
542 eek,
543 challenge,
544 sec_level,
545 protected_data,
546 device_info,
547 ),
Max Biresb2e1d032021-02-08 21:35:05 -0800548 Ok,
549 )
Max Bires148c08e2020-10-13 13:41:41 -0700550 }
551
552 fn provisionCertChain(
553 &self,
554 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800555 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700556 certs: &[u8],
557 expiration_date: i64,
558 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700559 ) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000560 let _wp = wd::watch_millis("IRemoteProvisioning::provisionCertChain", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800561 DB.with::<_, binder::Result<()>>(|db| {
562 map_or_log_err(
563 self.provision_cert_chain(
564 &mut db.borrow_mut(),
565 public_key,
566 batch_cert,
567 certs,
568 expiration_date,
569 sec_level,
570 ),
571 Ok,
572 )
573 })
Max Bires148c08e2020-10-13 13:41:41 -0700574 }
575
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700576 fn generateKeyPair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000577 let _wp = wd::watch_millis("IRemoteProvisioning::generateKeyPair", 500);
Seth Moore7ee79f92021-12-07 11:42:49 -0800578 DB.with::<_, binder::Result<()>>(|db| {
579 map_or_log_err(
580 self.generate_key_pair(&mut db.borrow_mut(), is_test_mode, sec_level),
581 Ok,
582 )
583 })
Max Bires148c08e2020-10-13 13:41:41 -0700584 }
Max Biresb2e1d032021-02-08 21:35:05 -0800585
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700586 fn getImplementationInfo(&self) -> binder::Result<Vec<ImplInfo>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000587 let _wp = wd::watch_millis("IRemoteProvisioning::getSecurityLevels", 500);
Max Biresd2ce46b2021-07-06 02:54:47 -0700588 map_or_log_err(self.get_implementation_info(), Ok)
Max Biresb2e1d032021-02-08 21:35:05 -0800589 }
Max Bires60d7ed12021-03-05 15:59:22 -0800590
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700591 fn deleteAllKeys(&self) -> binder::Result<i64> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000592 let _wp = wd::watch_millis("IRemoteProvisioning::deleteAllKeys", 500);
Max Bires60d7ed12021-03-05 15:59:22 -0800593 map_or_log_err(self.delete_all_keys(), Ok)
594 }
Max Bires148c08e2020-10-13 13:41:41 -0700595}
Max Bires48fc2e52021-11-17 10:13:04 -0800596
Seth Moore92648b62022-02-02 13:26:18 -0800597/// Implementation of the IRemotelyProvisionedKeyPool service.
598#[derive(Default)]
599pub struct RemotelyProvisionedKeyPoolService {
600 unique_id_to_sec_level: HashMap<String, SecurityLevel>,
601}
602
603impl RemotelyProvisionedKeyPoolService {
604 /// Fetches a remotely provisioned certificate chain and key for the given client uid that
605 /// was provisioned using the IRemotelyProvisionedComponent with the given id. The same key
606 /// will be returned for a given caller_uid on every request. If there are no attestation keys
607 /// available, `OUT_OF_KEYS` is returned.
608 fn get_attestation_key(
609 &self,
610 db: &mut KeystoreDB,
611 caller_uid: i32,
612 irpc_id: &str,
613 ) -> Result<RemotelyProvisionedKey> {
614 log::info!("get_attestation_key(self, {}, {}", caller_uid, irpc_id);
615
616 let sec_level = self
617 .unique_id_to_sec_level
618 .get(irpc_id)
619 .ok_or(Error::Rc(ResponseCode::INVALID_ARGUMENT))
620 .context(format!("In get_attestation_key: unknown irpc id '{}'", irpc_id))?;
621 let (_, _, km_uuid) = get_keymint_device(sec_level)?;
622
Max Bires55620ff2022-02-11 13:34:15 -0800623 let guard_and_cert_chain =
624 get_rem_prov_attest_key(Domain::APP, caller_uid as u32, db, &km_uuid)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000625 .context(ks_err!())?;
Max Bires55620ff2022-02-11 13:34:15 -0800626 match guard_and_cert_chain {
627 Some((_, chain)) => Ok(RemotelyProvisionedKey {
Seth Moore92648b62022-02-02 13:26:18 -0800628 keyBlob: chain.private_key.to_vec(),
629 encodedCertChain: chain.cert_chain,
630 }),
631 // It should be impossible to get `None`, but handle it just in case as a
632 // precaution against future behavioral changes in `get_rem_prov_attest_key`.
633 None => Err(error::Error::Rc(ResponseCode::OUT_OF_KEYS))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000634 .context(ks_err!("No available attestation keys")),
Seth Moore92648b62022-02-02 13:26:18 -0800635 }
636 }
637
638 /// Creates a new instance of the remotely provisioned key pool service, used for fetching
639 /// remotely provisioned attestation keys.
640 pub fn new_native_binder() -> Result<Strong<dyn IRemotelyProvisionedKeyPool>> {
641 let mut result: Self = Default::default();
642
643 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000644 .context(ks_err!("Failed to get TEE Remote Provisioner instance."))?;
Seth Moore92648b62022-02-02 13:26:18 -0800645 if let Some(id) = dev.getHardwareInfo()?.uniqueId {
646 result.unique_id_to_sec_level.insert(id, SecurityLevel::TRUSTED_ENVIRONMENT);
647 }
648
649 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
650 if let Some(id) = dev.getHardwareInfo()?.uniqueId {
651 if result.unique_id_to_sec_level.contains_key(&id) {
652 anyhow::bail!("In new_native_binder: duplicate irpc id found: '{}'", id)
653 }
654 result.unique_id_to_sec_level.insert(id, SecurityLevel::STRONGBOX);
655 }
656 }
657
658 // If none of the remotely provisioned components have unique ids, then we shouldn't
659 // bother publishing the service, as it's impossible to match keys with their backends.
660 if result.unique_id_to_sec_level.is_empty() {
661 anyhow::bail!(
662 "In new_native_binder: No remotely provisioned components have unique ids"
663 )
664 }
665
666 Ok(BnRemotelyProvisionedKeyPool::new_binder(
667 result,
668 BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
669 ))
670 }
671}
672
673impl binder::Interface for RemotelyProvisionedKeyPoolService {}
674
Seth Moore7ee79f92021-12-07 11:42:49 -0800675// Implementation of IRemotelyProvisionedKeyPool. See AIDL spec at
676// :aidl/android/security/remoteprovisioning/IRemotelyProvisionedKeyPool.aidl
Seth Moore92648b62022-02-02 13:26:18 -0800677impl IRemotelyProvisionedKeyPool for RemotelyProvisionedKeyPoolService {
Seth Moore7ee79f92021-12-07 11:42:49 -0800678 fn getAttestationKey(
679 &self,
680 caller_uid: i32,
681 irpc_id: &str,
682 ) -> binder::Result<RemotelyProvisionedKey> {
683 let _wp = wd::watch_millis("IRemotelyProvisionedKeyPool::getAttestationKey", 500);
684 map_or_log_err(check_keystore_permission(KeystorePerm::GetAttestationKey), Ok)?;
685 DB.with::<_, binder::Result<RemotelyProvisionedKey>>(|db| {
686 map_or_log_err(self.get_attestation_key(&mut db.borrow_mut(), caller_uid, irpc_id), Ok)
687 })
688 }
689}
690
Max Bires48fc2e52021-11-17 10:13:04 -0800691#[cfg(test)]
692mod tests {
693 use super::*;
694 use serde_cbor::Value;
695 use std::collections::BTreeMap;
Seth Moore7ee79f92021-12-07 11:42:49 -0800696 use std::sync::{Arc, Mutex};
697 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
698 RpcHardwareInfo::RpcHardwareInfo,
699 };
700
701 #[derive(Default)]
702 struct MockRemotelyProvisionedComponentValues {
703 hw_info: RpcHardwareInfo,
704 private_key: Vec<u8>,
705 maced_public_key: Vec<u8>,
706 }
707
708 // binder::Interface requires the Send trait, so we have to use a Mutex even though the test
709 // is single threaded.
710 #[derive(Default)]
711 struct MockRemotelyProvisionedComponent(Arc<Mutex<MockRemotelyProvisionedComponentValues>>);
712
713 impl binder::Interface for MockRemotelyProvisionedComponent {}
714
715 impl IRemotelyProvisionedComponent for MockRemotelyProvisionedComponent {
716 fn getHardwareInfo(&self) -> binder::Result<RpcHardwareInfo> {
717 Ok(self.0.lock().unwrap().hw_info.clone())
718 }
719
720 fn generateEcdsaP256KeyPair(
721 &self,
722 test_mode: bool,
723 maced_public_key: &mut MacedPublicKey,
724 ) -> binder::Result<Vec<u8>> {
725 assert!(test_mode);
726 maced_public_key.macedKey = self.0.lock().unwrap().maced_public_key.clone();
727 Ok(self.0.lock().unwrap().private_key.clone())
728 }
729
730 fn generateCertificateRequest(
731 &self,
732 _test_mode: bool,
733 _keys_to_sign: &[MacedPublicKey],
734 _eek: &[u8],
735 _challenge: &[u8],
736 _device_info: &mut DeviceInfo,
737 _protected_data: &mut ProtectedData,
738 ) -> binder::Result<Vec<u8>> {
739 Err(binder::StatusCode::INVALID_OPERATION.into())
740 }
741 }
742
743 // Hard coded cert that can be parsed -- the content doesn't matter for testing, only that it's valid.
744 fn get_fake_cert() -> Vec<u8> {
745 vec![
746 0x30, 0x82, 0x01, 0xbb, 0x30, 0x82, 0x01, 0x61, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
747 0x14, 0x3a, 0xd5, 0x67, 0xce, 0xfe, 0x93, 0xe1, 0xea, 0xb7, 0xe4, 0xbf, 0x64, 0x19,
748 0xa4, 0x11, 0xe1, 0x87, 0x40, 0x20, 0x37, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
749 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
750 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
751 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
752 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
753 0x6c, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x32, 0x31, 0x30, 0x32, 0x32,
754 0x30, 0x38, 0x35, 0x32, 0x5a, 0x17, 0x0d, 0x34, 0x39, 0x30, 0x34, 0x32, 0x36, 0x32,
755 0x32, 0x30, 0x38, 0x35, 0x32, 0x5a, 0x30, 0x33, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
756 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x54, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
757 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
758 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f,
759 0x67, 0x6c, 0x65, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
760 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42,
761 0x00, 0x04, 0x1e, 0xac, 0x0c, 0xe0, 0x0d, 0xc5, 0x25, 0x84, 0x1b, 0xd2, 0x77, 0x2d,
762 0xe7, 0xba, 0xf1, 0xde, 0xa7, 0xf6, 0x39, 0x7f, 0x38, 0x91, 0xbf, 0xa4, 0x58, 0xf5,
763 0x62, 0x6b, 0xce, 0x06, 0xcf, 0xb9, 0x73, 0x91, 0x0d, 0x8a, 0x60, 0xa0, 0xc6, 0xa2,
764 0x22, 0xe6, 0x51, 0x2e, 0x58, 0xd6, 0x43, 0x02, 0x80, 0x43, 0x44, 0x29, 0x38, 0x9a,
765 0x99, 0xf3, 0xa4, 0xdd, 0xd0, 0xb4, 0x6f, 0x8b, 0x44, 0x2d, 0xa3, 0x53, 0x30, 0x51,
766 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xdb, 0x13, 0x68,
767 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe, 0x42, 0x3c, 0xd9, 0x3f, 0x1a,
768 0x33, 0xe9, 0xaa, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
769 0x80, 0x14, 0xdb, 0x13, 0x68, 0xe0, 0x0e, 0x47, 0x10, 0xf8, 0xcb, 0x88, 0x83, 0xfe,
770 0x42, 0x3c, 0xd9, 0x3f, 0x1a, 0x33, 0xe9, 0xaa, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
771 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06,
772 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45,
773 0x02, 0x20, 0x10, 0xdf, 0x40, 0xc3, 0x20, 0x54, 0x36, 0xb5, 0xc9, 0x3c, 0x70, 0xe3,
774 0x55, 0x37, 0xd2, 0x04, 0x51, 0xeb, 0x0f, 0x18, 0x83, 0xd0, 0x58, 0xa1, 0x08, 0x77,
775 0x8d, 0x4d, 0xa4, 0x20, 0xee, 0x33, 0x02, 0x21, 0x00, 0x8d, 0xe3, 0xa6, 0x6c, 0x0d,
776 0x86, 0x25, 0xdc, 0x59, 0x0d, 0x21, 0x43, 0x22, 0x3a, 0xb9, 0xa1, 0x73, 0x28, 0xc9,
777 0x16, 0x9e, 0x91, 0x15, 0xc4, 0xc3, 0xd7, 0xeb, 0xe5, 0xce, 0xdc, 0x1c, 0x1b,
778 ]
779 }
780
781 // Generate a fake COSE_Mac0 with a key that's just `byte` repeated
782 fn generate_maced_pubkey(byte: u8) -> Vec<u8> {
783 vec![
784 0x84, 0x43, 0xA1, 0x01, 0x05, 0xA0, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20,
785 0x01, 0x21, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
786 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
787 byte, byte, byte, byte, byte, byte, byte, byte, 0x22, 0x58, 0x20, byte, byte, byte,
788 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
789 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
790 byte, 0x58, 0x20, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
791 byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte,
792 byte, byte, byte, byte, byte, byte, byte,
793 ]
794 }
Max Bires48fc2e52021-11-17 10:13:04 -0800795
796 #[test]
797 fn test_parse_cose_mac0_for_coords_raw_bytes() -> Result<()> {
798 let cose_mac0: Vec<u8> = vec![
799 0x84, 0x01, 0x02, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
800 0x20, 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9,
801 0x21, 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C,
802 0x43, 0x22, 0xC8, 0xEE, 0x03, 0x22, 0x58, 0x20, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95,
803 0x90, 0xA7, 0x5C, 0x5A, 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A,
804 0xA3, 0xB3, 0x1A, 0xB4, 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC, 0x03,
805 ];
806 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&cose_mac0)?;
807 assert_eq!(
808 raw_key,
809 vec![
810 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9, 0x21,
811 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C, 0x43,
812 0x22, 0xC8, 0xEE, 0x03, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95, 0x90, 0xA7, 0x5C, 0x5A,
813 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A, 0xA3, 0xB3, 0x1A, 0xB4,
814 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC,
815 ]
816 );
817 Ok(())
818 }
819
820 #[test]
821 fn test_parse_cose_mac0_for_coords_constructed_mac() -> Result<()> {
822 let x_coord: Vec<u8> = vec![0; 32];
823 let y_coord: Vec<u8> = vec![1; 32];
824 let mut expected_key: Vec<u8> = Vec::new();
825 expected_key.extend(&x_coord);
826 expected_key.extend(&y_coord);
827 let key_map: BTreeMap<Value, Value> = BTreeMap::from([
828 (Value::Integer(1), Value::Integer(2)),
829 (Value::Integer(3), Value::Integer(-7)),
830 (Value::Integer(-1), Value::Integer(1)),
831 (Value::Integer(-2), Value::Bytes(x_coord)),
832 (Value::Integer(-3), Value::Bytes(y_coord)),
833 ]);
834 let cose_mac0: Vec<Value> = vec![
835 Value::Integer(0),
836 Value::Integer(1),
837 Value::from(serde_cbor::to_vec(&key_map)?),
838 Value::Integer(2),
839 ];
840 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&serde_cbor::to_vec(
841 &Value::from(cose_mac0),
842 )?)?;
843 assert_eq!(expected_key, raw_key);
844 Ok(())
845 }
846
847 #[test]
848 fn test_extract_payload_from_cose_mac() -> Result<()> {
849 let key_map = Value::Map(BTreeMap::from([(Value::Integer(1), Value::Integer(2))]));
850 let payload = Value::Bytes(serde_cbor::to_vec(&key_map)?);
851 let cose_mac0 =
852 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
853 let extracted_map = RemoteProvisioningService::extract_payload_from_cose_mac(
854 &serde_cbor::to_vec(&cose_mac0)?,
855 )?;
856 assert_eq!(key_map, extracted_map);
857 Ok(())
858 }
859
860 #[test]
861 fn test_extract_payload_from_cose_mac_fails_malformed_payload() -> Result<()> {
862 let payload = Value::Bytes(vec![5; 10]);
863 let cose_mac0 =
864 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
865 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
866 &serde_cbor::to_vec(&cose_mac0)?,
867 );
868 assert!(extracted_payload.is_err());
869 Ok(())
870 }
871
872 #[test]
873 fn test_extract_payload_from_cose_mac_fails_type() -> Result<()> {
874 let payload = Value::Integer(1);
875 let cose_mac0 =
876 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
877 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
878 &serde_cbor::to_vec(&cose_mac0)?,
879 );
880 assert!(extracted_payload.is_err());
881 Ok(())
882 }
883
884 #[test]
885 fn test_extract_payload_from_cose_mac_fails_length() -> Result<()> {
886 let cose_mac0 = Value::Array(vec![Value::Integer(0), Value::Integer(1)]);
887 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
888 &serde_cbor::to_vec(&cose_mac0)?,
889 );
890 assert!(extracted_payload.is_err());
891 Ok(())
892 }
Seth Moore7ee79f92021-12-07 11:42:49 -0800893
894 #[test]
895 #[ignore] // b/215746308
896 fn test_get_attestation_key_no_keys_provisioned() {
897 let mut db = crate::database::tests::new_test_db().unwrap();
898 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
899 mock_rpc.0.lock().unwrap().hw_info.uniqueId = Some(String::from("mallory"));
900
Seth Moore92648b62022-02-02 13:26:18 -0800901 let mut service: RemotelyProvisionedKeyPoolService = Default::default();
Seth Moore7ee79f92021-12-07 11:42:49 -0800902 service
Seth Moore92648b62022-02-02 13:26:18 -0800903 .unique_id_to_sec_level
904 .insert(String::from("mallory"), SecurityLevel::TRUSTED_ENVIRONMENT);
Seth Moore7ee79f92021-12-07 11:42:49 -0800905
906 assert_eq!(
907 service
908 .get_attestation_key(&mut db, 0, "mallory")
909 .unwrap_err()
910 .downcast::<error::Error>()
911 .unwrap(),
912 error::Error::Rc(ResponseCode::OUT_OF_KEYS)
913 );
914 }
915
916 #[test]
917 #[ignore] // b/215746308
918 fn test_get_attestation_key() {
919 let mut db = crate::database::tests::new_test_db().unwrap();
920 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
921 let irpc_id = "paul";
922 let caller_uid = 0;
923
924 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
925 let mock_values = mock_rpc.0.clone();
Seth Moore92648b62022-02-02 13:26:18 -0800926 let mut remote_provisioning: RemoteProvisioningService = Default::default();
927 remote_provisioning.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
928 let mut key_pool: RemotelyProvisionedKeyPoolService = Default::default();
929 key_pool.unique_id_to_sec_level.insert(String::from(irpc_id), sec_level);
Seth Moore7ee79f92021-12-07 11:42:49 -0800930
931 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
932 mock_values.lock().unwrap().private_key = vec![8, 6, 7, 5, 3, 0, 9];
933 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
Seth Moore92648b62022-02-02 13:26:18 -0800934 remote_provisioning.generate_key_pair(&mut db, true, sec_level).unwrap();
Seth Moore7ee79f92021-12-07 11:42:49 -0800935
936 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
937 mock_values.lock().unwrap().maced_public_key.as_slice(),
938 )
939 .unwrap();
940 let batch_cert = get_fake_cert();
941 let certs = &[5, 6, 7, 8];
Seth Moore92648b62022-02-02 13:26:18 -0800942 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -0800943 .provision_cert_chain(
944 &mut db,
945 public_key.as_slice(),
946 batch_cert.as_slice(),
947 certs,
948 0,
949 sec_level
950 )
951 .is_ok());
952
953 // ensure we got the key we expected
Seth Moore92648b62022-02-02 13:26:18 -0800954 let first_key = key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -0800955 .get_attestation_key(&mut db, caller_uid, irpc_id)
956 .context("get first key")
957 .unwrap();
958 assert_eq!(first_key.keyBlob, mock_values.lock().unwrap().private_key);
959 assert_eq!(first_key.encodedCertChain, certs);
960
961 // ensure that multiple calls get the same key
962 assert_eq!(
963 first_key,
Seth Moore92648b62022-02-02 13:26:18 -0800964 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -0800965 .get_attestation_key(&mut db, caller_uid, irpc_id)
966 .context("get second key")
967 .unwrap()
968 );
969
970 // no more keys for new clients
971 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -0800972 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -0800973 .get_attestation_key(&mut db, caller_uid + 1, irpc_id)
974 .unwrap_err()
975 .downcast::<error::Error>()
976 .unwrap(),
977 error::Error::Rc(ResponseCode::OUT_OF_KEYS)
978 );
979 }
980
981 #[test]
982 #[ignore] // b/215746308
983 fn test_get_attestation_key_gets_different_key_for_different_client() {
984 let mut db = crate::database::tests::new_test_db().unwrap();
985 let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
986 let irpc_id = "ringo";
987 let first_caller = 0;
988 let second_caller = first_caller + 1;
989
990 let mock_rpc = Box::<MockRemotelyProvisionedComponent>::default();
991 let mock_values = mock_rpc.0.clone();
Seth Moore92648b62022-02-02 13:26:18 -0800992 let mut remote_provisioning: RemoteProvisioningService = Default::default();
993 remote_provisioning.device_by_sec_level.insert(sec_level, Strong::new(mock_rpc));
994 let mut key_pool: RemotelyProvisionedKeyPoolService = Default::default();
995 key_pool.unique_id_to_sec_level.insert(String::from(irpc_id), sec_level);
Seth Moore7ee79f92021-12-07 11:42:49 -0800996
997 // generate two distinct keys and provision them with certs
998 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
999 mock_values.lock().unwrap().private_key = vec![3, 1, 4, 1, 5];
1000 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x11);
Seth Moore92648b62022-02-02 13:26:18 -08001001 assert!(remote_provisioning.generate_key_pair(&mut db, true, sec_level).is_ok());
Seth Moore7ee79f92021-12-07 11:42:49 -08001002 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
1003 mock_values.lock().unwrap().maced_public_key.as_slice(),
1004 )
1005 .unwrap();
Seth Moore92648b62022-02-02 13:26:18 -08001006 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -08001007 .provision_cert_chain(
1008 &mut db,
1009 public_key.as_slice(),
1010 get_fake_cert().as_slice(),
1011 &[1],
1012 0,
1013 sec_level
1014 )
1015 .is_ok());
1016
1017 mock_values.lock().unwrap().hw_info.uniqueId = Some(String::from(irpc_id));
1018 mock_values.lock().unwrap().private_key = vec![9, 0, 2, 1, 0];
1019 mock_values.lock().unwrap().maced_public_key = generate_maced_pubkey(0x22);
Seth Moore92648b62022-02-02 13:26:18 -08001020 assert!(remote_provisioning.generate_key_pair(&mut db, true, sec_level).is_ok());
Seth Moore7ee79f92021-12-07 11:42:49 -08001021 let public_key = RemoteProvisioningService::parse_cose_mac0_for_coords(
1022 mock_values.lock().unwrap().maced_public_key.as_slice(),
1023 )
1024 .unwrap();
Seth Moore92648b62022-02-02 13:26:18 -08001025 assert!(remote_provisioning
Seth Moore7ee79f92021-12-07 11:42:49 -08001026 .provision_cert_chain(
1027 &mut db,
1028 public_key.as_slice(),
1029 get_fake_cert().as_slice(),
1030 &[2],
1031 0,
1032 sec_level
1033 )
1034 .is_ok());
1035
1036 // make sure each caller gets a distinct key
1037 assert_ne!(
Seth Moore92648b62022-02-02 13:26:18 -08001038 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001039 .get_attestation_key(&mut db, first_caller, irpc_id)
1040 .context("get first key")
1041 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001042 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001043 .get_attestation_key(&mut db, second_caller, irpc_id)
1044 .context("get second key")
1045 .unwrap()
1046 );
1047
1048 // repeated calls should return the same key for a given caller
1049 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -08001050 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001051 .get_attestation_key(&mut db, first_caller, irpc_id)
1052 .context("first caller a")
1053 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001054 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001055 .get_attestation_key(&mut db, first_caller, irpc_id)
1056 .context("first caller b")
1057 .unwrap(),
1058 );
1059
1060 assert_eq!(
Seth Moore92648b62022-02-02 13:26:18 -08001061 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001062 .get_attestation_key(&mut db, second_caller, irpc_id)
1063 .context("second caller a")
1064 .unwrap(),
Seth Moore92648b62022-02-02 13:26:18 -08001065 key_pool
Seth Moore7ee79f92021-12-07 11:42:49 -08001066 .get_attestation_key(&mut db, second_caller, irpc_id)
1067 .context("second caller b")
1068 .unwrap()
1069 );
1070 }
Max Bires48fc2e52021-11-17 10:13:04 -08001071}