Merge changes from topic "super-key-cleanups"
* changes:
Add tests for super_key.rs
Simplify control flow for user unlocking.
Remove unlock_user_key function
Separate logic for user reset, remove, and init
Separate hybrid key logic into a helper function.
Make super_encrypt_on_key_init inline
diff --git a/diced/open_dice/src/bcc.rs b/diced/open_dice/src/bcc.rs
index 1575113..f9c6a34 100644
--- a/diced/open_dice/src/bcc.rs
+++ b/diced/open_dice/src/bcc.rs
@@ -50,9 +50,12 @@
let mut buffer_size = 0;
// SAFETY: The function writes to the buffer, within the given bounds, and only reads the
// input values. It writes its result to buffer_size.
- check_result(unsafe {
- BccFormatConfigDescriptor(&values, buffer.len(), buffer.as_mut_ptr(), &mut buffer_size)
- })?;
+ check_result(
+ unsafe {
+ BccFormatConfigDescriptor(&values, buffer.len(), buffer.as_mut_ptr(), &mut buffer_size)
+ },
+ buffer_size,
+ )?;
Ok(buffer_size)
}
@@ -73,21 +76,24 @@
// to `next_bcc` and next CDI values within its bounds. It also reads
// `input_values` as a constant input and doesn't store any pointer.
// The first argument can be null and is not used in the current implementation.
- check_result(unsafe {
- BccMainFlow(
- ptr::null_mut(), // context
- current_cdi_attest.as_ptr(),
- current_cdi_seal.as_ptr(),
- current_bcc.as_ptr(),
- current_bcc.len(),
- input_values.as_ptr(),
- next_bcc.len(),
- next_bcc.as_mut_ptr(),
- &mut next_bcc_size,
- next_cdi_values.cdi_attest.as_mut_ptr(),
- next_cdi_values.cdi_seal.as_mut_ptr(),
- )
- })?;
+ check_result(
+ unsafe {
+ BccMainFlow(
+ ptr::null_mut(), // context
+ current_cdi_attest.as_ptr(),
+ current_cdi_seal.as_ptr(),
+ current_bcc.as_ptr(),
+ current_bcc.len(),
+ input_values.as_ptr(),
+ next_bcc.len(),
+ next_bcc.as_mut_ptr(),
+ &mut next_bcc_size,
+ next_cdi_values.cdi_attest.as_mut_ptr(),
+ next_cdi_values.cdi_seal.as_mut_ptr(),
+ )
+ },
+ next_bcc_size,
+ )?;
Ok(next_bcc_size)
}
@@ -106,17 +112,20 @@
// within its bounds,
// It also reads `input_values` as a constant input and doesn't store any pointer.
// The first argument can be null and is not used in the current implementation.
- check_result(unsafe {
- BccHandoverMainFlow(
- ptr::null_mut(), // context
- current_bcc_handover.as_ptr(),
- current_bcc_handover.len(),
- input_values.as_ptr(),
- next_bcc_handover.len(),
- next_bcc_handover.as_mut_ptr(),
- &mut next_bcc_handover_size,
- )
- })?;
+ check_result(
+ unsafe {
+ BccHandoverMainFlow(
+ ptr::null_mut(), // context
+ current_bcc_handover.as_ptr(),
+ current_bcc_handover.len(),
+ input_values.as_ptr(),
+ next_bcc_handover.len(),
+ next_bcc_handover.as_mut_ptr(),
+ &mut next_bcc_handover_size,
+ )
+ },
+ next_bcc_handover_size,
+ )?;
Ok(next_bcc_handover_size)
}
@@ -158,16 +167,19 @@
let mut bcc_size = 0;
// SAFETY: The `bcc_handover` is only read and never stored and the returned pointers should all
// point within the address range of the `bcc_handover` or be NULL.
- check_result(unsafe {
- BccHandoverParse(
- bcc_handover.as_ptr(),
- bcc_handover.len(),
- &mut cdi_attest,
- &mut cdi_seal,
- &mut bcc,
- &mut bcc_size,
- )
- })?;
+ check_result(
+ unsafe {
+ BccHandoverParse(
+ bcc_handover.as_ptr(),
+ bcc_handover.len(),
+ &mut cdi_attest,
+ &mut cdi_seal,
+ &mut bcc,
+ &mut bcc_size,
+ )
+ },
+ bcc_size,
+ )?;
let cdi_attest = sub_slice(bcc_handover, cdi_attest, CDI_SIZE)?;
let cdi_seal = sub_slice(bcc_handover, cdi_seal, CDI_SIZE)?;
let bcc = sub_slice(bcc_handover, bcc, bcc_size).ok();
diff --git a/diced/open_dice/src/dice.rs b/diced/open_dice/src/dice.rs
index 6e2df81..0704d21 100644
--- a/diced/open_dice/src/dice.rs
+++ b/diced/open_dice/src/dice.rs
@@ -219,13 +219,16 @@
let mut seed = PrivateKeySeed::default();
// SAFETY: The function writes to the buffer within the given bounds, and only reads the
// input values. The first argument context is not used in this function.
- check_result(unsafe {
- DiceDeriveCdiPrivateKeySeed(
- ptr::null_mut(), // context
- cdi_attest.as_ptr(),
- seed.as_mut_ptr(),
- )
- })?;
+ check_result(
+ unsafe {
+ DiceDeriveCdiPrivateKeySeed(
+ ptr::null_mut(), // context
+ cdi_attest.as_ptr(),
+ seed.as_mut_ptr(),
+ )
+ },
+ seed.0.len(),
+ )?;
Ok(seed)
}
@@ -234,14 +237,17 @@
let mut id = [0u8; ID_SIZE];
// SAFETY: The function writes to the buffer within the given bounds, and only reads the
// input values. The first argument context is not used in this function.
- check_result(unsafe {
- DiceDeriveCdiCertificateId(
- ptr::null_mut(), // context
- cdi_public_key.as_ptr(),
- cdi_public_key.len(),
- id.as_mut_ptr(),
- )
- })?;
+ check_result(
+ unsafe {
+ DiceDeriveCdiCertificateId(
+ ptr::null_mut(), // context
+ cdi_public_key.as_ptr(),
+ cdi_public_key.len(),
+ id.as_mut_ptr(),
+ )
+ },
+ id.len(),
+ )?;
Ok(id)
}
@@ -261,18 +267,21 @@
// SAFETY: The function only reads the current CDI values and inputs and writes
// to `next_cdi_certificate` and next CDI values within its bounds.
// The first argument can be null and is not used in the current implementation.
- check_result(unsafe {
- DiceMainFlow(
- ptr::null_mut(), // context
- current_cdi_attest.as_ptr(),
- current_cdi_seal.as_ptr(),
- input_values.as_ptr(),
- next_cdi_certificate.len(),
- next_cdi_certificate.as_mut_ptr(),
- &mut next_cdi_certificate_actual_size,
- next_cdi_values.cdi_attest.as_mut_ptr(),
- next_cdi_values.cdi_seal.as_mut_ptr(),
- )
- })?;
+ check_result(
+ unsafe {
+ DiceMainFlow(
+ ptr::null_mut(), // context
+ current_cdi_attest.as_ptr(),
+ current_cdi_seal.as_ptr(),
+ input_values.as_ptr(),
+ next_cdi_certificate.len(),
+ next_cdi_certificate.as_mut_ptr(),
+ &mut next_cdi_certificate_actual_size,
+ next_cdi_values.cdi_attest.as_mut_ptr(),
+ next_cdi_values.cdi_seal.as_mut_ptr(),
+ )
+ },
+ next_cdi_certificate_actual_size,
+ )?;
Ok(next_cdi_certificate_actual_size)
}
diff --git a/diced/open_dice/src/error.rs b/diced/open_dice/src/error.rs
index 4c67335..53ffd2d 100644
--- a/diced/open_dice/src/error.rs
+++ b/diced/open_dice/src/error.rs
@@ -26,7 +26,7 @@
/// Provided input was invalid.
InvalidInput,
/// Provided buffer was too small.
- BufferTooSmall,
+ BufferTooSmall(usize),
/// Platform error.
PlatformError,
}
@@ -39,7 +39,9 @@
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::InvalidInput => write!(f, "invalid input"),
- Self::BufferTooSmall => write!(f, "buffer too small"),
+ Self::BufferTooSmall(buffer_required_size) => {
+ write!(f, "buffer too small. Required {buffer_required_size} bytes.")
+ }
Self::PlatformError => write!(f, "platform error"),
}
}
@@ -49,11 +51,13 @@
pub type Result<T> = result::Result<T, DiceError>;
/// Checks the given `DiceResult`. Returns an error if it's not OK.
-pub fn check_result(result: DiceResult) -> Result<()> {
+pub(crate) fn check_result(result: DiceResult, buffer_required_size: usize) -> Result<()> {
match result {
DiceResult::kDiceResultOk => Ok(()),
DiceResult::kDiceResultInvalidInput => Err(DiceError::InvalidInput),
- DiceResult::kDiceResultBufferTooSmall => Err(DiceError::BufferTooSmall),
+ DiceResult::kDiceResultBufferTooSmall => {
+ Err(DiceError::BufferTooSmall(buffer_required_size))
+ }
DiceResult::kDiceResultPlatformError => Err(DiceError::PlatformError),
}
}
diff --git a/diced/open_dice/src/lib.rs b/diced/open_dice/src/lib.rs
index e7ec56b..4a85a1e 100644
--- a/diced/open_dice/src/lib.rs
+++ b/diced/open_dice/src/lib.rs
@@ -36,7 +36,7 @@
DiceArtifacts, DiceMode, Hash, Hidden, InlineConfig, InputValues, PrivateKey, PrivateKeySeed,
PublicKey, Signature, CDI_SIZE, HASH_SIZE, HIDDEN_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
};
-pub use error::{check_result, DiceError, Result};
+pub use error::{DiceError, Result};
pub use ops::{generate_certificate, hash, kdf, keypair_from_seed, sign, verify};
#[cfg(feature = "std")]
pub use retry::{
diff --git a/diced/open_dice/src/ops.rs b/diced/open_dice/src/ops.rs
index 8222b26..d978f86 100644
--- a/diced/open_dice/src/ops.rs
+++ b/diced/open_dice/src/ops.rs
@@ -31,14 +31,17 @@
let mut output: Hash = [0; HASH_SIZE];
// SAFETY: DiceHash takes a sized input buffer and writes to a constant-sized output buffer.
// The first argument context is not used in this function.
- check_result(unsafe {
- DiceHash(
- ptr::null_mut(), // context
- input.as_ptr(),
- input.len(),
- output.as_mut_ptr(),
- )
- })?;
+ check_result(
+ unsafe {
+ DiceHash(
+ ptr::null_mut(), // context
+ input.as_ptr(),
+ input.len(),
+ output.as_mut_ptr(),
+ )
+ },
+ output.len(),
+ )?;
Ok(output)
}
@@ -47,19 +50,22 @@
pub fn kdf(ikm: &[u8], salt: &[u8], info: &[u8], derived_key: &mut [u8]) -> Result<()> {
// SAFETY: The function writes to the `derived_key`, within the given bounds, and only reads the
// input values. The first argument context is not used in this function.
- check_result(unsafe {
- DiceKdf(
- ptr::null_mut(), // context
- derived_key.len(),
- ikm.as_ptr(),
- ikm.len(),
- salt.as_ptr(),
- salt.len(),
- info.as_ptr(),
- info.len(),
- derived_key.as_mut_ptr(),
- )
- })
+ check_result(
+ unsafe {
+ DiceKdf(
+ ptr::null_mut(), // context
+ derived_key.len(),
+ ikm.as_ptr(),
+ ikm.len(),
+ salt.as_ptr(),
+ salt.len(),
+ info.as_ptr(),
+ info.len(),
+ derived_key.as_mut_ptr(),
+ )
+ },
+ derived_key.len(),
+ )
}
/// Deterministically generates a public and private key pair from `seed`.
@@ -70,14 +76,17 @@
let mut private_key = PrivateKey::default();
// SAFETY: The function writes to the `public_key` and `private_key` within the given bounds,
// and only reads the `seed`. The first argument context is not used in this function.
- check_result(unsafe {
- DiceKeypairFromSeed(
- ptr::null_mut(), // context
- seed.as_ptr(),
- public_key.as_mut_ptr(),
- private_key.as_mut_ptr(),
- )
- })?;
+ check_result(
+ unsafe {
+ DiceKeypairFromSeed(
+ ptr::null_mut(), // context
+ seed.as_ptr(),
+ public_key.as_mut_ptr(),
+ private_key.as_mut_ptr(),
+ )
+ },
+ public_key.len(),
+ )?;
Ok((public_key, private_key))
}
@@ -86,15 +95,18 @@
let mut signature = [0u8; SIGNATURE_SIZE];
// SAFETY: The function writes to the `signature` within the given bounds, and only reads the
// message and the private key. The first argument context is not used in this function.
- check_result(unsafe {
- DiceSign(
- ptr::null_mut(), // context
- message.as_ptr(),
- message.len(),
- private_key.as_ptr(),
- signature.as_mut_ptr(),
- )
- })?;
+ check_result(
+ unsafe {
+ DiceSign(
+ ptr::null_mut(), // context
+ message.as_ptr(),
+ message.len(),
+ private_key.as_ptr(),
+ signature.as_mut_ptr(),
+ )
+ },
+ signature.len(),
+ )?;
Ok(signature)
}
@@ -102,15 +114,18 @@
pub fn verify(message: &[u8], signature: &Signature, public_key: &PublicKey) -> Result<()> {
// SAFETY: only reads the messages, signature and public key as constant values.
// The first argument context is not used in this function.
- check_result(unsafe {
- DiceVerify(
- ptr::null_mut(), // context
- message.as_ptr(),
- message.len(),
- signature.as_ptr(),
- public_key.as_ptr(),
- )
- })
+ check_result(
+ unsafe {
+ DiceVerify(
+ ptr::null_mut(), // context
+ message.as_ptr(),
+ message.len(),
+ signature.as_ptr(),
+ public_key.as_ptr(),
+ )
+ },
+ 0,
+ )
}
/// Generates an X.509 certificate from the given `subject_private_key_seed` and
@@ -127,16 +142,19 @@
let mut certificate_actual_size = 0;
// SAFETY: The function writes to the `certificate` within the given bounds, and only reads the
// input values and the key seeds. The first argument context is not used in this function.
- check_result(unsafe {
- DiceGenerateCertificate(
- ptr::null_mut(), // context
- subject_private_key_seed.as_ptr(),
- authority_private_key_seed.as_ptr(),
- input_values.as_ptr(),
- certificate.len(),
- certificate.as_mut_ptr(),
- &mut certificate_actual_size,
- )
- })?;
+ check_result(
+ unsafe {
+ DiceGenerateCertificate(
+ ptr::null_mut(), // context
+ subject_private_key_seed.as_ptr(),
+ authority_private_key_seed.as_ptr(),
+ input_values.as_ptr(),
+ certificate.len(),
+ certificate.as_mut_ptr(),
+ &mut certificate_actual_size,
+ )
+ },
+ certificate_actual_size,
+ )?;
Ok(certificate_actual_size)
}
diff --git a/diced/open_dice/src/retry.rs b/diced/open_dice/src/retry.rs
index 76a214c..3db4781 100644
--- a/diced/open_dice/src/retry.rs
+++ b/diced/open_dice/src/retry.rs
@@ -51,35 +51,21 @@
}
}
-/// Retries the given function with bigger output buffer size.
-fn retry_with_bigger_buffer<F>(mut f: F) -> Result<Vec<u8>>
+/// Retries the given function with bigger measured buffer size.
+fn retry_with_measured_buffer<F>(mut f: F) -> Result<Vec<u8>>
where
F: FnMut(&mut Vec<u8>) -> Result<usize>,
{
- const INITIAL_BUFFER_SIZE: usize = 256;
- const MAX_BUFFER_SIZE: usize = 64 * 1024 * 1024;
-
- let mut buffer = vec![0u8; INITIAL_BUFFER_SIZE];
- while buffer.len() <= MAX_BUFFER_SIZE {
- match f(&mut buffer) {
- Err(DiceError::BufferTooSmall) => {
- let new_size = buffer.len() * 2;
- buffer.resize(new_size, 0);
- }
- Err(e) => return Err(e),
- Ok(actual_size) => {
- if actual_size > buffer.len() {
- panic!(
- "actual_size larger than buffer size: open-dice function
- may have written past the end of the buffer."
- );
- }
- buffer.truncate(actual_size);
- return Ok(buffer);
- }
+ let mut buffer = Vec::new();
+ match f(&mut buffer) {
+ Err(DiceError::BufferTooSmall(actual_size)) => {
+ buffer.resize(actual_size, 0);
+ f(&mut buffer)?;
}
- }
- Err(DiceError::PlatformError)
+ Err(e) => return Err(e),
+ Ok(_) => {}
+ };
+ Ok(buffer)
}
/// Formats a configuration descriptor following the BCC's specification.
@@ -88,7 +74,7 @@
version: Option<u64>,
resettable: bool,
) -> Result<Vec<u8>> {
- retry_with_bigger_buffer(|buffer| {
+ retry_with_measured_buffer(|buffer| {
bcc_format_config_descriptor(name, version, resettable, buffer)
})
}
@@ -104,7 +90,7 @@
input_values: &InputValues,
) -> Result<OwnedDiceArtifacts> {
let mut next_cdi_values = CdiValues::default();
- let next_bcc = retry_with_bigger_buffer(|next_bcc| {
+ let next_bcc = retry_with_measured_buffer(|next_bcc| {
bcc_main_flow(
current_cdi_attest,
current_cdi_seal,
@@ -127,7 +113,7 @@
input_values: &InputValues,
) -> Result<(CdiValues, Vec<u8>)> {
let mut next_cdi_values = CdiValues::default();
- let next_cdi_certificate = retry_with_bigger_buffer(|next_cdi_certificate| {
+ let next_cdi_certificate = retry_with_measured_buffer(|next_cdi_certificate| {
dice_main_flow(
current_cdi_attest,
current_cdi_seal,
@@ -149,7 +135,7 @@
authority_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
input_values: &InputValues,
) -> Result<Vec<u8>> {
- retry_with_bigger_buffer(|certificate| {
+ retry_with_measured_buffer(|certificate| {
generate_certificate(
subject_private_key_seed,
authority_private_key_seed,
diff --git a/identity/Android.bp b/identity/Android.bp
index f4fcc0a..da0df07 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -29,6 +29,7 @@
"identity_use_latest_hal_aidl_cpp_static",
"keymint_use_latest_hal_aidl_ndk_shared",
"keymint_use_latest_hal_aidl_cpp_static",
+ "android.hardware.identity-support-lib-deps",
],
srcs: [
@@ -43,27 +44,27 @@
],
init_rc: ["credstore.rc"],
shared_libs: [
- "android.hardware.identity-support-lib",
"android.hardware.keymaster@4.0",
"android.security.authorization-ndk",
"libbase",
"libbinder",
"libbinder_ndk",
- "libcredstore_aidl",
"libcrypto",
"libhidlbase",
+ "liblog",
+ "libutils",
+ "libutilscallstack",
+ ],
+ static_libs: [
+ "android.hardware.keymaster-V3-cpp",
+ "android.hardware.identity-support-lib",
+ "android.hardware.security.rkp-V3-cpp",
+ "android.security.rkp_aidl-cpp",
+ "libcppbor_external",
+ "libcredstore_aidl",
"libkeymaster4support",
"libkeystore-attestation-application-id",
"librkp_support",
- "libutils",
- "libutilscallstack",
- "libvintf",
- ],
- static_libs: [
- "android.hardware.security.rkp-V3-cpp",
- "android.hardware.keymaster-V3-cpp",
- "android.security.rkp_aidl-cpp",
- "libcppbor_external",
],
}
@@ -89,7 +90,7 @@
path: "binder",
}
-cc_library_shared {
+cc_library_static {
name: "libcredstore_aidl",
srcs: [
":credstore_aidl",
@@ -103,6 +104,8 @@
shared_libs: [
"libbinder",
"libutils",
+ ],
+ static_libs: [
"libkeymaster4support",
],
export_shared_lib_headers: [
diff --git a/identity/CredentialStore.cpp b/identity/CredentialStore.cpp
index cb2e8c7..57361c0 100644
--- a/identity/CredentialStore.cpp
+++ b/identity/CredentialStore.cpp
@@ -25,7 +25,6 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <rkp/support/rkpd_client.h>
-#include <vintf/VintfObject.h>
#include "Credential.h"
#include "CredentialData.h"
diff --git a/keystore2/legacykeystore/lib.rs b/keystore2/legacykeystore/lib.rs
index 464f0a2..b826a65 100644
--- a/keystore2/legacykeystore/lib.rs
+++ b/keystore2/legacykeystore/lib.rs
@@ -29,9 +29,7 @@
legacy_blob::LegacyBlobLoader, maintenance::DeleteListener, maintenance::Domain,
utils::uid_to_android_user, utils::watchdog as wd,
};
-use rusqlite::{
- params, Connection, OptionalExtension, Transaction, TransactionBehavior, NO_PARAMS,
-};
+use rusqlite::{params, Connection, OptionalExtension, Transaction, TransactionBehavior};
use std::sync::Arc;
use std::{
collections::HashSet,
@@ -95,7 +93,7 @@
alias BLOB,
profile BLOB,
UNIQUE(owner, alias));",
- NO_PARAMS,
+ [],
)
.context("Failed to initialize \"profiles\" table.")?;
Ok(())
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 10cadfe..d6bfaf2 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -82,7 +82,7 @@
types::FromSqlResult,
types::ToSqlOutput,
types::{FromSqlError, Value, ValueRef},
- Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
+ Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior,
};
use std::{
@@ -905,21 +905,21 @@
alias BLOB,
state INTEGER,
km_uuid BLOB);",
- NO_PARAMS,
+ [],
)
.context("Failed to initialize \"keyentry\" table.")?;
tx.execute(
"CREATE INDEX IF NOT EXISTS persistent.keyentry_id_index
ON keyentry(id);",
- NO_PARAMS,
+ [],
)
.context("Failed to create index keyentry_id_index.")?;
tx.execute(
"CREATE INDEX IF NOT EXISTS persistent.keyentry_domain_namespace_index
ON keyentry(domain, namespace, alias);",
- NO_PARAMS,
+ [],
)
.context("Failed to create index keyentry_domain_namespace_index.")?;
@@ -929,14 +929,14 @@
subcomponent_type INTEGER,
keyentryid INTEGER,
blob BLOB);",
- NO_PARAMS,
+ [],
)
.context("Failed to initialize \"blobentry\" table.")?;
tx.execute(
"CREATE INDEX IF NOT EXISTS persistent.blobentry_keyentryid_index
ON blobentry(keyentryid);",
- NO_PARAMS,
+ [],
)
.context("Failed to create index blobentry_keyentryid_index.")?;
@@ -947,14 +947,14 @@
tag INTEGER,
data ANY,
UNIQUE (blobentryid, tag));",
- NO_PARAMS,
+ [],
)
.context("Failed to initialize \"blobmetadata\" table.")?;
tx.execute(
"CREATE INDEX IF NOT EXISTS persistent.blobmetadata_blobentryid_index
ON blobmetadata(blobentryid);",
- NO_PARAMS,
+ [],
)
.context("Failed to create index blobmetadata_blobentryid_index.")?;
@@ -964,14 +964,14 @@
tag INTEGER,
data ANY,
security_level INTEGER);",
- NO_PARAMS,
+ [],
)
.context("Failed to initialize \"keyparameter\" table.")?;
tx.execute(
"CREATE INDEX IF NOT EXISTS persistent.keyparameter_keyentryid_index
ON keyparameter(keyentryid);",
- NO_PARAMS,
+ [],
)
.context("Failed to create index keyparameter_keyentryid_index.")?;
@@ -981,14 +981,14 @@
tag INTEGER,
data ANY,
UNIQUE (keyentryid, tag));",
- NO_PARAMS,
+ [],
)
.context("Failed to initialize \"keymetadata\" table.")?;
tx.execute(
"CREATE INDEX IF NOT EXISTS persistent.keymetadata_keyentryid_index
ON keymetadata(keyentryid);",
- NO_PARAMS,
+ [],
)
.context("Failed to create index keymetadata_keyentryid_index.")?;
@@ -998,7 +998,7 @@
grantee INTEGER,
keyentryid INTEGER,
access_vector INTEGER);",
- NO_PARAMS,
+ [],
)
.context("Failed to initialize \"grant\" table.")?;
@@ -1611,7 +1611,7 @@
.context(ks_err!("Failed to insert blob."))?;
if let Some(blob_metadata) = blob_metadata {
let blob_id = tx
- .query_row("SELECT MAX(id) FROM persistent.blobentry;", NO_PARAMS, |row| {
+ .query_row("SELECT MAX(id) FROM persistent.blobentry;", [], |row| {
row.get(0)
})
.context(ks_err!("Failed to get new blob id."))?;
@@ -2859,7 +2859,6 @@
use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Timestamp::Timestamp,
};
- use rusqlite::NO_PARAMS;
use rusqlite::TransactionBehavior;
use std::cell::RefCell;
use std::collections::BTreeMap;
@@ -2898,7 +2897,7 @@
#[test]
fn datetime() -> Result<()> {
let conn = Connection::open_in_memory()?;
- conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
+ conn.execute("CREATE TABLE test (ts DATETIME);", [])?;
let now = SystemTime::now();
let duration = Duration::from_secs(1000);
let then = now.checked_sub(duration).unwrap();
@@ -2908,7 +2907,7 @@
params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
)?;
let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
- let mut rows = stmt.query(NO_PARAMS)?;
+ let mut rows = stmt.query([])?;
assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
@@ -3259,15 +3258,9 @@
let mut stmt = db
.conn
.prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
- let mut rows =
- stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>(NO_PARAMS, |row| {
- Ok((
- row.get(0)?,
- row.get(1)?,
- row.get(2)?,
- KeyPermSet::from(row.get::<_, i32>(3)?),
- ))
- })?;
+ let mut rows = stmt.query_map::<(i64, u32, i64, KeyPermSet), _, _>([], |row| {
+ Ok((row.get(0)?, row.get(1)?, row.get(2)?, KeyPermSet::from(row.get::<_, i32>(3)?)))
+ })?;
let r = rows.next().unwrap().unwrap();
assert_eq!(r, (next_random, GRANTEE_UID, 1, PVEC1));
@@ -3311,7 +3304,7 @@
ORDER BY subcomponent_type ASC;",
)?;
let mut rows = stmt
- .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>(NO_PARAMS, |row| {
+ .query_map::<((SubComponentType, i64, Vec<u8>), i64), _, _>([], |row| {
Ok(((row.get(0)?, row.get(1)?, row.get(2)?), row.get(3)?))
})?;
let (r, id) = rows.next().unwrap().unwrap();
@@ -4412,7 +4405,7 @@
fn get_keyentry(db: &KeystoreDB) -> Result<Vec<KeyEntryRow>> {
db.conn
.prepare("SELECT * FROM persistent.keyentry;")?
- .query_map(NO_PARAMS, |row| {
+ .query_map([], |row| {
Ok(KeyEntryRow {
id: row.get(0)?,
key_type: row.get(1)?,
@@ -4784,7 +4777,7 @@
"SELECT id, key_type, domain, namespace, alias, state, km_uuid FROM persistent.keyentry;",
)?;
let rows = stmt.query_map::<(i64, KeyType, i32, i64, String, KeyLifeCycle, Uuid), _, _>(
- NO_PARAMS,
+ [],
|row| {
Ok((
row.get(0)?,
@@ -4813,7 +4806,7 @@
let mut stmt = db
.conn
.prepare("SELECT id, grantee, keyentryid, access_vector FROM persistent.grant;")?;
- let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>(NO_PARAMS, |row| {
+ let rows = stmt.query_map::<(i64, i64, i64, i64), _, _>([], |row| {
Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
})?;
diff --git a/keystore2/src/database/versioning.rs b/keystore2/src/database/versioning.rs
index e3a95c8..2c816f4 100644
--- a/keystore2/src/database/versioning.rs
+++ b/keystore2/src/database/versioning.rs
@@ -13,21 +13,19 @@
// limitations under the License.
use anyhow::{anyhow, Context, Result};
-use rusqlite::{params, OptionalExtension, Transaction, NO_PARAMS};
+use rusqlite::{params, OptionalExtension, Transaction};
pub fn create_or_get_version(tx: &Transaction, current_version: u32) -> Result<u32> {
tx.execute(
"CREATE TABLE IF NOT EXISTS persistent.version (
id INTEGER PRIMARY KEY,
version INTEGER);",
- NO_PARAMS,
+ [],
)
.context("In create_or_get_version: Failed to create version table.")?;
let version = tx
- .query_row("SELECT version FROM persistent.version WHERE id = 0;", NO_PARAMS, |row| {
- row.get(0)
- })
+ .query_row("SELECT version FROM persistent.version WHERE id = 0;", [], |row| row.get(0))
.optional()
.context("In create_or_get_version: Failed to read version.")?;
@@ -44,7 +42,7 @@
.query_row(
"SELECT name FROM persistent.sqlite_master
WHERE type = 'table' AND name = 'keyentry';",
- NO_PARAMS,
+ [],
|_| Ok(()),
)
.optional()
@@ -94,12 +92,12 @@
#[cfg(test)]
mod test {
use super::*;
- use rusqlite::{Connection, TransactionBehavior, NO_PARAMS};
+ use rusqlite::{Connection, TransactionBehavior};
#[test]
fn upgrade_database_test() {
let mut conn = Connection::open_in_memory().unwrap();
- conn.execute("ATTACH DATABASE 'file::memory:' as persistent;", NO_PARAMS).unwrap();
+ conn.execute("ATTACH DATABASE 'file::memory:' as persistent;", []).unwrap();
let upgraders: Vec<_> = (0..30_u32)
.map(move |i| {
@@ -125,19 +123,19 @@
alias BLOB,
state INTEGER,
km_uuid BLOB);",
- NO_PARAMS,
+ [],
)
.unwrap();
}
for from in 1..29 {
for to in from..30 {
- conn.execute("DROP TABLE IF EXISTS persistent.version;", NO_PARAMS).unwrap();
- conn.execute("DROP TABLE IF EXISTS persistent.test;", NO_PARAMS).unwrap();
+ conn.execute("DROP TABLE IF EXISTS persistent.version;", []).unwrap();
+ conn.execute("DROP TABLE IF EXISTS persistent.test;", []).unwrap();
conn.execute(
"CREATE TABLE IF NOT EXISTS persistent.test (
id INTEGER PRIMARY KEY,
test_field INTEGER);",
- NO_PARAMS,
+ [],
)
.unwrap();
@@ -163,7 +161,7 @@
to - from,
conn.query_row(
"SELECT COUNT(test_field) FROM persistent.test;",
- NO_PARAMS,
+ [],
|row| row.get(0)
)
.unwrap()
@@ -188,7 +186,7 @@
#[test]
fn create_or_get_version_new_database() {
let mut conn = Connection::open_in_memory().unwrap();
- conn.execute("ATTACH DATABASE 'file::memory:' as persistent;", NO_PARAMS).unwrap();
+ conn.execute("ATTACH DATABASE 'file::memory:' as persistent;", []).unwrap();
{
let tx = conn.transaction_with_behavior(TransactionBehavior::Immediate).unwrap();
let version = create_or_get_version(&tx, 3).unwrap();
@@ -202,7 +200,7 @@
conn.query_row(
"SELECT name FROM persistent.sqlite_master
WHERE type = 'table' AND name = 'version';",
- NO_PARAMS,
+ [],
|row| row.get(0),
)
);
@@ -210,18 +208,14 @@
// There is exactly one row in the version table.
assert_eq!(
Ok(1),
- conn.query_row("SELECT COUNT(id) from persistent.version;", NO_PARAMS, |row| row
- .get(0))
+ conn.query_row("SELECT COUNT(id) from persistent.version;", [], |row| row.get(0))
);
// The version must be set to 3
assert_eq!(
Ok(3),
- conn.query_row(
- "SELECT version from persistent.version WHERE id = 0;",
- NO_PARAMS,
- |row| row.get(0)
- )
+ conn.query_row("SELECT version from persistent.version WHERE id = 0;", [], |row| row
+ .get(0))
);
// Will subsequent calls to create_or_get_version still return the same version even
@@ -236,8 +230,7 @@
// There is still exactly one row in the version table.
assert_eq!(
Ok(1),
- conn.query_row("SELECT COUNT(id) from persistent.version;", NO_PARAMS, |row| row
- .get(0))
+ conn.query_row("SELECT COUNT(id) from persistent.version;", [], |row| row.get(0))
);
// Bump the version.
@@ -258,25 +251,21 @@
// There is still exactly one row in the version table.
assert_eq!(
Ok(1),
- conn.query_row("SELECT COUNT(id) from persistent.version;", NO_PARAMS, |row| row
- .get(0))
+ conn.query_row("SELECT COUNT(id) from persistent.version;", [], |row| row.get(0))
);
// The version must be set to 5
assert_eq!(
Ok(5),
- conn.query_row(
- "SELECT version from persistent.version WHERE id = 0;",
- NO_PARAMS,
- |row| row.get(0)
- )
+ conn.query_row("SELECT version from persistent.version WHERE id = 0;", [], |row| row
+ .get(0))
);
}
#[test]
fn create_or_get_version_legacy_database() {
let mut conn = Connection::open_in_memory().unwrap();
- conn.execute("ATTACH DATABASE 'file::memory:' as persistent;", NO_PARAMS).unwrap();
+ conn.execute("ATTACH DATABASE 'file::memory:' as persistent;", []).unwrap();
// A legacy (version 0) database is detected if the keyentry table exists but no
// version table.
conn.execute(
@@ -288,7 +277,7 @@
alias BLOB,
state INTEGER,
km_uuid BLOB);",
- NO_PARAMS,
+ [],
)
.unwrap();
@@ -306,7 +295,7 @@
conn.query_row(
"SELECT name FROM persistent.sqlite_master
WHERE type = 'table' AND name = 'version';",
- NO_PARAMS,
+ [],
|row| row.get(0),
)
);
@@ -314,18 +303,14 @@
// There is exactly one row in the version table.
assert_eq!(
Ok(1),
- conn.query_row("SELECT COUNT(id) from persistent.version;", NO_PARAMS, |row| row
- .get(0))
+ conn.query_row("SELECT COUNT(id) from persistent.version;", [], |row| row.get(0))
);
// The version must be set to 0
assert_eq!(
Ok(0),
- conn.query_row(
- "SELECT version from persistent.version WHERE id = 0;",
- NO_PARAMS,
- |row| row.get(0)
- )
+ conn.query_row("SELECT version from persistent.version WHERE id = 0;", [], |row| row
+ .get(0))
);
// Will subsequent calls to create_or_get_version still return the same version even
@@ -340,8 +325,7 @@
// There is still exactly one row in the version table.
assert_eq!(
Ok(1),
- conn.query_row("SELECT COUNT(id) from persistent.version;", NO_PARAMS, |row| row
- .get(0))
+ conn.query_row("SELECT COUNT(id) from persistent.version;", [], |row| row.get(0))
);
// Bump the version.
@@ -362,18 +346,14 @@
// There is still exactly one row in the version table.
assert_eq!(
Ok(1),
- conn.query_row("SELECT COUNT(id) from persistent.version;", NO_PARAMS, |row| row
- .get(0))
+ conn.query_row("SELECT COUNT(id) from persistent.version;", [], |row| row.get(0))
);
// The version must be set to 5
assert_eq!(
Ok(5),
- conn.query_row(
- "SELECT version from persistent.version WHERE id = 0;",
- NO_PARAMS,
- |row| row.get(0)
- )
+ conn.query_row("SELECT version from persistent.version WHERE id = 0;", [], |row| row
+ .get(0))
);
}
}
diff --git a/keystore2/src/key_parameter.rs b/keystore2/src/key_parameter.rs
index 5da95d9..02a1f16 100644
--- a/keystore2/src/key_parameter.rs
+++ b/keystore2/src/key_parameter.rs
@@ -1216,7 +1216,7 @@
use crate::key_parameter::*;
use anyhow::Result;
use rusqlite::types::ToSql;
- use rusqlite::{params, Connection, NO_PARAMS};
+ use rusqlite::{params, Connection};
/// Test initializing a KeyParameter (with key parameter value corresponding to an enum of i32)
/// from a database table row.
@@ -1423,7 +1423,7 @@
tag INTEGER,
data ANY,
security_level INTEGER);",
- NO_PARAMS,
+ [],
)
.context("Failed to initialize \"keyparameter\" table.")?;
Ok(db)
@@ -1459,7 +1459,7 @@
fn query_from_keyparameter(db: &Connection) -> Result<KeyParameter> {
let mut stmt =
db.prepare("SELECT tag, data, security_level FROM persistent.keyparameter")?;
- let mut rows = stmt.query(NO_PARAMS)?;
+ let mut rows = stmt.query([])?;
let row = rows.next()?.unwrap();
KeyParameter::new_from_sql(
Tag(row.get(0)?),
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index e4c4968..02384d9 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -16,6 +16,10 @@
use anyhow::Result;
+use core::ops::Range;
+use std::collections::HashSet;
+use std::fmt::Write;
+
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
ErrorCode::ErrorCode, HardwareAuthenticatorType::HardwareAuthenticatorType,
@@ -1082,3 +1086,23 @@
Err(e) => Err(e),
}
}
+
+/// Helper method to import AES keys `total_count` of times.
+pub fn import_aes_keys(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ alias_prefix: String,
+ total_count: Range<i32>,
+) -> binder::Result<HashSet<String>> {
+ let mut imported_key_aliases = HashSet::new();
+
+ // Import Total number of keys with given alias prefix.
+ for count in total_count {
+ let mut alias = String::new();
+ write!(alias, "{}_{}", alias_prefix, count).unwrap();
+ imported_key_aliases.insert(alias.clone());
+
+ import_aes_key(sec_level, Domain::APP, -1, Some(alias))?;
+ }
+
+ Ok(imported_key_aliases)
+}
diff --git a/keystore2/tests/keystore2_client_list_entries_tests.rs b/keystore2/tests/keystore2_client_list_entries_tests.rs
index 3b656c3..809c01f 100644
--- a/keystore2/tests/keystore2_client_list_entries_tests.rs
+++ b/keystore2/tests/keystore2_client_list_entries_tests.rs
@@ -23,7 +23,7 @@
KeyPermission::KeyPermission, ResponseCode::ResponseCode,
};
-use crate::keystore2_client_test_utils::delete_app_key;
+use crate::keystore2_client_test_utils::{delete_all_entries, delete_app_key, verify_aliases};
use keystore2_test_utils::{get_keystore_service, key_generations, key_generations::Error, run_as};
/// Try to find a key with given key parameters using `listEntries` API.
@@ -251,3 +251,464 @@
})
};
}
+
+/// Import large number of Keystore entries with long aliases such that the
+/// aliases list would exceed the binder transaction size limit.
+/// Try to list aliases of all the entries in the keystore using `listEntriesBatched` API.
+#[test]
+fn keystore2_list_entries_batched_with_long_aliases_success() {
+ static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+ const USER_ID: u32 = 92;
+ const APPLICATION_ID: u32 = 10002;
+ static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ static CLIENT_GID: u32 = CLIENT_UID;
+
+ unsafe {
+ run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ // Make sure there are no keystore entries exist before adding new entries.
+ delete_all_entries(&keystore2);
+
+ // Import 100 keys with aliases of length 6000.
+ let mut imported_key_aliases =
+ key_generations::import_aes_keys(&sec_level, "X".repeat(6000), 1..101).unwrap();
+ assert_eq!(
+ keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 100,
+ "Error while importing keys"
+ );
+
+ let mut start_past_alias = None;
+ let mut alias;
+ while !imported_key_aliases.is_empty() {
+ let key_descriptors =
+ keystore2.listEntriesBatched(Domain::APP, -1, start_past_alias).unwrap();
+
+ // Check retrieved key entries list is a subset of imported keys list.
+ assert!(key_descriptors
+ .iter()
+ .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+
+ alias = key_descriptors.last().unwrap().alias.clone().unwrap();
+ start_past_alias = Some(alias.as_ref());
+ // Delete the listed key entries from imported keys list.
+ key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
+ assert!(imported_key_aliases.remove(&alias));
+ });
+ }
+
+ assert!(imported_key_aliases.is_empty());
+ delete_all_entries(&keystore2);
+ assert_eq!(
+ keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 0,
+ "Error while doing cleanup"
+ );
+ })
+ };
+}
+
+/// Import keys from multiple processes with same user context and try to list the keystore entries
+/// using `listEntriesBatched` API.
+/// - Create two processes sharing user-id.
+/// - From process-1, import 3 keys and try to list the keys using `listEntriesBatched`
+/// without `startingPastAlias`, it should list all the 3 entries.
+/// - From process-2, import another 5 keys and try to list the keys using `listEntriesBatched`
+/// with the alias of the last key listed in process-1 as `startingPastAlias`. It should list
+/// all the entries whose alias is greater than the provided `startingPastAlias`.
+/// - From process-2 try to list all entries accessible to it by using `listEntriesBatched` with
+/// `startingPastAlias` as None. It should list all the keys imported in process-1 and process-2.
+#[test]
+fn keystore2_list_entries_batched_with_multi_procs_success() {
+ static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+ const USER_ID: u32 = 92;
+ const APPLICATION_ID: u32 = 10002;
+ static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ static CLIENT_GID: u32 = CLIENT_UID;
+ static ALIAS_PREFIX: &str = "key_test_batch_list";
+
+ unsafe {
+ run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ // Make sure there are no keystore entries exist before adding new entries.
+ delete_all_entries(&keystore2);
+
+ // Import 3 keys with below aliases -
+ // [key_test_batch_list_1, key_test_batch_list_2, key_test_batch_list_3]
+ let imported_key_aliases =
+ key_generations::import_aes_keys(&sec_level, ALIAS_PREFIX.to_string(), 1..4)
+ .unwrap();
+ assert_eq!(
+ keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 3,
+ "Error while importing keys"
+ );
+
+ // List all entries in keystore for this user-id.
+ let key_descriptors = keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
+ assert_eq!(key_descriptors.len(), 3);
+
+ // Makes sure all listed aliases are matching with imported keys aliases.
+ assert!(key_descriptors
+ .iter()
+ .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+ })
+ };
+
+ unsafe {
+ run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ // Import another 5 keys with below aliases -
+ // [ key_test_batch_list_4, key_test_batch_list_5, key_test_batch_list_6,
+ // key_test_batch_list_7, key_test_batch_list_8 ]
+ let mut imported_key_aliases =
+ key_generations::import_aes_keys(&sec_level, ALIAS_PREFIX.to_string(), 4..9)
+ .unwrap();
+
+ // Above context already 3 keys are imported, in this context 5 keys are imported,
+ // total 8 keystore entries are expected to be present in Keystore for this user-id.
+ assert_eq!(
+ keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 8,
+ "Error while importing keys"
+ );
+
+ // List keystore entries with `start_past_alias` as "key_test_batch_list_3".
+ // `listEntriesBatched` should list all the keystore entries with
+ // alias > "key_test_batch_list_3".
+ let key_descriptors = keystore2
+ .listEntriesBatched(Domain::APP, -1, Some("key_test_batch_list_3"))
+ .unwrap();
+ assert_eq!(key_descriptors.len(), 5);
+
+ // Make sure above listed aliases are matching with imported keys aliases.
+ assert!(key_descriptors
+ .iter()
+ .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+
+ // List all keystore entries with `start_past_alias` as `None`.
+ // `listEntriesBatched` should list all the keystore entries.
+ let key_descriptors = keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
+ assert_eq!(key_descriptors.len(), 8);
+
+ // Include previously imported keys aliases as well
+ imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_1");
+ imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_2");
+ imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_3");
+
+ // Make sure all the above listed aliases are matching with imported keys aliases.
+ assert!(key_descriptors
+ .iter()
+ .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+
+ delete_all_entries(&keystore2);
+ assert_eq!(
+ keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 0,
+ "Error while doing cleanup"
+ );
+ })
+ };
+}
+
+#[test]
+fn keystore2_list_entries_batched_with_empty_keystore_success() {
+ static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+ const USER_ID: u32 = 92;
+ const APPLICATION_ID: u32 = 10002;
+ static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ static CLIENT_GID: u32 = CLIENT_UID;
+
+ unsafe {
+ run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
+ let keystore2 = get_keystore_service();
+
+ // Make sure there are no keystore entries exist before adding new entries.
+ delete_all_entries(&keystore2);
+
+ // List all entries in keystore for this user-id, pass startingPastAlias = None
+ let key_descriptors = keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
+ assert_eq!(key_descriptors.len(), 0);
+
+ // List all entries in keystore for this user-id, pass startingPastAlias = <random value>
+ let key_descriptors =
+ keystore2.listEntriesBatched(Domain::APP, -1, Some("startingPastAlias")).unwrap();
+ assert_eq!(key_descriptors.len(), 0);
+ })
+ };
+}
+
+/// Import a key with SELINUX as domain, list aliases using `listEntriesBatched`.
+/// Test should successfully list the imported key.
+#[test]
+fn keystore2_list_entries_batched_with_selinux_domain_success() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = "test_selinux_key_list_alias_batched";
+ let _result = keystore2.deleteKey(&KeyDescriptor {
+ domain: Domain::SELINUX,
+ nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+ alias: Some(alias.to_string()),
+ blob: None,
+ });
+
+ let initial_count = keystore2
+ .getNumberOfEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE)
+ .unwrap();
+
+ key_generations::import_aes_key(
+ &sec_level,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias.to_string()),
+ )
+ .unwrap();
+
+ assert_eq!(
+ keystore2
+ .getNumberOfEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE)
+ .unwrap(),
+ initial_count + 1,
+ "Error while getting number of keystore entries accessible."
+ );
+
+ let key_descriptors = keystore2
+ .listEntriesBatched(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE, None)
+ .unwrap();
+ assert_eq!(key_descriptors.len(), (initial_count + 1) as usize);
+
+ let count =
+ key_descriptors.into_iter().map(|key| key.alias.unwrap()).filter(|a| a == alias).count();
+ assert_eq!(count, 1);
+
+ keystore2
+ .deleteKey(&KeyDescriptor {
+ domain: Domain::SELINUX,
+ nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+ alias: Some(alias.to_string()),
+ blob: None,
+ })
+ .unwrap();
+}
+
+#[test]
+fn keystore2_list_entries_batched_validate_count_and_order_success() {
+ static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+ const USER_ID: u32 = 92;
+ const APPLICATION_ID: u32 = 10002;
+ static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ static CLIENT_GID: u32 = CLIENT_UID;
+ static ALIAS_PREFIX: &str = "key_test_batch_list";
+
+ unsafe {
+ run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ // Make sure there are no keystore entries exist before adding new entries.
+ delete_all_entries(&keystore2);
+
+ // Import keys with below mentioned aliases -
+ // [
+ // key_test_batch_list_1,
+ // key_test_batch_list_2,
+ // key_test_batch_list_3,
+ // key_test_batch_list_4,
+ // key_test_batch_list_5,
+ // key_test_batch_list_10,
+ // key_test_batch_list_11,
+ // key_test_batch_list_12,
+ // key_test_batch_list_21,
+ // key_test_batch_list_22,
+ // ]
+ let _imported_key_aliases =
+ key_generations::import_aes_keys(&sec_level, ALIAS_PREFIX.to_string(), 1..6)
+ .unwrap();
+ assert_eq!(
+ keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 5,
+ "Error while importing keys"
+ );
+ let _imported_key_aliases =
+ key_generations::import_aes_keys(&sec_level, ALIAS_PREFIX.to_string(), 10..13)
+ .unwrap();
+ assert_eq!(
+ keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 8,
+ "Error while importing keys"
+ );
+ let _imported_key_aliases =
+ key_generations::import_aes_keys(&sec_level, ALIAS_PREFIX.to_string(), 21..23)
+ .unwrap();
+ assert_eq!(
+ keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 10,
+ "Error while importing keys"
+ );
+
+ // List the aliases using given `startingPastAlias` and verify the listed
+ // aliases with the expected list of aliases.
+ verify_aliases(&keystore2, Some(format!("{}{}", ALIAS_PREFIX, "_5").as_str()), vec![]);
+
+ verify_aliases(
+ &keystore2,
+ Some(format!("{}{}", ALIAS_PREFIX, "_4").as_str()),
+ vec![ALIAS_PREFIX.to_owned() + "_5"],
+ );
+
+ verify_aliases(
+ &keystore2,
+ Some(format!("{}{}", ALIAS_PREFIX, "_3").as_str()),
+ vec![ALIAS_PREFIX.to_owned() + "_4", ALIAS_PREFIX.to_owned() + "_5"],
+ );
+
+ verify_aliases(
+ &keystore2,
+ Some(format!("{}{}", ALIAS_PREFIX, "_2").as_str()),
+ vec![
+ ALIAS_PREFIX.to_owned() + "_21",
+ ALIAS_PREFIX.to_owned() + "_22",
+ ALIAS_PREFIX.to_owned() + "_3",
+ ALIAS_PREFIX.to_owned() + "_4",
+ ALIAS_PREFIX.to_owned() + "_5",
+ ],
+ );
+
+ verify_aliases(
+ &keystore2,
+ Some(format!("{}{}", ALIAS_PREFIX, "_1").as_str()),
+ vec![
+ ALIAS_PREFIX.to_owned() + "_10",
+ ALIAS_PREFIX.to_owned() + "_11",
+ ALIAS_PREFIX.to_owned() + "_12",
+ ALIAS_PREFIX.to_owned() + "_2",
+ ALIAS_PREFIX.to_owned() + "_21",
+ ALIAS_PREFIX.to_owned() + "_22",
+ ALIAS_PREFIX.to_owned() + "_3",
+ ALIAS_PREFIX.to_owned() + "_4",
+ ALIAS_PREFIX.to_owned() + "_5",
+ ],
+ );
+
+ verify_aliases(
+ &keystore2,
+ Some(ALIAS_PREFIX),
+ vec![
+ ALIAS_PREFIX.to_owned() + "_1",
+ ALIAS_PREFIX.to_owned() + "_10",
+ ALIAS_PREFIX.to_owned() + "_11",
+ ALIAS_PREFIX.to_owned() + "_12",
+ ALIAS_PREFIX.to_owned() + "_2",
+ ALIAS_PREFIX.to_owned() + "_21",
+ ALIAS_PREFIX.to_owned() + "_22",
+ ALIAS_PREFIX.to_owned() + "_3",
+ ALIAS_PREFIX.to_owned() + "_4",
+ ALIAS_PREFIX.to_owned() + "_5",
+ ],
+ );
+
+ verify_aliases(
+ &keystore2,
+ None,
+ vec![
+ ALIAS_PREFIX.to_owned() + "_1",
+ ALIAS_PREFIX.to_owned() + "_10",
+ ALIAS_PREFIX.to_owned() + "_11",
+ ALIAS_PREFIX.to_owned() + "_12",
+ ALIAS_PREFIX.to_owned() + "_2",
+ ALIAS_PREFIX.to_owned() + "_21",
+ ALIAS_PREFIX.to_owned() + "_22",
+ ALIAS_PREFIX.to_owned() + "_3",
+ ALIAS_PREFIX.to_owned() + "_4",
+ ALIAS_PREFIX.to_owned() + "_5",
+ ],
+ );
+ })
+ };
+}
+
+/// Try to list the key entries with domain SELINUX from user context where user doesn't possesses
+/// `GET_INFO` permission for specified namespace. Test should fail to list key entries with error
+/// response code `PERMISSION_DENIED`.
+#[test]
+fn keystore2_list_entries_batched_fails_perm_denied() {
+ let auid = 91 * AID_USER_OFFSET + 10001;
+ let agid = 91 * AID_USER_OFFSET + 10001;
+ static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+ unsafe {
+ run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
+ let keystore2 = get_keystore_service();
+
+ let result = key_generations::map_ks_error(keystore2.listEntriesBatched(
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ None,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ })
+ };
+}
+
+/// Try to list key entries with domain BLOB. Test should fail with error response code
+/// `INVALID_ARGUMENT`.
+#[test]
+fn keystore2_list_entries_batched_fails_invalid_arg() {
+ let keystore2 = get_keystore_service();
+
+ let result = key_generations::map_ks_error(keystore2.listEntriesBatched(
+ Domain::BLOB,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ None,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
+}
+
+/// Try to get the number of key entries with domain SELINUX from user context where user doesn't
+/// possesses `GET_INFO` permission for specified namespace. Test should fail to list key entries
+/// with error response code `PERMISSION_DENIED`.
+#[test]
+fn keystore2_get_number_of_entries_fails_perm_denied() {
+ let auid = 91 * AID_USER_OFFSET + 10001;
+ let agid = 91 * AID_USER_OFFSET + 10001;
+ static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+ unsafe {
+ run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
+ let keystore2 = get_keystore_service();
+
+ let result = key_generations::map_ks_error(
+ keystore2
+ .getNumberOfEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
+ );
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ })
+ };
+}
+
+/// Try to get number of key entries with domain BLOB. Test should fail with error response code
+/// `INVALID_ARGUMENT`.
+#[test]
+fn keystore2_get_number_of_entries_fails_invalid_arg() {
+ let keystore2 = get_keystore_service();
+
+ let result = key_generations::map_ks_error(
+ keystore2.getNumberOfEntries(Domain::BLOB, key_generations::SELINUX_SHELL_NAMESPACE),
+ );
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
+}
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index 58e6b7d..07c2183 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -376,6 +376,17 @@
})
}
+/// Deletes all entries from keystore.
+pub fn delete_all_entries(keystore2: &binder::Strong<dyn IKeystoreService>) {
+ while keystore2.getNumberOfEntries(Domain::APP, -1).unwrap() != 0 {
+ let key_descriptors = keystore2.listEntries(Domain::APP, -1).unwrap();
+ key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
+ delete_app_key(keystore2, &alias).unwrap();
+ });
+ }
+ assert!(keystore2.getNumberOfEntries(Domain::APP, -1).unwrap() == 0);
+}
+
/// Encrypt the secure key with given transport key.
pub fn encrypt_secure_key(
sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
@@ -417,3 +428,19 @@
Ok(encoded.to_vec())
}
+
+/// List aliases using given `startingPastAlias` and verify that the fetched list is matching with
+/// the expected list of aliases.
+pub fn verify_aliases(
+ keystore2: &binder::Strong<dyn IKeystoreService>,
+ starting_past_alias: Option<&str>,
+ expected_aliases: Vec<String>,
+) {
+ let key_descriptors =
+ keystore2.listEntriesBatched(Domain::APP, -1, starting_past_alias).unwrap();
+
+ assert_eq!(key_descriptors.len(), expected_aliases.len());
+ assert!(key_descriptors
+ .iter()
+ .all(|key| expected_aliases.contains(key.alias.as_ref().unwrap())));
+}
diff --git a/provisioner/rkp_factory_extraction_lib.cpp b/provisioner/rkp_factory_extraction_lib.cpp
index 8db62e6..ab7d17c 100644
--- a/provisioner/rkp_factory_extraction_lib.cpp
+++ b/provisioner/rkp_factory_extraction_lib.cpp
@@ -195,7 +195,11 @@
protectedData, *eekChain, eekId,
hwInfo.supportedEekCurve, irpc, challenge);
- std::cout << "Self test successful." << std::endl;
+ if (!result) {
+ std::cerr << "Self test failed for IRemotelyProvisionedComponent '" << componentName
+ << "'. Error message: '" << result.message() << "'." << std::endl;
+ exit(-1);
+ }
}
CborResult<Array> composeCertificateRequestV3(const std::vector<uint8_t>& csr) {
@@ -220,7 +224,7 @@
}
CborResult<cppbor::Array> getCsrV3(std::string_view componentName,
- IRemotelyProvisionedComponent* irpc) {
+ IRemotelyProvisionedComponent* irpc, bool selfTest) {
std::vector<uint8_t> csr;
std::vector<MacedPublicKey> emptyKeys;
const std::vector<uint8_t> challenge = generateChallenge();
@@ -232,32 +236,20 @@
exit(-1);
}
+ if (selfTest) {
+ auto result = verifyFactoryCsr(/*keysToSign=*/cppbor::Array(), csr, irpc, challenge);
+ if (!result) {
+ std::cerr << "Self test failed for IRemotelyProvisionedComponent '" << componentName
+ << "'. Error message: '" << result.message() << "'." << std::endl;
+ exit(-1);
+ }
+ }
+
return composeCertificateRequestV3(csr);
}
-void selfTestGetCsrV3(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
- std::vector<uint8_t> csr;
- std::vector<MacedPublicKey> emptyKeys;
- const std::vector<uint8_t> challenge = generateChallenge();
-
- auto status = irpc->generateCertificateRequestV2(emptyKeys, challenge, &csr);
- if (!status.isOk()) {
- std::cerr << "Bundle extraction failed for '" << componentName
- << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
- exit(-1);
- }
-
- auto result = verifyFactoryCsr(/*keysToSign=*/cppbor::Array(), csr, irpc, challenge);
- if (!result) {
- std::cerr << "Self test failed for '" << componentName
- << "'. Error message: " << result.message() << "." << std::endl;
- exit(-1);
- }
-
- std::cout << "Self test successful." << std::endl;
-}
-
-CborResult<Array> getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
+CborResult<Array> getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc,
+ bool selfTest) {
RpcHardwareInfo hwInfo;
auto status = irpc->getHardwareInfo(&hwInfo);
if (!status.isOk()) {
@@ -267,24 +259,11 @@
}
if (hwInfo.versionNumber < kVersionWithoutSuperencryption) {
+ if (selfTest) {
+ selfTestGetCsrV1(componentName, irpc);
+ }
return getCsrV1(componentName, irpc);
} else {
- return getCsrV3(componentName, irpc);
- }
-}
-
-void selfTestGetCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
- RpcHardwareInfo hwInfo;
- auto status = irpc->getHardwareInfo(&hwInfo);
- if (!status.isOk()) {
- std::cerr << "Failed to get hardware info for '" << componentName
- << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
- exit(-1);
- }
-
- if (hwInfo.versionNumber < kVersionWithoutSuperencryption) {
- selfTestGetCsrV1(componentName, irpc);
- } else {
- selfTestGetCsrV3(componentName, irpc);
+ return getCsrV3(componentName, irpc, selfTest);
}
}
diff --git a/provisioner/rkp_factory_extraction_lib.h b/provisioner/rkp_factory_extraction_lib.h
index a218338..ae8ea6b 100644
--- a/provisioner/rkp_factory_extraction_lib.h
+++ b/provisioner/rkp_factory_extraction_lib.h
@@ -46,7 +46,8 @@
// what went wrong.
CborResult<cppbor::Array>
getCsr(std::string_view componentName,
- aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc);
+ aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc,
+ bool selfTest);
// Generates a test certificate chain and validates it, exiting the process on error.
void selfTestGetCsr(
diff --git a/provisioner/rkp_factory_extraction_lib_test.cpp b/provisioner/rkp_factory_extraction_lib_test.cpp
index 72d7b71..3fe88da 100644
--- a/provisioner/rkp_factory_extraction_lib_test.cpp
+++ b/provisioner/rkp_factory_extraction_lib_test.cpp
@@ -180,7 +180,8 @@
SetArgPointee<6>(kFakeMac), //
Return(ByMove(ScopedAStatus::ok())))); //
- auto [csr, csrErrMsg] = getCsr("mock component name", mockRpc.get());
+ auto [csr, csrErrMsg] = getCsr("mock component name", mockRpc.get(),
+ /*selfTest=*/false);
ASSERT_THAT(csr, NotNull()) << csrErrMsg;
ASSERT_THAT(csr->asArray(), Pointee(Property(&Array::size, Eq(4))));
@@ -249,7 +250,8 @@
.WillOnce(DoAll(SaveArg<1>(&challenge), SetArgPointee<2>(kCsr),
Return(ByMove(ScopedAStatus::ok()))));
- auto [csr, csrErrMsg] = getCsr("mock component name", mockRpc.get());
+ auto [csr, csrErrMsg] = getCsr("mock component name", mockRpc.get(),
+ /*selfTest=*/false);
ASSERT_THAT(csr, NotNull()) << csrErrMsg;
ASSERT_THAT(csr, Pointee(Property(&Array::size, Eq(5))));
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index 2aeabe0..5ba777e 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -35,10 +35,10 @@
using namespace cppcose;
DEFINE_string(output_format, "build+csr", "How to format the output. Defaults to 'build+csr'.");
-DEFINE_bool(self_test, false,
- "If true, the tool does not output CSR data, but instead performs a self-test, "
- "validating a test payload for correctness. This may be used to verify a device on the "
- "factory line before attempting to upload the output to the device info service.");
+DEFINE_bool(self_test, true,
+ "If true, this tool performs a self-test, validating the payload for correctness. "
+ "This checks that the device on the factory line is producing valid output "
+ "before attempting to upload the output to the device info service.");
namespace {
@@ -81,17 +81,13 @@
exit(-1);
}
- if (FLAGS_self_test) {
- selfTestGetCsr(name, rkp_service.get());
- } else {
- auto [request, errMsg] = getCsr(name, rkp_service.get());
- if (!request) {
- std::cerr << "Unable to build CSR for '" << fullName << ": " << errMsg << std::endl;
- exit(-1);
- }
-
- writeOutput(std::string(name), *request);
+ auto [request, errMsg] = getCsr(name, rkp_service.get(), FLAGS_self_test);
+ if (!request) {
+ std::cerr << "Unable to build CSR for '" << fullName << ": " << errMsg << std::endl;
+ exit(-1);
}
+
+ writeOutput(std::string(name), *request);
}
} // namespace
diff --git a/provisioner/support/Android.bp b/provisioner/support/Android.bp
index 778b1e0..52b204f 100644
--- a/provisioner/support/Android.bp
+++ b/provisioner/support/Android.bp
@@ -31,7 +31,6 @@
"libbase",
"libbinder",
"libutils",
- "libvintf",
],
cflags: [
"-Wall",
diff --git a/provisioner/support/rkpd_client.cpp b/provisioner/support/rkpd_client.cpp
index 0643457..de1e3bb 100644
--- a/provisioner/support/rkpd_client.cpp
+++ b/provisioner/support/rkpd_client.cpp
@@ -26,7 +26,6 @@
#include <binder/IServiceManager.h>
#include <binder/Status.h>
#include <rkp/support/rkpd_client.h>
-#include <vintf/VintfObject.h>
namespace android::security::rkp::support {
namespace {
@@ -61,12 +60,10 @@
}
std::optional<String16> findRpcNameById(std::string_view targetRpcId) {
- auto deviceManifest = vintf::VintfObject::GetDeviceHalManifest();
- auto instances = deviceManifest->getAidlInstances("android.hardware.security.keymint",
- "IRemotelyProvisionedComponent");
- for (const std::string& instance : instances) {
- auto rpcName =
- IRemotelyProvisionedComponent::descriptor + String16("/") + String16(instance.c_str());
+ auto instances = android::defaultServiceManager()->getDeclaredInstances(
+ IRemotelyProvisionedComponent::descriptor);
+ for (const auto& instance : instances) {
+ auto rpcName = IRemotelyProvisionedComponent::descriptor + String16("/") + instance;
sp<IRemotelyProvisionedComponent> rpc =
android::waitForService<IRemotelyProvisionedComponent>(rpcName);