Adding generate key tests using RSA algorithm.
- Generate RSA signing keys with combinations of digest modes [NONE,
MD5, SHA1, SHA_2_224, SHA_2_256, SHA_2_384, SHA_2_512] and padding
modes [NONE, RSA_PKCS1_1_5_SIGN, RSA_PSS]. Should be able to
create operations using these keys except in below cases.
- when padding mode is RSA_PSS and digest mode is NONE
- when padding mode is NONE and digest is other than NONE.
- Generate RSA encrypt/decrypt keys with OAEP padding mode, combinations
of digests [MD5, SHA1, SHA_2_224, SHA_2_256, SHA_2_384, SHA_2_512] and
mgf-digests [MD5, SHA1, SHA_2_224, SHA_2_256, SHA_2_384, SHA_2_512].
Should be able to create operations with these generated keys
successfully.
- Generate RSA encrypt/decrypt keys with combinations of padding modes
[NONE, RSA_PKCS1_1_5_ENCRYPT, RSA_OAEP], digests [NONE, MD5, SHA1,
SHA_2_224, SHA_2_256, SHA_2_384, SHA_2_512]. Should be able to create
operations with these generated keys successfully except in below case
- with padding mode RSA_OAEP and digest mode NONE an error is
expected.
- Generate RSA encrypt/decrypt keys with padding modes [NONE,
RSA_PKCS1_1_5_ENCRYPT, RSA_OAEP] and without digests. Should be able
to create operations with these generated keys successfully.
- Generate RSA keys without padding modes and digest modes. Creation of
an operation should fail with unsupported padding mode error.
- Tests to validate failure of generating RSA keys with incompatible
purpose, unsupported purpose, unsupported padding mode, unsupported
digest and unsupported key sizes.
Bug: 194359114
Test: atest keystore2_client_test
Change-Id: I16843932cc170d0e820208f558587aacf13b9272
diff --git a/keystore2/test_utils/authorizations.rs b/keystore2/test_utils/authorizations.rs
index d5a7b7b..5876c09 100644
--- a/keystore2/test_utils/authorizations.rs
+++ b/keystore2/test_utils/authorizations.rs
@@ -17,8 +17,9 @@
use std::ops::Deref;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, KeyParameter::KeyParameter,
- KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, Tag::Tag,
+ Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
+ KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose,
+ PaddingMode::PaddingMode, Tag::Tag,
};
/// Helper struct to create set of Authorizations.
@@ -87,6 +88,60 @@
});
self
}
+
+ /// Add RSA_public_exponent.
+ pub fn rsa_public_exponent(mut self, e: i64) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::RSA_PUBLIC_EXPONENT,
+ value: KeyParameterValue::LongInteger(e),
+ });
+ self
+ }
+
+ /// Add key size.
+ pub fn key_size(mut self, s: i32) -> Self {
+ self.0.push(KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(s) });
+ self
+ }
+
+ /// Add block mode.
+ pub fn block_mode(mut self, b: BlockMode) -> Self {
+ self.0.push(KeyParameter { tag: Tag::BLOCK_MODE, value: KeyParameterValue::BlockMode(b) });
+ self
+ }
+
+ /// Add certificate_not_before.
+ pub fn cert_not_before(mut self, b: i64) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::CERTIFICATE_NOT_BEFORE,
+ value: KeyParameterValue::DateTime(b),
+ });
+ self
+ }
+
+ /// Add certificate_not_after.
+ pub fn cert_not_after(mut self, a: i64) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::CERTIFICATE_NOT_AFTER,
+ value: KeyParameterValue::DateTime(a),
+ });
+ self
+ }
+
+ /// Add padding mode.
+ pub fn padding_mode(mut self, p: PaddingMode) -> Self {
+ self.0.push(KeyParameter { tag: Tag::PADDING, value: KeyParameterValue::PaddingMode(p) });
+ self
+ }
+
+ /// Add mgf_digest.
+ pub fn mgf_digest(mut self, d: Digest) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::RSA_OAEP_MGF_DIGEST,
+ value: KeyParameterValue::Digest(d),
+ });
+ self
+ }
}
impl Deref for AuthSetBuilder {
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index b1405c7..36986ec 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -17,8 +17,8 @@
use anyhow::Result;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, ErrorCode::ErrorCode,
- KeyPurpose::KeyPurpose,
+ Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
+ ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
};
use android_system_keystore2::aidl::android::system::keystore2::{
Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
@@ -39,6 +39,26 @@
/// Vold context
pub const TARGET_VOLD_CTX: &str = "u:r:vold:s0";
+/// Key parameters to generate a key.
+pub struct KeyParams {
+ /// Key Size.
+ pub key_size: i32,
+ /// Key Purposes.
+ pub purpose: Vec<KeyPurpose>,
+ /// Padding Mode.
+ pub padding: Option<PaddingMode>,
+ /// Digest.
+ pub digest: Option<Digest>,
+ /// MFG Digest.
+ pub mgf_digest: Option<Digest>,
+ /// Block Mode.
+ pub block_mode: Option<BlockMode>,
+ /// Attestation challenge.
+ pub att_challenge: Option<Vec<u8>>,
+ /// Attestation app id.
+ pub att_app_id: Option<Vec<u8>>,
+}
+
/// To map Keystore errors.
#[derive(thiserror::Error, Debug, Eq, PartialEq)]
pub enum Error {
@@ -168,3 +188,68 @@
}
Ok(key_metadata)
}
+
+/// Generate a RSA key with the given key parameters, alias, domain and namespace.
+pub fn generate_rsa_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ domain: Domain,
+ nspace: i64,
+ alias: Option<String>,
+ key_params: &KeyParams,
+ attest_key: Option<&KeyDescriptor>,
+) -> binder::Result<KeyMetadata> {
+ let mut gen_params = AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .rsa_public_exponent(65537)
+ .key_size(key_params.key_size);
+
+ for purpose in &key_params.purpose {
+ gen_params = gen_params.purpose(*purpose);
+ }
+ if let Some(value) = key_params.digest {
+ gen_params = gen_params.digest(value)
+ }
+ if let Some(value) = key_params.padding {
+ gen_params = gen_params.padding_mode(value);
+ }
+ if let Some(value) = key_params.mgf_digest {
+ gen_params = gen_params.mgf_digest(value);
+ }
+ if let Some(value) = key_params.block_mode {
+ gen_params = gen_params.block_mode(value)
+ }
+ if let Some(value) = &key_params.att_challenge {
+ gen_params = gen_params.attestation_challenge(value.to_vec())
+ }
+ if let Some(value) = &key_params.att_app_id {
+ gen_params = gen_params.attestation_app_id(value.to_vec())
+ }
+
+ let key_metadata = sec_level.generateKey(
+ &KeyDescriptor { domain, nspace, alias, blob: None },
+ attest_key,
+ &gen_params,
+ 0,
+ b"entropy",
+ )?;
+
+ // Must have a public key.
+ assert!(key_metadata.certificate.is_some());
+
+ if attest_key.is_none() && key_params.att_challenge.is_some() && key_params.att_app_id.is_some()
+ {
+ // Should have an attestation record.
+ assert!(key_metadata.certificateChain.is_some());
+ } else {
+ // Should not have an attestation record.
+ assert!(key_metadata.certificateChain.is_none());
+ }
+
+ assert!(
+ (domain == Domain::BLOB && key_metadata.key.blob.is_some())
+ || key_metadata.key.blob.is_none()
+ );
+
+ Ok(key_metadata)
+}