blob: 132ffbee8f1b6c80a47220d2b7f4355826a15ae8 [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,
Max Biresd2ce46b2021-07-06 02:54:47 -070033 IRemoteProvisioning::IRemoteProvisioning, ImplInfo::ImplInfo,
Max Bires148c08e2020-10-13 13:41:41 -070034};
Andrew Walbrande45c8b2021-04-13 14:42:38 +000035use android_security_remoteprovisioning::binder::{BinderFeatures, Strong};
Max Bires97f96812021-02-23 23:44:57 -080036use android_system_keystore2::aidl::android::system::keystore2::{
37 Domain::Domain, KeyDescriptor::KeyDescriptor,
38};
Max Biresb2e1d032021-02-08 21:35:05 -080039use anyhow::{Context, Result};
Max Bires97f96812021-02-23 23:44:57 -080040use keystore2_crypto::parse_subject_from_certificate;
Max Bires48fc2e52021-11-17 10:13:04 -080041use serde_cbor::Value;
42use std::collections::BTreeMap;
Max Bires97f96812021-02-23 23:44:57 -080043use std::sync::atomic::{AtomicBool, Ordering};
Max Bires148c08e2020-10-13 13:41:41 -070044
Max Bires97f96812021-02-23 23:44:57 -080045use crate::database::{CertificateChain, KeystoreDB, Uuid};
46use crate::error::{self, map_or_log_err, map_rem_prov_error, Error};
Max Biresb2e1d032021-02-08 21:35:05 -080047use crate::globals::{get_keymint_device, get_remotely_provisioned_component, DB};
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000048use crate::metrics_store::log_rkp_error_stats;
Janis Danisevskis5f3a0572021-06-18 11:26:42 -070049use crate::utils::watchdog as wd;
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +000050use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
Max Bires148c08e2020-10-13 13:41:41 -070051
Max Bires97f96812021-02-23 23:44:57 -080052/// Contains helper functions to check if remote provisioning is enabled on the system and, if so,
53/// to assign and retrieve attestation keys and certificate chains.
54#[derive(Default)]
55pub struct RemProvState {
56 security_level: SecurityLevel,
57 km_uuid: Uuid,
58 is_hal_present: AtomicBool,
59}
60
Max Bires48fc2e52021-11-17 10:13:04 -080061static COSE_KEY_XCOORD: Value = Value::Integer(-2);
62static COSE_KEY_YCOORD: Value = Value::Integer(-3);
63static COSE_MAC0_LEN: usize = 4;
64static COSE_MAC0_PAYLOAD: usize = 2;
65
Max Bires97f96812021-02-23 23:44:57 -080066impl RemProvState {
67 /// Creates a RemProvState struct.
68 pub fn new(security_level: SecurityLevel, km_uuid: Uuid) -> Self {
69 Self { security_level, km_uuid, is_hal_present: AtomicBool::new(true) }
70 }
71
72 /// Checks if remote provisioning is enabled and partially caches the result. On a hybrid system
73 /// remote provisioning can flip from being disabled to enabled depending on responses from the
74 /// server, so unfortunately caching the presence or absence of the HAL is not enough to fully
75 /// make decisions about the state of remote provisioning during runtime.
76 fn check_rem_prov_enabled(&self, db: &mut KeystoreDB) -> Result<bool> {
77 if !self.is_hal_present.load(Ordering::Relaxed)
78 || get_remotely_provisioned_component(&self.security_level).is_err()
79 {
80 self.is_hal_present.store(false, Ordering::Relaxed);
81 return Ok(false);
82 }
83 // To check if remote provisioning is enabled on a system that supports both remote
84 // provisioning and factory provisioned keys, we only need to check if there are any
85 // keys at all generated to indicate if the app has gotten the signal to begin filling
86 // the key pool from the server.
87 let pool_status = db
88 .get_attestation_pool_status(0 /* date */, &self.km_uuid)
89 .context("In check_rem_prov_enabled: failed to get attestation pool status.")?;
90 Ok(pool_status.total != 0)
91 }
92
93 /// Fetches a remote provisioning attestation key and certificate chain inside of the
94 /// returned `CertificateChain` struct if one exists for the given caller_uid. If one has not
95 /// been assigned, this function will assign it. If there are no signed attestation keys
96 /// available to be assigned, it will return the ResponseCode `OUT_OF_KEYS`
97 fn get_rem_prov_attest_key(
98 &self,
99 key: &KeyDescriptor,
100 caller_uid: u32,
101 db: &mut KeystoreDB,
102 ) -> Result<Option<CertificateChain>> {
103 match key.domain {
104 Domain::APP => {
105 // Attempt to get an Attestation Key once. If it fails, then the app doesn't
106 // have a valid chain assigned to it. The helper function will return None after
107 // attempting to assign a key. An error will be thrown if the pool is simply out
108 // of usable keys. Then another attempt to fetch the just-assigned key will be
109 // made. If this fails too, something is very wrong.
110 self.get_rem_prov_attest_key_helper(key, caller_uid, db)
111 .context("In get_rem_prov_attest_key: Failed to get a key")?
112 .map_or_else(
113 || self.get_rem_prov_attest_key_helper(key, caller_uid, db),
114 |v| Ok(Some(v)),
115 )
116 .context(concat!(
117 "In get_rem_prov_attest_key: Failed to get a key after",
118 "attempting to assign one."
119 ))?
120 .map_or_else(
121 || {
122 Err(Error::sys()).context(concat!(
123 "In get_rem_prov_attest_key: Attempted to assign a ",
124 "key and failed silently. Something is very wrong."
125 ))
126 },
127 |cert_chain| Ok(Some(cert_chain)),
128 )
129 }
130 _ => Ok(None),
131 }
132 }
133
134 /// Returns None if an AttestationKey fails to be assigned. Errors if no keys are available.
135 fn get_rem_prov_attest_key_helper(
136 &self,
137 key: &KeyDescriptor,
138 caller_uid: u32,
139 db: &mut KeystoreDB,
140 ) -> Result<Option<CertificateChain>> {
141 let cert_chain = db
142 .retrieve_attestation_key_and_cert_chain(key.domain, caller_uid as i64, &self.km_uuid)
143 .context("In get_rem_prov_attest_key_helper: Failed to retrieve a key + cert chain")?;
144 match cert_chain {
145 Some(cert_chain) => Ok(Some(cert_chain)),
146 // Either this app needs to be assigned a key, or the pool is empty. An error will
147 // be thrown if there is no key available to assign. This will indicate that the app
148 // should be nudged to provision more keys so keystore can retry.
149 None => {
150 db.assign_attestation_key(key.domain, caller_uid as i64, &self.km_uuid)
151 .context("In get_rem_prov_attest_key_helper: Failed to assign a key")?;
152 Ok(None)
153 }
154 }
155 }
156
157 fn is_asymmetric_key(&self, params: &[KeyParameter]) -> bool {
158 params.iter().any(|kp| {
159 matches!(
160 kp,
161 KeyParameter {
162 tag: Tag::ALGORITHM,
163 value: KeyParameterValue::Algorithm(Algorithm::RSA)
164 } | KeyParameter {
165 tag: Tag::ALGORITHM,
166 value: KeyParameterValue::Algorithm(Algorithm::EC)
167 }
168 )
169 })
170 }
171
172 /// Checks to see (1) if the key in question should be attested to based on the algorithm and
173 /// (2) if remote provisioning is present and enabled on the system. If these conditions are
174 /// met, it makes an attempt to fetch the attestation key assigned to the `caller_uid`.
175 ///
176 /// It returns the ResponseCode `OUT_OF_KEYS` if there is not one key currently assigned to the
177 /// `caller_uid` and there are none available to assign.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700178 pub fn get_remotely_provisioned_attestation_key_and_certs(
Max Bires97f96812021-02-23 23:44:57 -0800179 &self,
180 key: &KeyDescriptor,
181 caller_uid: u32,
182 params: &[KeyParameter],
183 db: &mut KeystoreDB,
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700184 ) -> Result<Option<(AttestationKey, Certificate)>> {
Max Bires97f96812021-02-23 23:44:57 -0800185 if !self.is_asymmetric_key(params) || !self.check_rem_prov_enabled(db)? {
186 // There is no remote provisioning component for this security level on the
187 // device. Return None so the underlying KM instance knows to use its
188 // factory provisioned key instead. Alternatively, it's not an asymmetric key
189 // and therefore will not be attested.
Janis Danisevskis3541f3e2021-03-20 14:18:52 -0700190 Ok(None)
Max Bires97f96812021-02-23 23:44:57 -0800191 } else {
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700192 match self.get_rem_prov_attest_key(key, caller_uid, db) {
Max Bires31cdfb82021-07-06 02:59:25 -0700193 Err(e) => {
194 log::error!(
195 concat!(
196 "In get_remote_provisioning_key_and_certs: Failed to get ",
197 "attestation key. {:?}"
198 ),
199 e
200 );
Hasini Gunasinghe8a1a2242021-08-02 22:28:39 +0000201 log_rkp_error_stats(MetricsRkpError::FALL_BACK_DURING_HYBRID);
Max Bires31cdfb82021-07-06 02:59:25 -0700202 Ok(None)
203 }
204 Ok(v) => match v {
205 Some(cert_chain) => Ok(Some((
206 AttestationKey {
207 keyBlob: cert_chain.private_key.to_vec(),
208 attestKeyParams: vec![],
209 issuerSubjectName: parse_subject_from_certificate(
210 &cert_chain.batch_cert,
211 )
Max Bires97f96812021-02-23 23:44:57 -0800212 .context(concat!(
Max Bires31cdfb82021-07-06 02:59:25 -0700213 "In get_remote_provisioning_key_and_certs: Failed to ",
214 "parse subject."
215 ))?,
216 },
217 Certificate { encodedCertificate: cert_chain.cert_chain },
218 ))),
219 None => Ok(None),
220 },
Max Bires97f96812021-02-23 23:44:57 -0800221 }
222 }
223 }
224}
Max Bires148c08e2020-10-13 13:41:41 -0700225/// Implementation of the IRemoteProvisioning service.
Max Biresb2e1d032021-02-08 21:35:05 -0800226#[derive(Default)]
Max Bires148c08e2020-10-13 13:41:41 -0700227pub struct RemoteProvisioningService {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -0700228 device_by_sec_level: HashMap<SecurityLevel, Strong<dyn IRemotelyProvisionedComponent>>,
Max Biresd2ce46b2021-07-06 02:54:47 -0700229 curve_by_sec_level: HashMap<SecurityLevel, i32>,
Max Bires148c08e2020-10-13 13:41:41 -0700230}
231
232impl RemoteProvisioningService {
Max Biresb2e1d032021-02-08 21:35:05 -0800233 fn get_dev_by_sec_level(
234 &self,
235 sec_level: &SecurityLevel,
236 ) -> Result<Strong<dyn IRemotelyProvisionedComponent>> {
237 if let Some(dev) = self.device_by_sec_level.get(sec_level) {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -0700238 Ok(dev.clone())
Max Biresb2e1d032021-02-08 21:35:05 -0800239 } else {
240 Err(error::Error::sys()).context(concat!(
241 "In get_dev_by_sec_level: Remote instance for requested security level",
242 " not found."
243 ))
244 }
245 }
246
Max Bires148c08e2020-10-13 13:41:41 -0700247 /// Creates a new instance of the remote provisioning service
Stephen Crane221bbb52020-12-16 15:52:10 -0800248 pub fn new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800249 let mut result: Self = Default::default();
250 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
251 .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
Max Biresd2ce46b2021-07-06 02:54:47 -0700252 result.curve_by_sec_level.insert(
253 SecurityLevel::TRUSTED_ENVIRONMENT,
254 dev.getHardwareInfo()
255 .context("In new_native_binder: Failed to get hardware info for the TEE.")?
256 .supportedEekCurve,
257 );
Max Biresb2e1d032021-02-08 21:35:05 -0800258 result.device_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, dev);
259 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
Max Biresd2ce46b2021-07-06 02:54:47 -0700260 result.curve_by_sec_level.insert(
261 SecurityLevel::STRONGBOX,
262 dev.getHardwareInfo()
263 .context("In new_native_binder: Failed to get hardware info for StrongBox.")?
264 .supportedEekCurve,
265 );
Max Biresb2e1d032021-02-08 21:35:05 -0800266 result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
267 }
Andrew Walbrande45c8b2021-04-13 14:42:38 +0000268 Ok(BnRemoteProvisioning::new_binder(result, BinderFeatures::default()))
Max Bires148c08e2020-10-13 13:41:41 -0700269 }
270
Max Bires48fc2e52021-11-17 10:13:04 -0800271 fn extract_payload_from_cose_mac(data: &[u8]) -> Result<Value> {
272 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
273 "In extract_payload_from_cose_mac: COSE_Mac0 returned from IRPC cannot be parsed",
274 )?;
275 if cose_mac0.len() != COSE_MAC0_LEN {
276 return Err(error::Error::sys()).context(format!(
277 "In extract_payload_from_cose_mac: COSE_Mac0 has improper length. \
278 Expected: {}, Actual: {}",
279 COSE_MAC0_LEN,
280 cose_mac0.len(),
281 ));
282 }
283 match &cose_mac0[COSE_MAC0_PAYLOAD] {
284 Value::Bytes(key) => Ok(serde_cbor::from_slice(key)
285 .context("In extract_payload_from_cose_mac: COSE_Mac0 payload is malformed.")?),
286 _ => Err(error::Error::sys()).context(
287 "In extract_payload_from_cose_mac: COSE_Mac0 payload is the wrong type.",
288 )?,
289 }
290 }
291
Max Bires148c08e2020-10-13 13:41:41 -0700292 /// Generates a CBOR blob which will be assembled by the calling code into a larger
293 /// CBOR blob intended for delivery to a provisioning serever. This blob will contain
294 /// `num_csr` certificate signing requests for attestation keys generated in the TEE,
295 /// along with a server provided `eek` and `challenge`. The endpoint encryption key will
296 /// be used to encrypt the sensitive contents being transmitted to the server, and the
297 /// challenge will ensure freshness. A `test_mode` flag will instruct the remote provisioning
298 /// HAL if it is okay to accept EEKs that aren't signed by something that chains back to the
299 /// baked in root of trust in the underlying IRemotelyProvisionedComponent instance.
Max Bires834dd362021-03-23 13:01:57 -0700300 #[allow(clippy::too_many_arguments)]
Max Bires148c08e2020-10-13 13:41:41 -0700301 pub fn generate_csr(
302 &self,
Max Biresb2e1d032021-02-08 21:35:05 -0800303 test_mode: bool,
304 num_csr: i32,
305 eek: &[u8],
306 challenge: &[u8],
307 sec_level: SecurityLevel,
308 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700309 device_info: &mut DeviceInfo,
Max Bires148c08e2020-10-13 13:41:41 -0700310 ) -> Result<Vec<u8>> {
Max Biresb2e1d032021-02-08 21:35:05 -0800311 let dev = self.get_dev_by_sec_level(&sec_level)?;
312 let (_, _, uuid) = get_keymint_device(&sec_level)?;
313 let keys_to_sign = DB.with::<_, Result<Vec<MacedPublicKey>>>(|db| {
314 let mut db = db.borrow_mut();
315 Ok(db
316 .fetch_unsigned_attestation_keys(num_csr, &uuid)?
317 .iter()
318 .map(|key| MacedPublicKey { macedKey: key.to_vec() })
319 .collect())
320 })?;
Max Bires48fc2e52021-11-17 10:13:04 -0800321 let mac = map_rem_prov_error(dev.generateCertificateRequest(
Max Biresb2e1d032021-02-08 21:35:05 -0800322 test_mode,
323 &keys_to_sign,
324 eek,
325 challenge,
Max Bires834dd362021-03-23 13:01:57 -0700326 device_info,
Max Biresb2e1d032021-02-08 21:35:05 -0800327 protected_data,
328 ))
329 .context("In generate_csr: Failed to generate csr")?;
Max Bires48fc2e52021-11-17 10:13:04 -0800330 let mut mac_and_keys: Vec<Value> = vec![Value::from(mac)];
Max Bires97f96812021-02-23 23:44:57 -0800331 for maced_public_key in keys_to_sign {
Max Bires48fc2e52021-11-17 10:13:04 -0800332 mac_and_keys.push(
333 Self::extract_payload_from_cose_mac(&maced_public_key.macedKey)
334 .context("In generate_csr: Failed to get the payload from the COSE_Mac0")?,
335 )
Max Bires97f96812021-02-23 23:44:57 -0800336 }
Max Bires48fc2e52021-11-17 10:13:04 -0800337 let cbor_array: Value = Value::Array(mac_and_keys);
338 serde_cbor::to_vec(&cbor_array)
339 .context("In generate_csr: Failed to serialize the mac and keys array")
Max Bires148c08e2020-10-13 13:41:41 -0700340 }
341
342 /// Provisions a certificate chain for a key whose CSR was included in generate_csr. The
343 /// `public_key` is used to index into the SQL database in order to insert the `certs` blob
344 /// which represents a PEM encoded X.509 certificate chain. The `expiration_date` is provided
345 /// as a convenience from the caller to avoid having to parse the certificates semantically
346 /// here.
347 pub fn provision_cert_chain(
348 &self,
349 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800350 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700351 certs: &[u8],
352 expiration_date: i64,
353 sec_level: SecurityLevel,
354 ) -> Result<()> {
355 DB.with::<_, Result<()>>(|db| {
356 let mut db = db.borrow_mut();
357 let (_, _, uuid) = get_keymint_device(&sec_level)?;
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700358 db.store_signed_attestation_certificate_chain(
Max Bires148c08e2020-10-13 13:41:41 -0700359 public_key,
Max Biresb2e1d032021-02-08 21:35:05 -0800360 batch_cert,
Max Bires148c08e2020-10-13 13:41:41 -0700361 certs, /* DER encoded certificate chain */
362 expiration_date,
363 &uuid,
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700364 )
Max Bires148c08e2020-10-13 13:41:41 -0700365 })
366 }
367
Max Bires48fc2e52021-11-17 10:13:04 -0800368 fn parse_cose_mac0_for_coords(data: &[u8]) -> Result<Vec<u8>> {
369 let cose_mac0: Vec<Value> = serde_cbor::from_slice(data).context(
370 "In parse_cose_mac0_for_coords: COSE_Mac0 returned from IRPC cannot be parsed",
371 )?;
372 if cose_mac0.len() != COSE_MAC0_LEN {
373 return Err(error::Error::sys()).context(format!(
374 "In parse_cose_mac0_for_coords: COSE_Mac0 has improper length. \
375 Expected: {}, Actual: {}",
376 COSE_MAC0_LEN,
377 cose_mac0.len(),
378 ));
379 }
380 let cose_key: BTreeMap<Value, Value> = match &cose_mac0[COSE_MAC0_PAYLOAD] {
381 Value::Bytes(key) => serde_cbor::from_slice(key)
382 .context("In parse_cose_mac0_for_coords: COSE_Key is malformed.")?,
383 _ => Err(error::Error::sys())
384 .context("In parse_cose_mac0_for_coords: COSE_Mac0 payload is the wrong type.")?,
385 };
386 if !cose_key.contains_key(&COSE_KEY_XCOORD) || !cose_key.contains_key(&COSE_KEY_YCOORD) {
387 return Err(error::Error::sys()).context(
388 "In parse_cose_mac0_for_coords: \
389 COSE_Key returned from IRPC is lacking required fields",
390 );
391 }
392 let mut raw_key: Vec<u8> = vec![0; 64];
393 match &cose_key[&COSE_KEY_XCOORD] {
394 Value::Bytes(x_coord) if x_coord.len() == 32 => {
395 raw_key[0..32].clone_from_slice(x_coord)
396 }
397 Value::Bytes(x_coord) => {
398 return Err(error::Error::sys()).context(format!(
399 "In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not the right length. \
400 Expected: 32; Actual: {}",
401 x_coord.len()
402 ))
403 }
404 _ => {
405 return Err(error::Error::sys())
406 .context("In parse_cose_mac0_for_coords: COSE_Key X-coordinate is not a bstr")
407 }
408 }
409 match &cose_key[&COSE_KEY_YCOORD] {
410 Value::Bytes(y_coord) if y_coord.len() == 32 => {
411 raw_key[32..64].clone_from_slice(y_coord)
412 }
413 Value::Bytes(y_coord) => {
414 return Err(error::Error::sys()).context(format!(
415 "In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not the right length. \
416 Expected: 32; Actual: {}",
417 y_coord.len()
418 ))
419 }
420 _ => {
421 return Err(error::Error::sys())
422 .context("In parse_cose_mac0_for_coords: COSE_Key Y-coordinate is not a bstr")
423 }
424 }
425 Ok(raw_key)
426 }
427
Max Bires148c08e2020-10-13 13:41:41 -0700428 /// Submits a request to the Remote Provisioner HAL to generate a signing key pair.
429 /// `is_test_mode` indicates whether or not the returned public key should be marked as being
430 /// for testing in order to differentiate them from private keys. If the call is successful,
431 /// the key pair is then added to the database.
Max Biresb2e1d032021-02-08 21:35:05 -0800432 pub fn generate_key_pair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> Result<()> {
433 let (_, _, uuid) = get_keymint_device(&sec_level)?;
434 let dev = self.get_dev_by_sec_level(&sec_level)?;
435 let mut maced_key = MacedPublicKey { macedKey: Vec::new() };
436 let priv_key =
437 map_rem_prov_error(dev.generateEcdsaP256KeyPair(is_test_mode, &mut maced_key))
438 .context("In generate_key_pair: Failed to generated ECDSA keypair.")?;
Max Bires48fc2e52021-11-17 10:13:04 -0800439 let raw_key = Self::parse_cose_mac0_for_coords(&maced_key.macedKey)
440 .context("In generate_key_pair: Failed to parse raw key")?;
Max Biresb2e1d032021-02-08 21:35:05 -0800441 DB.with::<_, Result<()>>(|db| {
442 let mut db = db.borrow_mut();
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700443 db.create_attestation_key_entry(&maced_key.macedKey, &raw_key, &priv_key, &uuid)
Max Biresb2e1d032021-02-08 21:35:05 -0800444 })
445 }
446
447 /// Checks the security level of each available IRemotelyProvisionedComponent hal and returns
448 /// all levels in an array to the caller.
Max Biresd2ce46b2021-07-06 02:54:47 -0700449 pub fn get_implementation_info(&self) -> Result<Vec<ImplInfo>> {
450 Ok(self
451 .curve_by_sec_level
452 .iter()
453 .map(|(sec_level, curve)| ImplInfo { secLevel: *sec_level, supportedCurve: *curve })
454 .collect())
Max Bires148c08e2020-10-13 13:41:41 -0700455 }
Max Bires60d7ed12021-03-05 15:59:22 -0800456
457 /// Deletes all attestation keys generated by the IRemotelyProvisionedComponent from the device,
458 /// regardless of what state of the attestation key lifecycle they were in.
459 pub fn delete_all_keys(&self) -> Result<i64> {
460 DB.with::<_, Result<i64>>(|db| {
461 let mut db = db.borrow_mut();
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700462 db.delete_all_attestation_keys()
Max Bires60d7ed12021-03-05 15:59:22 -0800463 })
464 }
Max Bires148c08e2020-10-13 13:41:41 -0700465}
466
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000467/// Populates the AttestationPoolStatus parcelable with information about how many
468/// certs will be expiring by the date provided in `expired_by` along with how many
469/// keys have not yet been assigned.
470pub fn get_pool_status(expired_by: i64, sec_level: SecurityLevel) -> Result<AttestationPoolStatus> {
471 let (_, _, uuid) = get_keymint_device(&sec_level)?;
472 DB.with::<_, Result<AttestationPoolStatus>>(|db| {
473 let mut db = db.borrow_mut();
474 // delete_expired_attestation_keys is always safe to call, and will remove anything
475 // older than the date at the time of calling. No work should be done on the
476 // attestation keys unless the pool status is checked first, so this call should be
477 // enough to routinely clean out expired keys.
478 db.delete_expired_attestation_keys()?;
479 db.get_attestation_pool_status(expired_by, &uuid)
480 })
481}
482
Max Bires148c08e2020-10-13 13:41:41 -0700483impl binder::Interface for RemoteProvisioningService {}
484
485// Implementation of IRemoteProvisioning. See AIDL spec at
486// :aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
487impl IRemoteProvisioning for RemoteProvisioningService {
488 fn getPoolStatus(
489 &self,
490 expired_by: i64,
491 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700492 ) -> binder::Result<AttestationPoolStatus> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000493 let _wp = wd::watch_millis("IRemoteProvisioning::getPoolStatus", 500);
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000494 map_or_log_err(get_pool_status(expired_by, sec_level), Ok)
Max Bires148c08e2020-10-13 13:41:41 -0700495 }
496
497 fn generateCsr(
498 &self,
499 test_mode: bool,
500 num_csr: i32,
501 eek: &[u8],
502 challenge: &[u8],
503 sec_level: SecurityLevel,
Max Biresb2e1d032021-02-08 21:35:05 -0800504 protected_data: &mut ProtectedData,
Max Bires834dd362021-03-23 13:01:57 -0700505 device_info: &mut DeviceInfo,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700506 ) -> binder::Result<Vec<u8>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000507 let _wp = wd::watch_millis("IRemoteProvisioning::generateCsr", 500);
Max Biresb2e1d032021-02-08 21:35:05 -0800508 map_or_log_err(
Max Bires834dd362021-03-23 13:01:57 -0700509 self.generate_csr(
510 test_mode,
511 num_csr,
512 eek,
513 challenge,
514 sec_level,
515 protected_data,
516 device_info,
517 ),
Max Biresb2e1d032021-02-08 21:35:05 -0800518 Ok,
519 )
Max Bires148c08e2020-10-13 13:41:41 -0700520 }
521
522 fn provisionCertChain(
523 &self,
524 public_key: &[u8],
Max Biresb2e1d032021-02-08 21:35:05 -0800525 batch_cert: &[u8],
Max Bires148c08e2020-10-13 13:41:41 -0700526 certs: &[u8],
527 expiration_date: i64,
528 sec_level: SecurityLevel,
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700529 ) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000530 let _wp = wd::watch_millis("IRemoteProvisioning::provisionCertChain", 500);
Max Biresb2e1d032021-02-08 21:35:05 -0800531 map_or_log_err(
532 self.provision_cert_chain(public_key, batch_cert, certs, expiration_date, sec_level),
533 Ok,
534 )
Max Bires148c08e2020-10-13 13:41:41 -0700535 }
536
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700537 fn generateKeyPair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> binder::Result<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000538 let _wp = wd::watch_millis("IRemoteProvisioning::generateKeyPair", 500);
Max Bires148c08e2020-10-13 13:41:41 -0700539 map_or_log_err(self.generate_key_pair(is_test_mode, sec_level), Ok)
540 }
Max Biresb2e1d032021-02-08 21:35:05 -0800541
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700542 fn getImplementationInfo(&self) -> binder::Result<Vec<ImplInfo>> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000543 let _wp = wd::watch_millis("IRemoteProvisioning::getSecurityLevels", 500);
Max Biresd2ce46b2021-07-06 02:54:47 -0700544 map_or_log_err(self.get_implementation_info(), Ok)
Max Biresb2e1d032021-02-08 21:35:05 -0800545 }
Max Bires60d7ed12021-03-05 15:59:22 -0800546
Stephen Craneeb3bd5d2021-08-16 16:44:15 -0700547 fn deleteAllKeys(&self) -> binder::Result<i64> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000548 let _wp = wd::watch_millis("IRemoteProvisioning::deleteAllKeys", 500);
Max Bires60d7ed12021-03-05 15:59:22 -0800549 map_or_log_err(self.delete_all_keys(), Ok)
550 }
Max Bires148c08e2020-10-13 13:41:41 -0700551}
Max Bires48fc2e52021-11-17 10:13:04 -0800552
553#[cfg(test)]
554mod tests {
555 use super::*;
556 use serde_cbor::Value;
557 use std::collections::BTreeMap;
558
559 #[test]
560 fn test_parse_cose_mac0_for_coords_raw_bytes() -> Result<()> {
561 let cose_mac0: Vec<u8> = vec![
562 0x84, 0x01, 0x02, 0x58, 0x4D, 0xA5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
563 0x20, 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9,
564 0x21, 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C,
565 0x43, 0x22, 0xC8, 0xEE, 0x03, 0x22, 0x58, 0x20, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95,
566 0x90, 0xA7, 0x5C, 0x5A, 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A,
567 0xA3, 0xB3, 0x1A, 0xB4, 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC, 0x03,
568 ];
569 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&cose_mac0)?;
570 assert_eq!(
571 raw_key,
572 vec![
573 0x1A, 0xFB, 0xB2, 0xD9, 0x9D, 0xF6, 0x2D, 0xF0, 0xC3, 0xA8, 0xFC, 0x7E, 0xC9, 0x21,
574 0x26, 0xED, 0xB5, 0x4A, 0x98, 0x9B, 0xF3, 0x0D, 0x91, 0x3F, 0xC6, 0x42, 0x5C, 0x43,
575 0x22, 0xC8, 0xEE, 0x03, 0x40, 0xB3, 0x9B, 0xFC, 0x47, 0x95, 0x90, 0xA7, 0x5C, 0x5A,
576 0x16, 0x31, 0x34, 0xAF, 0x0C, 0x5B, 0xF2, 0xB2, 0xD8, 0x2A, 0xA3, 0xB3, 0x1A, 0xB4,
577 0x4C, 0xA6, 0x3B, 0xE7, 0x22, 0xEC, 0x41, 0xDC,
578 ]
579 );
580 Ok(())
581 }
582
583 #[test]
584 fn test_parse_cose_mac0_for_coords_constructed_mac() -> Result<()> {
585 let x_coord: Vec<u8> = vec![0; 32];
586 let y_coord: Vec<u8> = vec![1; 32];
587 let mut expected_key: Vec<u8> = Vec::new();
588 expected_key.extend(&x_coord);
589 expected_key.extend(&y_coord);
590 let key_map: BTreeMap<Value, Value> = BTreeMap::from([
591 (Value::Integer(1), Value::Integer(2)),
592 (Value::Integer(3), Value::Integer(-7)),
593 (Value::Integer(-1), Value::Integer(1)),
594 (Value::Integer(-2), Value::Bytes(x_coord)),
595 (Value::Integer(-3), Value::Bytes(y_coord)),
596 ]);
597 let cose_mac0: Vec<Value> = vec![
598 Value::Integer(0),
599 Value::Integer(1),
600 Value::from(serde_cbor::to_vec(&key_map)?),
601 Value::Integer(2),
602 ];
603 let raw_key = RemoteProvisioningService::parse_cose_mac0_for_coords(&serde_cbor::to_vec(
604 &Value::from(cose_mac0),
605 )?)?;
606 assert_eq!(expected_key, raw_key);
607 Ok(())
608 }
609
610 #[test]
611 fn test_extract_payload_from_cose_mac() -> Result<()> {
612 let key_map = Value::Map(BTreeMap::from([(Value::Integer(1), Value::Integer(2))]));
613 let payload = Value::Bytes(serde_cbor::to_vec(&key_map)?);
614 let cose_mac0 =
615 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
616 let extracted_map = RemoteProvisioningService::extract_payload_from_cose_mac(
617 &serde_cbor::to_vec(&cose_mac0)?,
618 )?;
619 assert_eq!(key_map, extracted_map);
620 Ok(())
621 }
622
623 #[test]
624 fn test_extract_payload_from_cose_mac_fails_malformed_payload() -> Result<()> {
625 let payload = Value::Bytes(vec![5; 10]);
626 let cose_mac0 =
627 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
628 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
629 &serde_cbor::to_vec(&cose_mac0)?,
630 );
631 assert!(extracted_payload.is_err());
632 Ok(())
633 }
634
635 #[test]
636 fn test_extract_payload_from_cose_mac_fails_type() -> Result<()> {
637 let payload = Value::Integer(1);
638 let cose_mac0 =
639 Value::Array(vec![Value::Integer(0), Value::Integer(1), payload, Value::Integer(3)]);
640 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
641 &serde_cbor::to_vec(&cose_mac0)?,
642 );
643 assert!(extracted_payload.is_err());
644 Ok(())
645 }
646
647 #[test]
648 fn test_extract_payload_from_cose_mac_fails_length() -> Result<()> {
649 let cose_mac0 = Value::Array(vec![Value::Integer(0), Value::Integer(1)]);
650 let extracted_payload = RemoteProvisioningService::extract_payload_from_cose_mac(
651 &serde_cbor::to_vec(&cose_mac0)?,
652 );
653 assert!(extracted_payload.is_err());
654 Ok(())
655 }
656}