Merge "Skip test case for AVF since those are not supported." into main
diff --git a/keystore/tests/fuzzer/Android.bp b/keystore/tests/fuzzer/Android.bp
index 5df5c7a..d459f75 100644
--- a/keystore/tests/fuzzer/Android.bp
+++ b/keystore/tests/fuzzer/Android.bp
@@ -40,9 +40,17 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "android-hardware-security@google.com",
],
- componentid: 155276,
+ componentid: 1084732,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libkeystore-wifi-hidl",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
@@ -62,9 +70,17 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "android-hardware-security@google.com",
],
- componentid: 155276,
+ componentid: 1084732,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libkeystore-attestation-application-id",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index e59b6f2..c378b42 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -58,6 +58,7 @@
"liblog_rust",
"libmessage_macro",
"librand",
+ "librkpd_client",
"librustutils",
"libserde",
"libserde_cbor",
diff --git a/keystore2/TEST_MAPPING b/keystore2/TEST_MAPPING
index 1038bea..57ce78c 100644
--- a/keystore2/TEST_MAPPING
+++ b/keystore2/TEST_MAPPING
@@ -35,6 +35,9 @@
"name": "keystore2_client_tests"
},
{
+ "name": "librkpd_client.test"
+ },
+ {
"name": "libwatchdog_rs.test"
}
]
diff --git a/keystore2/rkpd_client/Android.bp b/keystore2/rkpd_client/Android.bp
new file mode 100644
index 0000000..1de333f
--- /dev/null
+++ b/keystore2/rkpd_client/Android.bp
@@ -0,0 +1,51 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "system_security_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_security_license"],
+}
+
+rust_defaults {
+ name: "librkpd_client_defaults",
+ crate_name: "rkpd_client",
+ srcs: ["src/lib.rs"],
+ rustlibs: [
+ "android.security.rkp_aidl-rust",
+ "libanyhow",
+ "libbinder_rs",
+ "liblog_rust",
+ "libmessage_macro",
+ "libthiserror",
+ "libtokio",
+ ],
+}
+
+rust_library {
+ name: "librkpd_client",
+ defaults: ["librkpd_client_defaults"],
+}
+
+rust_test {
+ name: "librkpd_client.test",
+ defaults: ["librkpd_client_defaults"],
+ test_suites: ["general-tests"],
+ rustlibs: [
+ "librand",
+ ],
+}
diff --git a/keystore2/src/rkpd_client.rs b/keystore2/rkpd_client/src/lib.rs
similarity index 84%
rename from keystore2/src/rkpd_client.rs
rename to keystore2/rkpd_client/src/lib.rs
index fe64150..d8a5276 100644
--- a/keystore2/src/rkpd_client.rs
+++ b/keystore2/rkpd_client/src/lib.rs
@@ -14,7 +14,6 @@
//! Helper wrapper around RKPD interface.
-use crate::error::{map_binder_status_code, Error, ResponseCode};
use android_security_rkp_aidl::aidl::android::security::rkp::{
IGetKeyCallback::BnGetKeyCallback, IGetKeyCallback::ErrorCode::ErrorCode as GetKeyErrorCode,
IGetKeyCallback::IGetKeyCallback, IGetRegistrationCallback::BnGetRegistrationCallback,
@@ -24,8 +23,8 @@
IStoreUpgradedKeyCallback::IStoreUpgradedKeyCallback,
RemotelyProvisionedKey::RemotelyProvisionedKey,
};
-use android_security_rkp_aidl::binder::{BinderFeatures, Interface, Strong};
use anyhow::{Context, Result};
+use binder::{BinderFeatures, Interface, StatusCode, Strong};
use message_macro::source_location_msg;
use std::sync::Mutex;
use std::time::Duration;
@@ -41,6 +40,44 @@
tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap()
}
+/// Errors occurred during the interaction with RKPD.
+#[derive(Debug, Clone, Copy, thiserror::Error, PartialEq, Eq)]
+pub enum Error {
+ /// An RKPD request gets cancelled.
+ #[error("An RKPD request gets cancelled")]
+ RequestCancelled,
+
+ /// Failed to get registration.
+ #[error("Failed to get registration")]
+ GetRegistrationFailed,
+
+ /// Failed to get key.
+ #[error("Failed to get key: {0:?}")]
+ GetKeyFailed(GetKeyErrorCode),
+
+ /// Failed to store upgraded key.
+ #[error("Failed to store upgraded key")]
+ StoreUpgradedKeyFailed,
+
+ /// Retryable timeout when waiting for a callback.
+ #[error("Retryable timeout when waiting for a callback")]
+ RetryableTimeout,
+
+ /// Timeout when waiting for a callback.
+ #[error("Timeout when waiting for a callback")]
+ Timeout,
+
+ /// Wraps a Binder status code.
+ #[error("Binder transaction error {0:?}")]
+ BinderTransaction(StatusCode),
+}
+
+impl From<StatusCode> for Error {
+ fn from(s: StatusCode) -> Self {
+ Self::BinderTransaction(s)
+ }
+}
+
/// Thread-safe channel for sending a value once and only once. If a value has
/// already been send, subsequent calls to send will noop.
struct SafeSender<T> {
@@ -87,17 +124,17 @@
fn onCancel(&self) -> binder::Result<()> {
log::warn!("IGetRegistrationCallback cancelled");
self.registration_tx.send(
- Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
+ Err(Error::RequestCancelled)
.context(source_location_msg!("GetRegistrationCallback cancelled.")),
);
Ok(())
}
fn onError(&self, description: &str) -> binder::Result<()> {
log::error!("IGetRegistrationCallback failed: '{description}'");
- self.registration_tx
- .send(Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)).context(
- source_location_msg!("GetRegistrationCallback failed: {:?}", description),
- ));
+ self.registration_tx.send(
+ Err(Error::GetRegistrationFailed)
+ .context(source_location_msg!("GetRegistrationCallback failed: {:?}", description)),
+ );
Ok(())
}
}
@@ -105,7 +142,8 @@
/// Make a new connection to a IRegistration service.
async fn get_rkpd_registration(rpc_name: &str) -> Result<binder::Strong<dyn IRegistration>> {
let remote_provisioning: Strong<dyn IRemoteProvisioning> =
- map_binder_status_code(binder::get_interface("remote_provisioning"))
+ binder::get_interface("remote_provisioning")
+ .map_err(Error::from)
.context(source_location_msg!("Trying to connect to IRemoteProvisioning service."))?;
let (tx, rx) = oneshot::channel();
@@ -116,8 +154,7 @@
.context(source_location_msg!("Trying to get registration."))?;
match timeout(RKPD_TIMEOUT, rx).await {
- Err(e) => Err(Error::Rc(ResponseCode::SYSTEM_ERROR))
- .context(source_location_msg!("Waiting for RKPD: {:?}", e)),
+ Err(e) => Err(Error::Timeout).context(source_location_msg!("Waiting for RKPD: {:?}", e)),
Ok(v) => v.unwrap(),
}
}
@@ -148,28 +185,13 @@
fn onCancel(&self) -> binder::Result<()> {
log::warn!("IGetKeyCallback cancelled");
self.key_tx.send(
- Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
- .context(source_location_msg!("GetKeyCallback cancelled.")),
+ Err(Error::RequestCancelled).context(source_location_msg!("GetKeyCallback cancelled.")),
);
Ok(())
}
fn onError(&self, error: GetKeyErrorCode, description: &str) -> binder::Result<()> {
log::error!("IGetKeyCallback failed: {description}");
- let rc = match error {
- GetKeyErrorCode::ERROR_UNKNOWN => ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
- GetKeyErrorCode::ERROR_PERMANENT => ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
- GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY => {
- ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY
- }
- GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH => {
- ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE
- }
- _ => {
- log::error!("Unexpected error from rkpd: {error:?}");
- ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR
- }
- };
- self.key_tx.send(Err(Error::Rc(rc)).context(source_location_msg!(
+ self.key_tx.send(Err(Error::GetKeyFailed(error)).context(source_location_msg!(
"GetKeyCallback failed: {:?} {:?}",
error,
description
@@ -195,7 +217,7 @@
if let Err(e) = registration.cancelGetKey(&cb) {
log::error!("IRegistration::cancelGetKey failed: {:?}", e);
}
- Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
+ Err(Error::RetryableTimeout)
.context(source_location_msg!("Waiting for RKPD key timed out: {:?}", e))
}
Ok(v) => v.unwrap(),
@@ -234,9 +256,9 @@
}
fn onError(&self, error: &str) -> binder::Result<()> {
- log::error!("IGetRegistrationCallback failed: {error}");
+ log::error!("IStoreUpgradedKeyCallback failed: {error}");
self.completer.send(
- Err(Error::Rc(ResponseCode::SYSTEM_ERROR))
+ Err(Error::StoreUpgradedKeyFailed)
.context(source_location_msg!("Failed to store upgraded key: {:?}", error)),
);
Ok(())
@@ -256,7 +278,7 @@
.context(source_location_msg!("Failed to store upgraded blob with RKPD."))?;
match timeout(RKPD_TIMEOUT, rx).await {
- Err(e) => Err(Error::Rc(ResponseCode::SYSTEM_ERROR))
+ Err(e) => Err(Error::Timeout)
.context(source_location_msg!("Waiting for RKPD to complete storing key: {:?}", e)),
Ok(v) => v.unwrap(),
}
@@ -291,7 +313,6 @@
mod tests {
use super::*;
use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration;
- use std::collections::HashMap;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, Mutex};
@@ -415,10 +436,7 @@
assert!(cb.onCancel().is_ok());
let result = tokio_rt().block_on(rx).unwrap();
- assert_eq!(
- result.unwrap_err().downcast::<Error>().unwrap(),
- Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
- );
+ assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::RequestCancelled);
}
#[test]
@@ -428,10 +446,7 @@
assert!(cb.onError("error").is_ok());
let result = tokio_rt().block_on(rx).unwrap();
- assert_eq!(
- result.unwrap_err().downcast::<Error>().unwrap(),
- Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
- );
+ assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::GetRegistrationFailed);
}
#[test]
@@ -453,29 +468,11 @@
assert!(cb.onCancel().is_ok());
let result = tokio_rt().block_on(rx).unwrap();
- assert_eq!(
- result.unwrap_err().downcast::<Error>().unwrap(),
- Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
- );
+ assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::RequestCancelled);
}
#[test]
fn test_get_key_cb_error() {
- let error_mapping = HashMap::from([
- (GetKeyErrorCode::ERROR_UNKNOWN, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
- (GetKeyErrorCode::ERROR_PERMANENT, ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR),
- (
- GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY,
- ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY,
- ),
- (
- GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH,
- ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE,
- ),
- ]);
-
- // Loop over the generated list of enum values to better ensure this test stays in
- // sync with the AIDL.
for get_key_error in GetKeyErrorCode::enum_values() {
let (tx, rx) = oneshot::channel();
let cb = GetKeyCallback::new_native_binder(tx);
@@ -484,7 +481,7 @@
let result = tokio_rt().block_on(rx).unwrap();
assert_eq!(
result.unwrap_err().downcast::<Error>().unwrap(),
- Error::Rc(error_mapping[&get_key_error]),
+ Error::GetKeyFailed(get_key_error),
);
}
}
@@ -505,10 +502,7 @@
assert!(cb.onError("oh no! it failed").is_ok());
let result = tokio_rt().block_on(rx).unwrap();
- assert_eq!(
- result.unwrap_err().downcast::<Error>().unwrap(),
- Error::Rc(ResponseCode::SYSTEM_ERROR)
- );
+ assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::StoreUpgradedKeyFailed);
}
#[test]
@@ -532,10 +526,7 @@
let result =
tokio_rt().block_on(get_rkpd_attestation_key_from_registration_async(®istration, 0));
- assert_eq!(
- result.unwrap_err().downcast::<Error>().unwrap(),
- Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
- );
+ assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::RetryableTimeout);
}
#[test]
@@ -560,10 +551,7 @@
&[],
&[],
));
- assert_eq!(
- result.unwrap_err().downcast::<Error>().unwrap(),
- Error::Rc(ResponseCode::SYSTEM_ERROR)
- );
+ assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::Timeout);
}
#[test]
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index 1a048b6..b4c57fb 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -28,11 +28,13 @@
//! be added every time an error is forwarded.
pub use android_hardware_security_keymint::aidl::android::hardware::security::keymint::ErrorCode::ErrorCode;
+use android_security_rkp_aidl::aidl::android::security::rkp::IGetKeyCallback::ErrorCode::ErrorCode as GetKeyErrorCode;
pub use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
use android_system_keystore2::binder::{
ExceptionCode, Result as BinderResult, Status as BinderStatus, StatusCode,
};
use keystore2_selinux as selinux;
+use rkpd_client::Error as RkpdError;
use std::cmp::PartialEq;
use std::ffi::CString;
@@ -66,6 +68,49 @@
}
}
+impl From<RkpdError> for Error {
+ fn from(e: RkpdError) -> Self {
+ match e {
+ RkpdError::RequestCancelled | RkpdError::GetRegistrationFailed => {
+ Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR)
+ }
+ RkpdError::GetKeyFailed(e) => {
+ let response_code = match e {
+ GetKeyErrorCode::ERROR_UNKNOWN => ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
+ GetKeyErrorCode::ERROR_PERMANENT => ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
+ GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY => {
+ ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY
+ }
+ GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH => {
+ ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE
+ }
+ _ => {
+ log::error!("Unexpected get key error from rkpd: {e:?}");
+ ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR
+ }
+ };
+ Error::Rc(response_code)
+ }
+ RkpdError::RetryableTimeout => Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
+ RkpdError::StoreUpgradedKeyFailed | RkpdError::Timeout => {
+ Error::Rc(ResponseCode::SYSTEM_ERROR)
+ }
+ RkpdError::BinderTransaction(s) => Error::BinderTransaction(s),
+ }
+ }
+}
+
+/// Maps an `rkpd_client::Error` that is wrapped with an `anyhow::Error` to a keystore2 `Error`.
+pub fn wrapped_rkpd_error_to_ks_error(e: &anyhow::Error) -> Error {
+ match e.downcast_ref::<RkpdError>() {
+ Some(e) => Error::from(*e),
+ None => {
+ log::error!("Failed to downcast the anyhow::Error to rkpd_client::Error: {e:?}");
+ Error::Rc(ResponseCode::SYSTEM_ERROR)
+ }
+ }
+}
+
/// Helper function to map the binder status we get from calls into KeyMint
/// to a Keystore Error. We don't create an anyhow error here to make
/// it easier to evaluate KeyMint errors, which we must do in some cases, e.g.,
@@ -409,4 +454,35 @@
expected_error_string
);
}
+
+ #[test]
+ fn rkpd_error_is_in_sync_with_response_code() {
+ let error_mapping = [
+ (RkpdError::RequestCancelled, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
+ (RkpdError::GetRegistrationFailed, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
+ (
+ RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_UNKNOWN),
+ ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
+ ),
+ (
+ RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PERMANENT),
+ ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
+ ),
+ (
+ RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY),
+ ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY,
+ ),
+ (
+ RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH),
+ ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE,
+ ),
+ (RkpdError::StoreUpgradedKeyFailed, ResponseCode::SYSTEM_ERROR),
+ (RkpdError::RetryableTimeout, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
+ (RkpdError::Timeout, ResponseCode::SYSTEM_ERROR),
+ ];
+ for (rkpd_error, expected_response_code) in error_mapping {
+ let e: Error = rkpd_error.into();
+ assert_eq!(e, Error::Rc(expected_response_code));
+ }
+ }
} // mod tests
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index e51a319..c0eecd8 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -37,7 +37,6 @@
pub mod permission;
pub mod raw_device;
pub mod remote_provisioning;
-pub mod rkpd_client;
pub mod security_level;
pub mod service;
pub mod shared_secret_negotiation;
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index 3f7833e..a386d96 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -31,12 +31,13 @@
use keystore2_crypto::parse_subject_from_certificate;
use crate::database::Uuid;
+use crate::error::wrapped_rkpd_error_to_ks_error;
use crate::globals::get_remotely_provisioned_component_name;
use crate::ks_err;
use crate::metrics_store::log_rkp_error_stats;
-use crate::rkpd_client::get_rkpd_attestation_key;
use crate::watchdog_helper::watchdog as wd;
use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
+use rkpd_client::get_rkpd_attestation_key;
/// Contains helper functions to check if remote provisioning is enabled on the system and, if so,
/// to assign and retrieve attestation keys and certificate chains.
@@ -102,7 +103,7 @@
Err(e) => {
if self.is_rkp_only() {
log::error!("Error occurred: {:?}", e);
- return Err(e);
+ return Err(wrapped_rkpd_error_to_ks_error(&e)).context(format!("{e:?}"));
}
log::warn!("Error occurred: {:?}", e);
log_rkp_error_stats(
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 830fbe1..7a27452 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -19,7 +19,9 @@
log_key_deleted, log_key_generated, log_key_imported, log_key_integrity_violation,
};
use crate::database::{BlobInfo, CertificateInfo, KeyIdGuard};
-use crate::error::{self, map_km_error, map_or_log_err, Error, ErrorCode};
+use crate::error::{
+ self, map_km_error, map_or_log_err, wrapped_rkpd_error_to_ks_error, Error, ErrorCode,
+};
use crate::globals::{
get_remotely_provisioned_component_name, DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY,
};
@@ -28,7 +30,6 @@
use crate::ks_err;
use crate::metrics_store::log_key_creation_event_stats;
use crate::remote_provisioning::RemProvState;
-use crate::rkpd_client::store_rkpd_attestation_key;
use crate::super_key::{KeyBlob, SuperKeyManager};
use crate::utils::{
check_device_attestation_permissions, check_key_permission,
@@ -62,6 +63,7 @@
KeyMetadata::KeyMetadata, KeyParameters::KeyParameters, ResponseCode::ResponseCode,
};
use anyhow::{anyhow, Context, Result};
+use rkpd_client::store_rkpd_attestation_key;
use std::convert::TryInto;
use std::time::SystemTime;
@@ -900,8 +902,11 @@
f,
|upgraded_blob| {
let _wp = wd::watch_millis("Calling store_rkpd_attestation_key()", 500);
- store_rkpd_attestation_key(&rpc_name, key_blob, upgraded_blob)
- .context(ks_err!("Failed store_rkpd_attestation_key()."))
+ if let Err(e) = store_rkpd_attestation_key(&rpc_name, key_blob, upgraded_blob) {
+ Err(wrapped_rkpd_error_to_ks_error(&e)).context(format!("{e:?}"))
+ } else {
+ Ok(())
+ }
},
)
.context(ks_err!())
@@ -1068,13 +1073,13 @@
use super::*;
use crate::error::map_km_error;
use crate::globals::get_keymint_device;
- use crate::rkpd_client::{get_rkpd_attestation_key, store_rkpd_attestation_key};
use crate::utils::upgrade_keyblob_if_required_with;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, AttestationKey::AttestationKey, KeyParameter::KeyParameter,
KeyParameterValue::KeyParameterValue, Tag::Tag,
};
use keystore2_crypto::parse_subject_from_certificate;
+ use rkpd_client::get_rkpd_attestation_key;
#[test]
// This is a helper for a manual test. We want to check that after a system upgrade RKPD
diff --git a/keystore2/test_utils/authorizations.rs b/keystore2/test_utils/authorizations.rs
index 02ceb83..61260c7 100644
--- a/keystore2/test_utils/authorizations.rs
+++ b/keystore2/test_utils/authorizations.rs
@@ -335,6 +335,15 @@
self.0.push(KeyParameter { tag: Tag::APPLICATION_ID, value: KeyParameterValue::Blob(b) });
self
}
+
+ /// Set device-unique-attestation.
+ pub fn device_unique_attestation(mut self) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::DEVICE_UNIQUE_ATTESTATION,
+ value: KeyParameterValue::BoolValue(true),
+ });
+ self
+ }
}
impl Deref for AuthSetBuilder {
diff --git a/keystore2/test_utils/ffi_test_utils.rs b/keystore2/test_utils/ffi_test_utils.rs
index 5d6bf46..1ccdcc8 100644
--- a/keystore2/test_utils/ffi_test_utils.rs
+++ b/keystore2/test_utils/ffi_test_utils.rs
@@ -50,7 +50,19 @@
/// Validate given certificate chain.
pub fn validate_certchain(cert_buf: &[u8]) -> Result<bool, Error> {
- if ffi::validateCertChain(cert_buf.to_vec(), cert_buf.len().try_into().unwrap(), true) {
+ validate_certchain_with_strict_issuer_check(cert_buf, true)
+}
+
+/// Validate given certificate chain with an option to validate the issuer.
+pub fn validate_certchain_with_strict_issuer_check(
+ cert_buf: &[u8],
+ strict_issuer_check: bool,
+) -> Result<bool, Error> {
+ if ffi::validateCertChain(
+ cert_buf.to_vec(),
+ cert_buf.len().try_into().unwrap(),
+ strict_issuer_check,
+ ) {
return Ok(true);
}
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index badc480..9ddc87a 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -40,7 +40,7 @@
use crate::ffi_test_utils::{
get_os_patchlevel, get_os_version, get_value_from_attest_record, get_vendor_patchlevel,
- validate_certchain,
+ validate_certchain_with_strict_issuer_check,
};
/// Shell namespace.
@@ -1426,7 +1426,10 @@
let mut cert_chain: Vec<u8> = Vec::new();
cert_chain.extend(key_metadata.certificate.as_ref().unwrap());
cert_chain.extend(key_metadata.certificateChain.as_ref().unwrap());
- validate_certchain(&cert_chain).expect("Error while validating cert chain");
+ let strict_issuer_check =
+ !(gen_params.iter().any(|kp| kp.tag == Tag::DEVICE_UNIQUE_ATTESTATION));
+ validate_certchain_with_strict_issuer_check(&cert_chain, strict_issuer_check)
+ .expect("Error while validating cert chain");
}
if let Some(challenge_param) =
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index c9ef298..3532a35 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -488,12 +488,12 @@
fn get_attestation_ids(keystore2: &binder::Strong<dyn IKeystoreService>) -> Vec<(Tag, Vec<u8>)> {
let attest_ids = vec![
- (Tag::ATTESTATION_ID_BRAND, "ro.product.brand_for_attestation"),
- (Tag::ATTESTATION_ID_DEVICE, "ro.product.device"),
- (Tag::ATTESTATION_ID_PRODUCT, "ro.product.name_for_attestation"),
- (Tag::ATTESTATION_ID_SERIAL, "ro.serialno"),
- (Tag::ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer"),
- (Tag::ATTESTATION_ID_MODEL, "ro.product.model_for_attestation"),
+ (Tag::ATTESTATION_ID_BRAND, "brand"),
+ (Tag::ATTESTATION_ID_DEVICE, "device"),
+ (Tag::ATTESTATION_ID_PRODUCT, "name"),
+ (Tag::ATTESTATION_ID_SERIAL, "serialno"),
+ (Tag::ATTESTATION_ID_MANUFACTURER, "manufacturer"),
+ (Tag::ATTESTATION_ID_MODEL, "model"),
(Tag::ATTESTATION_ID_IMEI, ""), //Get this value from Telephony service.
(Tag::ATTESTATION_ID_SECOND_IMEI, ""), //Get this value from Telephony service.
];
diff --git a/keystore2/tests/keystore2_client_device_unique_attestation_tests.rs b/keystore2/tests/keystore2_client_device_unique_attestation_tests.rs
new file mode 100644
index 0000000..cf88fc5
--- /dev/null
+++ b/keystore2/tests/keystore2_client_device_unique_attestation_tests.rs
@@ -0,0 +1,406 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, ErrorCode::ErrorCode,
+ KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, SecurityLevel::SecurityLevel, Tag::Tag,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error,
+};
+
+use keystore2_test_utils::ffi_test_utils::get_value_from_attest_record;
+
+use crate::keystore2_client_test_utils::{
+ delete_app_key, get_attest_id_value, is_second_imei_id_attestation_required,
+ perform_sample_asym_sign_verify_op,
+};
+
+/// This macro is used for generating device unique attested EC key with device id attestation.
+macro_rules! test_ec_key_device_unique_attestation_id {
+ ( $test_name:ident, $tag:expr, $prop_name:expr ) => {
+ #[test]
+ fn $test_name() {
+ generate_ec_key_device_unique_attested_with_id_attest($tag, $prop_name);
+ }
+ };
+}
+
+/// This macro is used for generating device unique attested RSA key with device id attestation.
+macro_rules! test_rsa_key_device_unique_attestation_id {
+ ( $test_name:ident, $tag:expr, $prop_name:expr ) => {
+ #[test]
+ fn $test_name() {
+ generate_rsa_key_device_unique_attested_with_id_attest($tag, $prop_name);
+ }
+ };
+}
+
+fn generate_ec_key_device_unique_attested_with_id_attest(attest_id_tag: Tag, prop_name: &str) {
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+ generate_device_unique_attested_key_with_device_attest_ids(
+ gen_params,
+ attest_id_tag,
+ prop_name,
+ );
+}
+
+fn generate_rsa_key_device_unique_attested_with_id_attest(attest_id_tag: Tag, prop_name: &str) {
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .rsa_public_exponent(65537)
+ .key_size(2048)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .padding_mode(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+ generate_device_unique_attested_key_with_device_attest_ids(
+ gen_params,
+ attest_id_tag,
+ prop_name,
+ );
+}
+
+fn add_attest_id_auth(
+ gen_params: authorizations::AuthSetBuilder,
+ attest_id_tag: Tag,
+ value: Vec<u8>,
+) -> authorizations::AuthSetBuilder {
+ match attest_id_tag {
+ Tag::ATTESTATION_ID_BRAND => gen_params.attestation_device_brand(value),
+ Tag::ATTESTATION_ID_DEVICE => gen_params.attestation_device_name(value),
+ Tag::ATTESTATION_ID_PRODUCT => gen_params.attestation_device_product_name(value),
+ Tag::ATTESTATION_ID_SERIAL => gen_params.attestation_device_serial(value),
+ Tag::ATTESTATION_ID_MANUFACTURER => gen_params.attestation_device_manufacturer(value),
+ Tag::ATTESTATION_ID_MODEL => gen_params.attestation_device_model(value),
+ Tag::ATTESTATION_ID_IMEI => gen_params.attestation_device_imei(value),
+ Tag::ATTESTATION_ID_SECOND_IMEI => gen_params.attestation_device_second_imei(value),
+ _ => {
+ panic!("Unknown attestation id");
+ }
+ }
+}
+
+/// Generate a device unique attested key with attestation of the device's identifiers. Test should
+/// succeed in generating a attested key with attestation of device identifiers. Test might fail on
+/// devices which don't support device id attestation with error response code `CANNOT_ATTEST_IDS`.
+fn generate_device_unique_attested_key_with_device_attest_ids(
+ gen_params: authorizations::AuthSetBuilder,
+ attest_id: Tag,
+ prop_name: &str,
+) {
+ let keystore2 = get_keystore_service();
+ let result =
+ key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::STRONGBOX));
+ if result.is_err() {
+ assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+ return;
+ }
+ let sec_level = result.unwrap();
+
+ if attest_id == Tag::ATTESTATION_ID_SECOND_IMEI
+ && !is_second_imei_id_attestation_required(&keystore2)
+ {
+ return;
+ }
+
+ if let Some(value) = get_attest_id_value(attest_id, prop_name) {
+ if value.is_empty() {
+ return;
+ }
+ let gen_params = add_attest_id_auth(gen_params, attest_id, value.clone());
+ let alias = "ks_test_device_unique_attest_id_test";
+ match key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ )) {
+ Ok(key_metadata) => {
+ let attest_id_value = get_value_from_attest_record(
+ key_metadata.certificate.as_ref().unwrap(),
+ attest_id,
+ key_metadata.keySecurityLevel,
+ )
+ .expect("Attest id verification failed.");
+ assert_eq!(attest_id_value, value);
+ delete_app_key(&keystore2, alias).unwrap();
+ }
+ Err(e) => {
+ assert_eq!(e, Error::Km(ErrorCode::CANNOT_ATTEST_IDS));
+ }
+ }
+ }
+}
+
+/// Try generate a key with `DEVICE_UNIQUE_ATTESTATION` using `TRUSTED_ENVIRONMENT` security level.
+/// Test should fail to generate a key with error code `INVALID_ARGUMENT`
+#[test]
+fn keystore2_gen_key_device_unique_attest_with_default_sec_level_unimplemented() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+
+ let alias = "ks_test_auth_tags_test";
+ let result = key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INVALID_ARGUMENT), result.unwrap_err());
+}
+
+/// Generate a EC key with `DEVICE_UNIQUE_ATTESTATION` using `STRONGBOX` security level.
+/// Test should create a key successfully, verify key characteristics, cert-chain signatures and
+/// use it for performing an operation.
+#[test]
+fn keystore2_gen_ec_key_device_unique_attest_with_strongbox_sec_level_test_success() {
+ let keystore2 = get_keystore_service();
+ let result =
+ key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::STRONGBOX));
+ if result.is_err() {
+ assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+ return;
+ }
+
+ let sec_level = result.unwrap();
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+
+ let alias = "ks_device_unique_ec_key_attest_test";
+ match key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ )) {
+ Ok(key_metadata) => {
+ perform_sample_asym_sign_verify_op(
+ &sec_level,
+ &key_metadata,
+ None,
+ Some(Digest::SHA_2_256),
+ );
+ delete_app_key(&keystore2, alias).unwrap();
+ }
+ Err(e) => {
+ assert_eq!(e, Error::Km(ErrorCode::CANNOT_ATTEST_IDS));
+ }
+ }
+}
+
+/// Generate a RSA key with `DEVICE_UNIQUE_ATTESTATION` using `STRONGBOX` security level.
+/// Test should create a key successfully, verify key characteristics, cert-chain signatures and
+/// use it for performing an operation.
+#[test]
+fn keystore2_gen_rsa_key_device_unique_attest_with_strongbox_sec_level_test_success() {
+ let keystore2 = get_keystore_service();
+ let result =
+ key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::STRONGBOX));
+ if result.is_err() {
+ assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+ return;
+ }
+
+ let sec_level = result.unwrap();
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .rsa_public_exponent(65537)
+ .key_size(2048)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .padding_mode(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+
+ let alias = "ks_device_unique_rsa_key_attest_test";
+ match key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ )) {
+ Ok(key_metadata) => {
+ perform_sample_asym_sign_verify_op(
+ &sec_level,
+ &key_metadata,
+ Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+ Some(Digest::SHA_2_256),
+ );
+ delete_app_key(&keystore2, alias).unwrap();
+ }
+ Err(e) => {
+ assert_eq!(e, Error::Km(ErrorCode::CANNOT_ATTEST_IDS));
+ }
+ }
+}
+
+/// Try to generate a device unique attested key with attestation of invalid device's identifiers.
+/// Test should fail with error response code `CANNOT_ATTEST_IDS`.
+#[test]
+fn keystore2_device_unique_attest_key_fails_with_invalid_attestation_id() {
+ let keystore2 = get_keystore_service();
+ let result =
+ key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::STRONGBOX));
+ if result.is_err() {
+ assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+ return;
+ }
+
+ let sec_level = result.unwrap();
+ let attest_id_params = vec![
+ (Tag::ATTESTATION_ID_BRAND, b"invalid-brand".to_vec()),
+ (Tag::ATTESTATION_ID_DEVICE, b"invalid-device-name".to_vec()),
+ (Tag::ATTESTATION_ID_PRODUCT, b"invalid-product-name".to_vec()),
+ (Tag::ATTESTATION_ID_SERIAL, b"invalid-ro-serial".to_vec()),
+ (Tag::ATTESTATION_ID_MANUFACTURER, b"invalid-ro-product-manufacturer".to_vec()),
+ (Tag::ATTESTATION_ID_MODEL, b"invalid-ro-product-model".to_vec()),
+ (Tag::ATTESTATION_ID_IMEI, b"invalid-imei".to_vec()),
+ ];
+
+ for (attest_id, value) in attest_id_params {
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+ let alias = "ks_ec_device_unique_attested_test_key_fail";
+ let gen_params = add_attest_id_auth(gen_params, attest_id, value.clone());
+
+ let result = key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ ));
+ assert!(result.is_err());
+ assert!(matches!(result.unwrap_err(), Error::Km(ErrorCode::CANNOT_ATTEST_IDS)));
+ }
+}
+
+// Below macros generate tests for generating device unique attested EC keys with attestation
+// of the device's identifiers.
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_brand,
+ Tag::ATTESTATION_ID_BRAND,
+ "ro.product.brand_for_attestation"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_device,
+ Tag::ATTESTATION_ID_DEVICE,
+ "ro.product.device"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_product,
+ Tag::ATTESTATION_ID_PRODUCT,
+ "ro.product.name_for_attestation"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_serial,
+ Tag::ATTESTATION_ID_SERIAL,
+ "ro.serialno"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_manufacturer,
+ Tag::ATTESTATION_ID_MANUFACTURER,
+ "ro.product.manufacturer"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_model,
+ Tag::ATTESTATION_ID_MODEL,
+ "ro.product.model_for_attestation"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_imei,
+ Tag::ATTESTATION_ID_IMEI,
+ ""
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_second_imei,
+ Tag::ATTESTATION_ID_SECOND_IMEI,
+ ""
+);
+
+// Below macros generate tests for generating device unique attested RSA keys with attestation
+// of the device's identifiers.
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_brand,
+ Tag::ATTESTATION_ID_BRAND,
+ "ro.product.brand_for_attestation"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_device,
+ Tag::ATTESTATION_ID_DEVICE,
+ "ro.product.device"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_product,
+ Tag::ATTESTATION_ID_PRODUCT,
+ "ro.product.name_for_attestation"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_serial,
+ Tag::ATTESTATION_ID_SERIAL,
+ "ro.serialno"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_manufacturer,
+ Tag::ATTESTATION_ID_MANUFACTURER,
+ "ro.product.manufacturer"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_model,
+ Tag::ATTESTATION_ID_MODEL,
+ "ro.product.model_for_attestation"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_imei,
+ Tag::ATTESTATION_ID_IMEI,
+ ""
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_second_imei,
+ Tag::ATTESTATION_ID_SECOND_IMEI,
+ ""
+);
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index e76c64b..364cec4 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -517,30 +517,20 @@
match attest_id {
Tag::ATTESTATION_ID_IMEI => get_imei(0),
Tag::ATTESTATION_ID_SECOND_IMEI => get_imei(1),
- Tag::ATTESTATION_ID_BRAND => {
- let prop_val = get_system_prop(prop_name);
- if prop_val.is_empty() {
- Some(get_system_prop("ro.product.brand"))
- } else {
+ Tag::ATTESTATION_ID_SERIAL => Some(get_system_prop(format!("ro.{}", prop_name).as_str())),
+ _ => {
+ let prop_val =
+ get_system_prop(format!("ro.product.{}_for_attestation", prop_name).as_str());
+ if !prop_val.is_empty() {
Some(prop_val)
+ } else {
+ let prop_val = get_system_prop(format!("ro.product.vendor.{}", prop_name).as_str());
+ if !prop_val.is_empty() {
+ Some(prop_val)
+ } else {
+ Some(get_system_prop(format!("ro.product.{}", prop_name).as_str()))
+ }
}
}
- Tag::ATTESTATION_ID_PRODUCT => {
- let prop_val = get_system_prop(prop_name);
- if prop_val.is_empty() {
- Some(get_system_prop("ro.product.name"))
- } else {
- Some(prop_val)
- }
- }
- Tag::ATTESTATION_ID_MODEL => {
- let prop_val = get_system_prop(prop_name);
- if prop_val.is_empty() {
- Some(get_system_prop("ro.product.model"))
- } else {
- Some(prop_val)
- }
- }
- _ => Some(get_system_prop(prop_name)),
}
}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index ac7f19f..a0c140a 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -17,6 +17,7 @@
pub mod keystore2_client_attest_key_tests;
pub mod keystore2_client_authorizations_tests;
pub mod keystore2_client_delete_key_tests;
+pub mod keystore2_client_device_unique_attestation_tests;
pub mod keystore2_client_ec_key_tests;
pub mod keystore2_client_grant_key_tests;
pub mod keystore2_client_hmac_key_tests;