Tests to verify importWrappedKey functionality.
- Build ASN.1 DER-encoded wrapped key material `SecureKeyWrapper`.
Import the wrapped key material. Test should create DER-encoded
wrapped key material and import the secure key successfully.
Imported key should be used perform crypto operation successfully.
- Build ASN.1 DER-encoded wrapped key material `SecureKeyWrapper` with
invalid AAD. Try to import the wrapped key material. Test should
create DER-encoded wrapped key material. Test should fail to import
the secure key with error code `VERIFICATION_FAILED`.
- Import wrapped AES key and use it for crypto operations. Test should
import wrapped key and user it for performing crypto operations
successfully.
- Import a key wihtout WRAP_KEY purpose and try to use it as wrapping
key while importing wrapped key. Test should fail to import wrapped
key with an error code `INCOMPATIBLE_PURPOSE`.
- Try to import wrapped key using non-existing wrapping key in Android
keystore. Test should fail to import wrapped key with an error code
`KEY_NOT_FOUND`.
Bug: 194359114
Test: atest keystore2_client_test
Change-Id: Ic9ed03b6f945bd41c4873f97a84c1658c284e918
diff --git a/keystore2/test_utils/authorizations.rs b/keystore2/test_utils/authorizations.rs
index c2f0279..7dcee83 100644
--- a/keystore2/test_utils/authorizations.rs
+++ b/keystore2/test_utils/authorizations.rs
@@ -149,6 +149,15 @@
self
}
+ /// Add CALLER_NONCE.
+ pub fn caller_nonce(mut self) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::CALLER_NONCE,
+ value: KeyParameterValue::BoolValue(true),
+ });
+ self
+ }
+
/// Add MAC length.
pub fn mac_length(mut self, l: i32) -> Self {
self.0.push(KeyParameter { tag: Tag::MAC_LENGTH, value: KeyParameterValue::Integer(l) });
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index 175d8bb..53597af 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -18,13 +18,14 @@
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
- ErrorCode::ErrorCode, KeyOrigin::KeyOrigin, KeyParameter::KeyParameter,
- KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
- Tag::Tag,
+ ErrorCode::ErrorCode, HardwareAuthenticatorType::HardwareAuthenticatorType,
+ KeyOrigin::KeyOrigin, KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue,
+ KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, Tag::Tag,
};
use android_system_keystore2::aidl::android::system::keystore2::{
- Authorization::Authorization, Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
- KeyDescriptor::KeyDescriptor, KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
+ AuthenticatorSpec::AuthenticatorSpec, Authorization::Authorization, Domain::Domain,
+ IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+ KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
};
use crate::authorizations::AuthSetBuilder;
@@ -157,6 +158,131 @@
0xD6, 0x84, 0x98, 0xEA, 0x96, 0x91, 0xFB, 0x78, 0xED, 0x86,
];
+/// DER-encoded PKCS#8 format RSA key -
+/// Size: 2048
+/// Public Exponent: 65537
+/// Purpose: WRAP_KEY, ENCRYPT, DECRYPT
+/// Encryption scheme: RSAES-PKCS1-v1_5
+/// Digest: SHA_2_256
+/// Padding: RSA_OAEP
+/// This sample wrapping_key is taken from KeyMint tests
+/// (see hardware/interfaces/security/keymint/aidl/vts/functional/KeyMintTest.cpp).
+/// Similarly more test keys can be generated with below command -
+/// openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt -outform der | hexdump -e '30/1 "%02X" "\n"'
+pub static WRAPPING_KEY: &[u8] = &[
+ 0x30, 0x82, 0x04, 0xbe, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x04, 0xa8, 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01,
+ 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc3, 0x67, 0x93, 0x1d, 0x89, 0x00, 0xce, 0x56, 0xb0,
+ 0x06, 0x7f, 0x7d, 0x70, 0xe1, 0xfc, 0x65, 0x3f, 0x3f, 0x34, 0xd1, 0x94, 0xc1, 0xfe, 0xd5, 0x00,
+ 0x18, 0xfb, 0x43, 0xdb, 0x93, 0x7b, 0x06, 0xe6, 0x73, 0xa8, 0x37, 0x31, 0x3d, 0x56, 0xb1, 0xc7,
+ 0x25, 0x15, 0x0a, 0x3f, 0xef, 0x86, 0xac, 0xbd, 0xdc, 0x41, 0xbb, 0x75, 0x9c, 0x28, 0x54, 0xea,
+ 0xe3, 0x2d, 0x35, 0x84, 0x1e, 0xfb, 0x5c, 0x18, 0xd8, 0x2b, 0xc9, 0x0a, 0x1c, 0xb5, 0xc1, 0xd5,
+ 0x5a, 0xdf, 0x24, 0x5b, 0x02, 0x91, 0x1f, 0x0b, 0x7c, 0xda, 0x88, 0xc4, 0x21, 0xff, 0x0e, 0xba,
+ 0xfe, 0x7c, 0x0d, 0x23, 0xbe, 0x31, 0x2d, 0x7b, 0xd5, 0x92, 0x1f, 0xfa, 0xea, 0x13, 0x47, 0xc1,
+ 0x57, 0x40, 0x6f, 0xef, 0x71, 0x8f, 0x68, 0x26, 0x43, 0xe4, 0xe5, 0xd3, 0x3c, 0x67, 0x03, 0xd6,
+ 0x1c, 0x0c, 0xf7, 0xac, 0x0b, 0xf4, 0x64, 0x5c, 0x11, 0xf5, 0xc1, 0x37, 0x4c, 0x38, 0x86, 0x42,
+ 0x74, 0x11, 0xc4, 0x49, 0x79, 0x67, 0x92, 0xe0, 0xbe, 0xf7, 0x5d, 0xec, 0x85, 0x8a, 0x21, 0x23,
+ 0xc3, 0x67, 0x53, 0xe0, 0x2a, 0x95, 0xa9, 0x6d, 0x7c, 0x45, 0x4b, 0x50, 0x4d, 0xe3, 0x85, 0xa6,
+ 0x42, 0xe0, 0xdf, 0xc3, 0xe6, 0x0a, 0xc3, 0xa7, 0xee, 0x49, 0x91, 0xd0, 0xd4, 0x8b, 0x01, 0x72,
+ 0xa9, 0x5f, 0x95, 0x36, 0xf0, 0x2b, 0xa1, 0x3c, 0xec, 0xcc, 0xb9, 0x2b, 0x72, 0x7d, 0xb5, 0xc2,
+ 0x7e, 0x5b, 0x2f, 0x5c, 0xec, 0x09, 0x60, 0x0b, 0x28, 0x6a, 0xf5, 0xcf, 0x14, 0xc4, 0x20, 0x24,
+ 0xc6, 0x1d, 0xdf, 0xe7, 0x1c, 0x2a, 0x8d, 0x74, 0x58, 0xf1, 0x85, 0x23, 0x4c, 0xb0, 0x0e, 0x01,
+ 0xd2, 0x82, 0xf1, 0x0f, 0x8f, 0xc6, 0x72, 0x1d, 0x2a, 0xed, 0x3f, 0x48, 0x33, 0xcc, 0xa2, 0xbd,
+ 0x8f, 0xa6, 0x28, 0x21, 0xdd, 0x55, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x43,
+ 0x14, 0x47, 0xb6, 0x25, 0x19, 0x08, 0x11, 0x2b, 0x1e, 0xe7, 0x6f, 0x99, 0xf3, 0x71, 0x1a, 0x52,
+ 0xb6, 0x63, 0x09, 0x60, 0x04, 0x6c, 0x2d, 0xe7, 0x0d, 0xe1, 0x88, 0xd8, 0x33, 0xf8, 0xb8, 0xb9,
+ 0x1e, 0x4d, 0x78, 0x5c, 0xae, 0xee, 0xaf, 0x4f, 0x0f, 0x74, 0x41, 0x4e, 0x2c, 0xda, 0x40, 0x64,
+ 0x1f, 0x7f, 0xe2, 0x4f, 0x14, 0xc6, 0x7a, 0x88, 0x95, 0x9b, 0xdb, 0x27, 0x76, 0x6d, 0xf9, 0xe7,
+ 0x10, 0xb6, 0x30, 0xa0, 0x3a, 0xdc, 0x68, 0x3b, 0x5d, 0x2c, 0x43, 0x08, 0x0e, 0x52, 0xbe, 0xe7,
+ 0x1e, 0x9e, 0xae, 0xb6, 0xde, 0x29, 0x7a, 0x5f, 0xea, 0x10, 0x72, 0x07, 0x0d, 0x18, 0x1c, 0x82,
+ 0x2b, 0xcc, 0xff, 0x08, 0x7d, 0x63, 0xc9, 0x40, 0xba, 0x8a, 0x45, 0xf6, 0x70, 0xfe, 0xb2, 0x9f,
+ 0xb4, 0x48, 0x4d, 0x1c, 0x95, 0xe6, 0xd2, 0x57, 0x9b, 0xa0, 0x2a, 0xae, 0x0a, 0x00, 0x90, 0x0c,
+ 0x3e, 0xbf, 0x49, 0x0e, 0x3d, 0x2c, 0xd7, 0xee, 0x8d, 0x0e, 0x20, 0xc5, 0x36, 0xe4, 0xdc, 0x5a,
+ 0x50, 0x97, 0x27, 0x28, 0x88, 0xcd, 0xdd, 0x7e, 0x91, 0xf2, 0x28, 0xb1, 0xc4, 0xd7, 0x47, 0x4c,
+ 0x55, 0xb8, 0xfc, 0xd6, 0x18, 0xc4, 0xa9, 0x57, 0xbb, 0xdd, 0xd5, 0xad, 0x74, 0x07, 0xcc, 0x31,
+ 0x2d, 0x8d, 0x98, 0xa5, 0xca, 0xf7, 0xe0, 0x8f, 0x4a, 0x0d, 0x6b, 0x45, 0xbb, 0x41, 0xc6, 0x52,
+ 0x65, 0x9d, 0x5a, 0x5b, 0xa0, 0x5b, 0x66, 0x37, 0x37, 0xa8, 0x69, 0x62, 0x81, 0x86, 0x5b, 0xa2,
+ 0x0f, 0xbd, 0xd7, 0xf8, 0x51, 0xe6, 0xc5, 0x6e, 0x8c, 0xbe, 0x0d, 0xdb, 0xbf, 0x24, 0xdc, 0x03,
+ 0xb2, 0xd2, 0xcb, 0x4c, 0x3d, 0x54, 0x0f, 0xb0, 0xaf, 0x52, 0xe0, 0x34, 0xa2, 0xd0, 0x66, 0x98,
+ 0xb1, 0x28, 0xe5, 0xf1, 0x01, 0xe3, 0xb5, 0x1a, 0x34, 0xf8, 0xd8, 0xb4, 0xf8, 0x61, 0x81, 0x02,
+ 0x81, 0x81, 0x00, 0xde, 0x39, 0x2e, 0x18, 0xd6, 0x82, 0xc8, 0x29, 0x26, 0x6c, 0xc3, 0x45, 0x4e,
+ 0x1d, 0x61, 0x66, 0x24, 0x2f, 0x32, 0xd9, 0xa1, 0xd1, 0x05, 0x77, 0x75, 0x3e, 0x90, 0x4e, 0xa7,
+ 0xd0, 0x8b, 0xff, 0x84, 0x1b, 0xe5, 0xba, 0xc8, 0x2a, 0x16, 0x4c, 0x59, 0x70, 0x00, 0x70, 0x47,
+ 0xb8, 0xc5, 0x17, 0xdb, 0x8f, 0x8f, 0x84, 0xe3, 0x7b, 0xd5, 0x98, 0x85, 0x61, 0xbd, 0xf5, 0x03,
+ 0xd4, 0xdc, 0x2b, 0xdb, 0x38, 0xf8, 0x85, 0x43, 0x4a, 0xe4, 0x2c, 0x35, 0x5f, 0x72, 0x5c, 0x9a,
+ 0x60, 0xf9, 0x1f, 0x07, 0x88, 0xe1, 0xf1, 0xa9, 0x72, 0x23, 0xb5, 0x24, 0xb5, 0x35, 0x7f, 0xdf,
+ 0x72, 0xe2, 0xf6, 0x96, 0xba, 0xb7, 0xd7, 0x8e, 0x32, 0xbf, 0x92, 0xba, 0x8e, 0x18, 0x64, 0xea,
+ 0xb1, 0x22, 0x9e, 0x91, 0x34, 0x61, 0x30, 0x74, 0x8a, 0x6e, 0x3c, 0x12, 0x4f, 0x91, 0x49, 0xd7,
+ 0x1c, 0x74, 0x35, 0x02, 0x81, 0x81, 0x00, 0xc9, 0x53, 0x87, 0xc0, 0xf9, 0xd3, 0x5f, 0x13, 0x7b,
+ 0x57, 0xd0, 0xd6, 0x5c, 0x39, 0x7c, 0x5e, 0x21, 0xcc, 0x25, 0x1e, 0x47, 0x00, 0x8e, 0xd6, 0x2a,
+ 0x54, 0x24, 0x09, 0xc8, 0xb6, 0xb6, 0xac, 0x7f, 0x89, 0x67, 0xb3, 0x86, 0x3c, 0xa6, 0x45, 0xfc,
+ 0xce, 0x49, 0x58, 0x2a, 0x9a, 0xa1, 0x73, 0x49, 0xdb, 0x6c, 0x4a, 0x95, 0xaf, 0xfd, 0xae, 0x0d,
+ 0xae, 0x61, 0x2e, 0x1a, 0xfa, 0xc9, 0x9e, 0xd3, 0x9a, 0x2d, 0x93, 0x4c, 0x88, 0x04, 0x40, 0xae,
+ 0xd8, 0x83, 0x2f, 0x98, 0x43, 0x16, 0x3a, 0x47, 0xf2, 0x7f, 0x39, 0x21, 0x99, 0xdc, 0x12, 0x02,
+ 0xf9, 0xa0, 0xf9, 0xbd, 0x08, 0x30, 0x80, 0x07, 0xcb, 0x1e, 0x4e, 0x7f, 0x58, 0x30, 0x93, 0x66,
+ 0xa7, 0xde, 0x25, 0xf7, 0xc3, 0xc9, 0xb8, 0x80, 0x67, 0x7c, 0x06, 0x8e, 0x1b, 0xe9, 0x36, 0xe8,
+ 0x12, 0x88, 0x81, 0x52, 0x52, 0xa8, 0xa1, 0x02, 0x81, 0x80, 0x57, 0xff, 0x8c, 0xa1, 0x89, 0x50,
+ 0x80, 0xb2, 0xca, 0xe4, 0x86, 0xef, 0x0a, 0xdf, 0xd7, 0x91, 0xfb, 0x02, 0x35, 0xc0, 0xb8, 0xb3,
+ 0x6c, 0xd6, 0xc1, 0x36, 0xe5, 0x2e, 0x40, 0x85, 0xf4, 0xea, 0x5a, 0x06, 0x32, 0x12, 0xa4, 0xf1,
+ 0x05, 0xa3, 0x76, 0x47, 0x43, 0xe5, 0x32, 0x81, 0x98, 0x8a, 0xba, 0x07, 0x3f, 0x6e, 0x00, 0x27,
+ 0x29, 0x8e, 0x1c, 0x43, 0x78, 0x55, 0x6e, 0x0e, 0xfc, 0xa0, 0xe1, 0x4e, 0xce, 0x1a, 0xf7, 0x6a,
+ 0xd0, 0xb0, 0x30, 0xf2, 0x7a, 0xf6, 0xf0, 0xab, 0x35, 0xfb, 0x73, 0xa0, 0x60, 0xd8, 0xb1, 0xa0,
+ 0xe1, 0x42, 0xfa, 0x26, 0x47, 0xe9, 0x3b, 0x32, 0xe3, 0x6d, 0x82, 0x82, 0xae, 0x0a, 0x4d, 0xe5,
+ 0x0a, 0xb7, 0xaf, 0xe8, 0x55, 0x00, 0xa1, 0x6f, 0x43, 0xa6, 0x47, 0x19, 0xd6, 0xe2, 0xb9, 0x43,
+ 0x98, 0x23, 0x71, 0x9c, 0xd0, 0x8b, 0xcd, 0x03, 0x17, 0x81, 0x02, 0x81, 0x81, 0x00, 0xba, 0x73,
+ 0xb0, 0xbb, 0x28, 0xe3, 0xf8, 0x1e, 0x9b, 0xd1, 0xc5, 0x68, 0x71, 0x3b, 0x10, 0x12, 0x41, 0xac,
+ 0xc6, 0x07, 0x97, 0x6c, 0x4d, 0xdc, 0xcc, 0x90, 0xe6, 0x5b, 0x65, 0x56, 0xca, 0x31, 0x51, 0x60,
+ 0x58, 0xf9, 0x2b, 0x6e, 0x09, 0xf3, 0xb1, 0x60, 0xff, 0x0e, 0x37, 0x4e, 0xc4, 0x0d, 0x78, 0xae,
+ 0x4d, 0x49, 0x79, 0xfd, 0xe6, 0xac, 0x06, 0xa1, 0xa4, 0x00, 0xc6, 0x1d, 0xd3, 0x12, 0x54, 0x18,
+ 0x6a, 0xf3, 0x0b, 0x22, 0xc1, 0x05, 0x82, 0xa8, 0xa4, 0x3e, 0x34, 0xfe, 0x94, 0x9c, 0x5f, 0x3b,
+ 0x97, 0x55, 0xba, 0xe7, 0xba, 0xa7, 0xb7, 0xb7, 0xa6, 0xbd, 0x03, 0xb3, 0x8c, 0xef, 0x55, 0xc8,
+ 0x68, 0x85, 0xfc, 0x6c, 0x19, 0x78, 0xb9, 0xce, 0xe7, 0xef, 0x33, 0xda, 0x50, 0x7c, 0x9d, 0xf6,
+ 0xb9, 0x27, 0x7c, 0xff, 0x1e, 0x6a, 0xaa, 0x5d, 0x57, 0xac, 0xa5, 0x28, 0x46, 0x61, 0x02, 0x81,
+ 0x81, 0x00, 0xc9, 0x31, 0x61, 0x7c, 0x77, 0x82, 0x9d, 0xfb, 0x12, 0x70, 0x50, 0x2b, 0xe9, 0x19,
+ 0x5c, 0x8f, 0x28, 0x30, 0x88, 0x5f, 0x57, 0xdb, 0xa8, 0x69, 0x53, 0x68, 0x11, 0xe6, 0x86, 0x42,
+ 0x36, 0xd0, 0xc4, 0x73, 0x6a, 0x00, 0x08, 0xa1, 0x45, 0xaf, 0x36, 0xb8, 0x35, 0x7a, 0x7c, 0x3d,
+ 0x13, 0x99, 0x66, 0xd0, 0x4c, 0x4e, 0x00, 0x93, 0x4e, 0xa1, 0xae, 0xde, 0x3b, 0xb6, 0xb8, 0xec,
+ 0x84, 0x1d, 0xc9, 0x5e, 0x3f, 0x57, 0x97, 0x51, 0xe2, 0xbf, 0xdf, 0xe2, 0x7a, 0xe7, 0x78, 0x98,
+ 0x3f, 0x95, 0x93, 0x56, 0x21, 0x07, 0x23, 0x28, 0x7b, 0x0a, 0xff, 0xcc, 0x9f, 0x72, 0x70, 0x44,
+ 0xd4, 0x8c, 0x37, 0x3f, 0x1b, 0xab, 0xde, 0x07, 0x24, 0xfa, 0x17, 0xa4, 0xfd, 0x4d, 0xa0, 0x90,
+ 0x2c, 0x7c, 0x9b, 0x9b, 0xf2, 0x7b, 0xa6, 0x1b, 0xe6, 0xad, 0x02, 0xdf, 0xdd, 0xda, 0x8f, 0x4e,
+ 0x68, 0x22,
+];
+
+/// WrappedKeyData as ASN.1 DER-encoded data corresponding to the `SecureKeyWrapper` schema
+/// specified in IKeyMintDevice.aidl. Wrapped key parameters are -
+/// Algorithm: AES
+/// Key size: 256
+/// Block mode: ECB
+/// Padding mode: PKCS7
+/// This sample wrapped_key is taken from KeyMint tests (see KeyMintTest.cpp).
+pub static WRAPPED_KEY: &[u8] = &[
+ 0x30, 0x82, 0x01, 0x79, 0x02, 0x01, 0x00, 0x04, 0x82, 0x01, 0x00, 0x93, 0x4b, 0xf9, 0x4e, 0x2a,
+ 0xa2, 0x8a, 0x3f, 0x83, 0xc9, 0xf7, 0x92, 0x97, 0x25, 0x02, 0x62, 0xfb, 0xe3, 0x27, 0x6b, 0x5a,
+ 0x1c, 0x91, 0x15, 0x9b, 0xbf, 0xa3, 0xef, 0x89, 0x57, 0xaa, 0xc8, 0x4b, 0x59, 0xb3, 0x0b, 0x45,
+ 0x5a, 0x79, 0xc2, 0x97, 0x34, 0x80, 0x82, 0x3d, 0x8b, 0x38, 0x63, 0xc3, 0xde, 0xef, 0x4a, 0x8e,
+ 0x24, 0x35, 0x90, 0x26, 0x8d, 0x80, 0xe1, 0x87, 0x51, 0xa0, 0xe1, 0x30, 0xf6, 0x7c, 0xe6, 0xa1,
+ 0xac, 0xe9, 0xf7, 0x9b, 0x95, 0xe0, 0x97, 0x47, 0x4f, 0xeb, 0xc9, 0x81, 0x19, 0x5b, 0x1d, 0x13,
+ 0xa6, 0x90, 0x86, 0xc0, 0x86, 0x3f, 0x66, 0xa7, 0xb7, 0xfd, 0xb4, 0x87, 0x92, 0x22, 0x7b, 0x1a,
+ 0xc5, 0xe2, 0x48, 0x9f, 0xeb, 0xdf, 0x08, 0x7a, 0xb5, 0x48, 0x64, 0x83, 0x03, 0x3a, 0x6f, 0x00,
+ 0x1c, 0xa5, 0xd1, 0xec, 0x1e, 0x27, 0xf5, 0xc3, 0x0f, 0x4c, 0xec, 0x26, 0x42, 0x07, 0x4a, 0x39,
+ 0xae, 0x68, 0xae, 0xe5, 0x52, 0xe1, 0x96, 0x62, 0x7a, 0x8e, 0x3d, 0x86, 0x7e, 0x67, 0xa8, 0xc0,
+ 0x1b, 0x11, 0xe7, 0x5f, 0x13, 0xcc, 0xa0, 0xa9, 0x7a, 0xb6, 0x68, 0xb5, 0x0c, 0xda, 0x07, 0xa8,
+ 0xec, 0xb7, 0xcd, 0x8e, 0x3d, 0xd7, 0x00, 0x9c, 0x96, 0x36, 0x53, 0x4f, 0x6f, 0x23, 0x9c, 0xff,
+ 0xe1, 0xfc, 0x8d, 0xaa, 0x46, 0x6f, 0x78, 0xb6, 0x76, 0xc7, 0x11, 0x9e, 0xfb, 0x96, 0xbc, 0xe4,
+ 0xe6, 0x9c, 0xa2, 0xa2, 0x5d, 0x0b, 0x34, 0xed, 0x9c, 0x3f, 0xf9, 0x99, 0xb8, 0x01, 0x59, 0x7d,
+ 0x52, 0x20, 0xe3, 0x07, 0xea, 0xa5, 0xbe, 0xe5, 0x07, 0xfb, 0x94, 0xd1, 0xfa, 0x69, 0xf9, 0xe5,
+ 0x19, 0xb2, 0xde, 0x31, 0x5b, 0xac, 0x92, 0xc3, 0x6f, 0x2e, 0xa1, 0xfa, 0x1d, 0xf4, 0x47, 0x8c,
+ 0x0d, 0xde, 0xde, 0xae, 0x8c, 0x70, 0xe0, 0x23, 0x3c, 0xd0, 0x98, 0x04, 0x0c, 0xd7, 0x96, 0xb0,
+ 0x2c, 0x37, 0x0f, 0x1f, 0xa4, 0xcc, 0x01, 0x24, 0xf1, 0x30, 0x2e, 0x02, 0x01, 0x03, 0x30, 0x29,
+ 0xa1, 0x08, 0x31, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0xa2, 0x03, 0x02, 0x01, 0x20, 0xa3,
+ 0x04, 0x02, 0x02, 0x01, 0x00, 0xa4, 0x05, 0x31, 0x03, 0x02, 0x01, 0x01, 0xa6, 0x05, 0x31, 0x03,
+ 0x02, 0x01, 0x40, 0xbf, 0x83, 0x77, 0x02, 0x05, 0x00, 0x04, 0x20, 0xcc, 0xd5, 0x40, 0x85, 0x5f,
+ 0x83, 0x3a, 0x5e, 0x14, 0x80, 0xbf, 0xd2, 0xd3, 0x6f, 0xaf, 0x3a, 0xee, 0xe1, 0x5d, 0xf5, 0xbe,
+ 0xab, 0xe2, 0x69, 0x1b, 0xc8, 0x2d, 0xde, 0x2a, 0x7a, 0xa9, 0x10, 0x04, 0x10, 0x64, 0xc9, 0xf6,
+ 0x89, 0xc6, 0x0f, 0xf6, 0x22, 0x3a, 0xb6, 0xe6, 0x99, 0x9e, 0x0e, 0xb6, 0xe5,
+];
+
/// To map Keystore errors.
#[derive(thiserror::Error, Debug, Eq, PartialEq)]
pub enum Error {
@@ -172,6 +298,9 @@
/// This is returned if the C implementation of extractSubjectFromCertificate failed.
#[error("Failed to validate certificate chain.")]
ValidateCertChainFailed,
+ /// Error code to indicate error in ASN.1 DER-encoded data creation.
+ #[error("Failed to create and encode ASN.1 data.")]
+ DerEncodeFailed,
}
/// Keystore2 error mapping.
@@ -564,7 +693,8 @@
Ok(ec_key_metadata)
}
-fn check_key_param(authorizations: &[Authorization], key_param: KeyParameter) -> bool {
+/// Verify that given key param is listed in given authorizations list.
+pub fn check_key_param(authorizations: &[Authorization], key_param: KeyParameter) -> bool {
for authrization in authorizations {
if authrization.keyParameter == key_param {
return true;
@@ -836,3 +966,103 @@
Ok(key_metadata)
}
+
+/// Imports RSA encryption key with WRAP_KEY purpose.
+pub fn import_wrapping_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ wrapping_key_data: &[u8],
+ wrapping_key_alias: Option<String>,
+) -> binder::Result<KeyMetadata> {
+ let wrapping_key_params = AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .digest(Digest::SHA_2_256)
+ .purpose(KeyPurpose::ENCRYPT)
+ .purpose(KeyPurpose::DECRYPT)
+ .purpose(KeyPurpose::WRAP_KEY)
+ .padding_mode(PaddingMode::RSA_OAEP)
+ .key_size(2048)
+ .rsa_public_exponent(65537)
+ .cert_not_before(0)
+ .cert_not_after(253402300799000);
+
+ sec_level.importKey(
+ &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: wrapping_key_alias, blob: None },
+ None,
+ &wrapping_key_params,
+ 0,
+ wrapping_key_data,
+ )
+}
+
+/// Import wrapped key using given wrapping key.
+pub fn import_wrapped_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ alias: Option<String>,
+ wrapping_key_metadata: &KeyMetadata,
+ wrapped_key: Option<Vec<u8>>,
+) -> binder::Result<KeyMetadata> {
+ let unwrap_params =
+ AuthSetBuilder::new().digest(Digest::SHA_2_256).padding_mode(PaddingMode::RSA_OAEP);
+
+ let authenticator_spec: &[AuthenticatorSpec] = &[AuthenticatorSpec {
+ authenticatorType: HardwareAuthenticatorType::NONE,
+ authenticatorId: 0,
+ }];
+
+ let key_metadata = sec_level.importWrappedKey(
+ &KeyDescriptor { domain: Domain::APP, nspace: -1, alias, blob: wrapped_key },
+ &wrapping_key_metadata.key,
+ None,
+ &unwrap_params,
+ authenticator_spec,
+ )?;
+
+ Ok(key_metadata)
+}
+
+/// Import wrapping key and then import wrapped key using wrapping key.
+pub fn import_wrapping_key_and_wrapped_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ domain: Domain,
+ nspace: i64,
+ alias: Option<String>,
+ wrapping_key_alias: Option<String>,
+ wrapping_key_params: AuthSetBuilder,
+) -> binder::Result<KeyMetadata> {
+ let wrapping_key_metadata = sec_level.importKey(
+ &KeyDescriptor { domain, nspace, alias: wrapping_key_alias, blob: None },
+ None,
+ &wrapping_key_params,
+ 0,
+ WRAPPING_KEY,
+ )?;
+
+ import_wrapped_key(sec_level, alias, &wrapping_key_metadata, Some(WRAPPED_KEY.to_vec()))
+}
+
+/// Import given key material as AES-256-GCM-NONE transport key.
+pub fn import_transport_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ transport_key_alias: Option<String>,
+ transport_key: &[u8],
+) -> binder::Result<KeyMetadata> {
+ let transport_key_params = AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::AES)
+ .block_mode(BlockMode::GCM)
+ .padding_mode(PaddingMode::NONE)
+ .key_size(256)
+ .caller_nonce()
+ .min_mac_length(128)
+ .purpose(KeyPurpose::ENCRYPT)
+ .purpose(KeyPurpose::DECRYPT);
+
+ sec_level.importKey(
+ &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: transport_key_alias, blob: None },
+ None,
+ &transport_key_params,
+ 0,
+ transport_key,
+ )
+}
diff --git a/keystore2/tests/Android.bp b/keystore2/tests/Android.bp
index dd5d782..78dd2d7 100644
--- a/keystore2/tests/Android.bp
+++ b/keystore2/tests/Android.bp
@@ -36,7 +36,7 @@
rustlibs: [
"librustutils",
"libkeystore2_test_utils",
- "packagemanager_aidl-rust",
+ "packagemanager_aidl-rust",
"libnix",
"libanyhow",
"libbinder_rs",
@@ -44,8 +44,8 @@
"liblibc",
"libserde",
"libthiserror",
- "libcxx",
- "libopenssl",
+ "libcxx",
+ "libopenssl",
],
static_libs: [
"libkeystore2_ffi_test_utils",
@@ -54,6 +54,9 @@
],
shared_libs: [
"libcrypto",
+ "libkeymaster_portable",
+ "libkeymaster_messages",
+ "libcppbor_external",
],
require_root: true,
}
@@ -67,17 +70,31 @@
],
generated_headers: [
"cxx-bridge-header",
+ "libkeystore2_ffi_test_utils_bridge_header",
],
generated_sources: ["libkeystore2_ffi_test_utils_bridge_code"],
static_libs: [
"libkeymint_vts_test_utils",
],
+ shared_libs: [
+ "libkeymaster_portable",
+ "libkeymaster_messages",
+ "libcppbor_external",
+ ],
}
genrule {
name: "libkeystore2_ffi_test_utils_bridge_code",
tools: ["cxxbridge"],
cmd: "$(location cxxbridge) $(in) >> $(out)",
- srcs: ["keystore2_client_attest_key_tests.rs"],
+ srcs: ["ffi_test_utils.rs"],
out: ["libkeystore2_test_utils_cxx_generated.cc"],
}
+
+genrule {
+ name: "libkeystore2_ffi_test_utils_bridge_header",
+ tools: ["cxxbridge"],
+ cmd: "$(location cxxbridge) $(in) --header >> $(out)",
+ srcs: ["ffi_test_utils.rs"],
+ out: ["ffi_test_utils.rs.h"],
+}
diff --git a/keystore2/tests/ffi_test_utils.cpp b/keystore2/tests/ffi_test_utils.cpp
index fb5a7d2..45ce02c 100644
--- a/keystore2/tests/ffi_test_utils.cpp
+++ b/keystore2/tests/ffi_test_utils.cpp
@@ -4,15 +4,86 @@
#include <KeyMintAidlTestBase.h>
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <keymaster/UniquePtr.h>
+#include <memory>
#include <vector>
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
+
+#include <keymaster/km_openssl/attestation_record.h>
+#include <keymaster/km_openssl/openssl_err.h>
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <openssl/asn1t.h>
+
using aidl::android::hardware::security::keymint::ErrorCode;
#define TAG_SEQUENCE 0x30
#define LENGTH_MASK 0x80
#define LENGTH_VALUE_MASK 0x7F
+/**
+ * ASN.1 structure for `KeyDescription` Schema.
+ * See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
+ * KeyDescription ::= SEQUENCE(
+ * keyFormat INTEGER, # Values from KeyFormat enum.
+ * keyParams AuthorizationList,
+ * )
+ */
+typedef struct key_description {
+ ASN1_INTEGER* key_format;
+ keymaster::KM_AUTH_LIST* key_params;
+} TEST_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(TEST_KEY_DESCRIPTION) = {
+ ASN1_SIMPLE(TEST_KEY_DESCRIPTION, key_format, ASN1_INTEGER),
+ ASN1_SIMPLE(TEST_KEY_DESCRIPTION, key_params, keymaster::KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(TEST_KEY_DESCRIPTION);
+DECLARE_ASN1_FUNCTIONS(TEST_KEY_DESCRIPTION);
+
+/**
+ * ASN.1 structure for `SecureKeyWrapper` Schema.
+ * See `IKeyMintDevice.aidl` for documentation of the `SecureKeyWrapper` schema.
+ * SecureKeyWrapper ::= SEQUENCE(
+ * version INTEGER, # Contains value 0
+ * encryptedTransportKey OCTET_STRING,
+ * initializationVector OCTET_STRING,
+ * keyDescription KeyDescription,
+ * encryptedKey OCTET_STRING,
+ * tag OCTET_STRING
+ * )
+ */
+typedef struct secure_key_wrapper {
+ ASN1_INTEGER* version;
+ ASN1_OCTET_STRING* encrypted_transport_key;
+ ASN1_OCTET_STRING* initialization_vector;
+ TEST_KEY_DESCRIPTION* key_desc;
+ ASN1_OCTET_STRING* encrypted_key;
+ ASN1_OCTET_STRING* tag;
+} TEST_SECURE_KEY_WRAPPER;
+
+ASN1_SEQUENCE(TEST_SECURE_KEY_WRAPPER) = {
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, version, ASN1_INTEGER),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, encrypted_transport_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, initialization_vector, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, key_desc, TEST_KEY_DESCRIPTION),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, encrypted_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, tag, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(TEST_SECURE_KEY_WRAPPER);
+DECLARE_ASN1_FUNCTIONS(TEST_SECURE_KEY_WRAPPER);
+
+IMPLEMENT_ASN1_FUNCTIONS(TEST_SECURE_KEY_WRAPPER);
+IMPLEMENT_ASN1_FUNCTIONS(TEST_KEY_DESCRIPTION);
+
+struct TEST_KEY_DESCRIPTION_Delete {
+ void operator()(TEST_KEY_DESCRIPTION* p) { TEST_KEY_DESCRIPTION_free(p); }
+};
+struct TEST_SECURE_KEY_WRAPPER_Delete {
+ void operator()(TEST_SECURE_KEY_WRAPPER* p) { TEST_SECURE_KEY_WRAPPER_free(p); }
+};
+
/* This function extracts a certificate from the certs_chain_buffer at the given
* offset. Each DER encoded certificate starts with TAG_SEQUENCE followed by the
* total length of the certificate. The length of the certificate is determined
@@ -118,3 +189,178 @@
return false;
}
+
+/**
+ * Below mentioned key parameters are used to create authorization list of
+ * secure key.
+ * Algorithm: AES-256
+ * Padding: PKCS7
+ * Blockmode: ECB
+ * Purpose: Encrypt, Decrypt
+ */
+keymaster::AuthorizationSet build_wrapped_key_auth_list() {
+ return keymaster::AuthorizationSet(keymaster::AuthorizationSetBuilder()
+ .AesEncryptionKey(256)
+ .Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_ECB)
+ .Authorization(keymaster::TAG_PADDING, KM_PAD_PKCS7)
+ .Authorization(keymaster::TAG_NO_AUTH_REQUIRED));
+}
+
+/**
+ * Creates ASN.1 DER-encoded data corresponding to `KeyDescription` schema as
+ * AAD. See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
+ */
+CxxResult buildAsn1DerEncodedWrappedKeyDescription() {
+ CxxResult cxx_result{};
+ keymaster_error_t error;
+ cxx_result.error = KM_ERROR_OK;
+
+ keymaster::UniquePtr<TEST_KEY_DESCRIPTION, TEST_KEY_DESCRIPTION_Delete> key_description(
+ TEST_KEY_DESCRIPTION_new());
+ if (!key_description.get()) {
+ cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return cxx_result;
+ }
+
+ // Fill secure key authorizations.
+ keymaster::AuthorizationSet auth_list = build_wrapped_key_auth_list();
+ error = build_auth_list(auth_list, key_description->key_params);
+ if (error != KM_ERROR_OK) {
+ cxx_result.error = error;
+ return cxx_result;
+ }
+
+ // Fill secure key format.
+ if (!ASN1_INTEGER_set(key_description->key_format, KM_KEY_FORMAT_RAW)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Perform ASN.1 DER encoding of KeyDescription.
+ size_t asn1_data_len = i2d_TEST_KEY_DESCRIPTION(key_description.get(), nullptr);
+ if (asn1_data_len < 0) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+ std::vector<uint8_t> asn1_data(asn1_data_len, 0);
+
+ if (!asn1_data.data()) {
+ cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return cxx_result;
+ }
+
+ uint8_t* p = asn1_data.data();
+ asn1_data_len = i2d_TEST_KEY_DESCRIPTION(key_description.get(), &p);
+ if (asn1_data_len < 0) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ std::move(asn1_data.begin(), asn1_data.end(), std::back_inserter(cxx_result.data));
+
+ return cxx_result;
+}
+
+/**
+ * Creates wrapped key material to import in ASN.1 DER-encoded data corresponding to
+ * `SecureKeyWrapper` schema. See `IKeyMintDevice.aidl` for documentation of the `SecureKeyWrapper`
+ * schema.
+ */
+CxxResult createWrappedKey(rust::Vec<rust::u8> encrypted_secure_key,
+ rust::Vec<rust::u8> encrypted_transport_key, rust::Vec<rust::u8> iv,
+ rust::Vec<rust::u8> tag) {
+ CxxResult cxx_result{};
+ keymaster_error_t error;
+ cxx_result.error = KM_ERROR_OK;
+
+ uint8_t* enc_secure_key_data = encrypted_secure_key.data();
+ int enc_secure_key_size = encrypted_secure_key.size();
+
+ uint8_t* iv_data = iv.data();
+ int iv_size = iv.size();
+
+ uint8_t* tag_data = tag.data();
+ int tag_size = tag.size();
+
+ uint8_t* enc_transport_key_data = encrypted_transport_key.data();
+ int enc_transport_key_size = encrypted_transport_key.size();
+
+ keymaster::UniquePtr<TEST_SECURE_KEY_WRAPPER, TEST_SECURE_KEY_WRAPPER_Delete> sec_key_wrapper(
+ TEST_SECURE_KEY_WRAPPER_new());
+ if (!sec_key_wrapper.get()) {
+ cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return cxx_result;
+ }
+
+ // Fill version = 0
+ if (!ASN1_INTEGER_set(sec_key_wrapper->version, 0)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill encrypted transport key.
+ if (enc_transport_key_size &&
+ !ASN1_OCTET_STRING_set(sec_key_wrapper->encrypted_transport_key, enc_transport_key_data,
+ enc_transport_key_size)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill encrypted secure key.
+ if (enc_secure_key_size && !ASN1_OCTET_STRING_set(sec_key_wrapper->encrypted_key,
+ enc_secure_key_data, enc_secure_key_size)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill secure key authorization list.
+ keymaster::AuthorizationSet auth_list = build_wrapped_key_auth_list();
+ error = build_auth_list(auth_list, sec_key_wrapper->key_desc->key_params);
+ if (error != KM_ERROR_OK) {
+ cxx_result.error = error;
+ return cxx_result;
+ }
+
+ // Fill secure key format.
+ if (!ASN1_INTEGER_set(sec_key_wrapper->key_desc->key_format, KM_KEY_FORMAT_RAW)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill initialization vector used for encrypting secure key.
+ if (iv_size &&
+ !ASN1_OCTET_STRING_set(sec_key_wrapper->initialization_vector, iv_data, iv_size)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill GCM-tag, extracted during secure key encryption.
+ if (tag_size && !ASN1_OCTET_STRING_set(sec_key_wrapper->tag, tag_data, tag_size)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // ASN.1 DER-encoding of secure key wrapper.
+ size_t asn1_data_len = i2d_TEST_SECURE_KEY_WRAPPER(sec_key_wrapper.get(), nullptr);
+ if (asn1_data_len < 0) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+ std::vector<uint8_t> asn1_data(asn1_data_len, 0);
+
+ if (!asn1_data.data()) {
+ cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return cxx_result;
+ }
+
+ uint8_t* p = asn1_data.data();
+ asn1_data_len = i2d_TEST_SECURE_KEY_WRAPPER(sec_key_wrapper.get(), &p);
+ if (asn1_data_len < 0) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ std::move(asn1_data.begin(), asn1_data.end(), std::back_inserter(cxx_result.data));
+
+ return cxx_result;
+}
diff --git a/keystore2/tests/ffi_test_utils.hpp b/keystore2/tests/ffi_test_utils.hpp
index 7f5c3b2..b8c7c48 100644
--- a/keystore2/tests/ffi_test_utils.hpp
+++ b/keystore2/tests/ffi_test_utils.hpp
@@ -1,5 +1,11 @@
#pragma once
#include "rust/cxx.h"
+#include "ffi_test_utils.rs.h"
bool validateCertChain(rust::Vec<rust::u8> cert_buf, uint32_t cert_len, bool strict_issuer_check);
+CxxResult createWrappedKey(rust::Vec<rust::u8> encrypted_secure_key,
+ rust::Vec<rust::u8> encrypted_transport_key,
+ rust::Vec<rust::u8> iv,
+ rust::Vec<rust::u8> tag);
+CxxResult buildAsn1DerEncodedWrappedKeyDescription();
diff --git a/keystore2/tests/ffi_test_utils.rs b/keystore2/tests/ffi_test_utils.rs
new file mode 100644
index 0000000..066d4a1
--- /dev/null
+++ b/keystore2/tests/ffi_test_utils.rs
@@ -0,0 +1,80 @@
+// Copyright 2022, 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 keystore2_test_utils::key_generations::Error;
+
+#[cxx::bridge]
+mod ffi {
+ struct CxxResult {
+ data: Vec<u8>,
+ error: i32,
+ }
+
+ unsafe extern "C++" {
+ include!("ffi_test_utils.hpp");
+ fn validateCertChain(cert_buf: Vec<u8>, cert_len: u32, strict_issuer_check: bool) -> bool;
+ fn createWrappedKey(
+ encrypted_secure_key: Vec<u8>,
+ encrypted_transport_key: Vec<u8>,
+ iv: Vec<u8>,
+ tag: Vec<u8>,
+ ) -> CxxResult;
+ fn buildAsn1DerEncodedWrappedKeyDescription() -> CxxResult;
+ }
+}
+
+/// 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) {
+ return Ok(true);
+ }
+
+ Err(Error::ValidateCertChainFailed)
+}
+
+fn get_result(result: ffi::CxxResult) -> Result<Vec<u8>, Error> {
+ if result.error == 0 && !result.data.is_empty() {
+ Ok(result.data)
+ } else {
+ Err(Error::DerEncodeFailed)
+ }
+}
+
+/// Creates wrapped key material to import in ASN.1 DER-encoded data corresponding to
+/// `SecureKeyWrapper`. See `IKeyMintDevice.aidl` for documentation of the `SecureKeyWrapper`
+/// schema.
+pub fn create_wrapped_key(
+ encrypted_secure_key: &[u8],
+ encrypted_transport_key: &[u8],
+ iv: &[u8],
+ tag: &[u8],
+) -> Result<Vec<u8>, Error> {
+ get_result(ffi::createWrappedKey(
+ encrypted_secure_key.to_vec(),
+ encrypted_transport_key.to_vec(),
+ iv.to_vec(),
+ tag.to_vec(),
+ ))
+}
+
+/// Creates ASN.1 DER-encoded data corresponding to `KeyDescription` schema.
+/// See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
+/// Below mentioned key parameters are used -
+/// Algorithm: AES-256
+/// Padding: PKCS7
+/// Blockmode: ECB
+/// Purpose: Encrypt, Decrypt
+pub fn create_wrapped_key_additional_auth_data() -> Result<Vec<u8>, Error> {
+ get_result(ffi::buildAsn1DerEncodedWrappedKeyDescription())
+}
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index fc3148c..5644fbe 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -27,28 +27,13 @@
authorizations, get_keystore_service, key_generations, key_generations::Error,
};
+use crate::ffi_test_utils::validate_certchain;
+
use crate::{
keystore2_client_test_utils::app_attest_key_feature_exists,
skip_test_if_no_app_attest_key_feature,
};
-#[cxx::bridge]
-mod ffi {
- unsafe extern "C++" {
- include!("ffi_test_utils.hpp");
- fn validateCertChain(cert_buf: Vec<u8>, cert_len: u32, strict_issuer_check: bool) -> bool;
- }
-}
-
-/// 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) {
- return Ok(true);
- }
-
- Err(Error::ValidateCertChainFailed)
-}
-
/// Generate RSA and EC attestation keys and use them for signing RSA-signing keys.
/// Test should be able to generate attestation keys and use them successfully.
#[test]
diff --git a/keystore2/tests/keystore2_client_import_keys_tests.rs b/keystore2/tests/keystore2_client_import_keys_tests.rs
index abf35b5..c8f94b6 100644
--- a/keystore2/tests/keystore2_client_import_keys_tests.rs
+++ b/keystore2/tests/keystore2_client_import_keys_tests.rs
@@ -14,21 +14,29 @@
use nix::unistd::getuid;
+use openssl::rand::rand_bytes;
+use openssl::x509::X509;
+
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
- ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
- SecurityLevel::SecurityLevel,
+ ErrorCode::ErrorCode, HardwareAuthenticatorType::HardwareAuthenticatorType,
+ KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, SecurityLevel::SecurityLevel,
};
use android_system_keystore2::aidl::android::system::keystore2::{
- Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+ AuthenticatorSpec::AuthenticatorSpec, Domain::Domain,
+ IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+ KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
};
use keystore2_test_utils::{
authorizations, get_keystore_service, key_generations, key_generations::Error,
};
+use crate::ffi_test_utils::{create_wrapped_key, create_wrapped_key_additional_auth_data};
+
use crate::keystore2_client_test_utils::{
- has_trusty_keymint, perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
+ encrypt_secure_key, encrypt_transport_key, has_trusty_keymint,
+ perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
};
@@ -51,6 +59,76 @@
);
}
+fn perform_sym_key_encrypt_decrypt_op(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ key_metadata: &KeyMetadata,
+) {
+ let cipher_text = perform_sample_sym_key_encrypt_op(
+ sec_level,
+ PaddingMode::PKCS7,
+ BlockMode::ECB,
+ &mut None,
+ None,
+ &key_metadata.key,
+ )
+ .unwrap();
+
+ assert!(cipher_text.is_some());
+
+ let plain_text = perform_sample_sym_key_decrypt_op(
+ sec_level,
+ &cipher_text.unwrap(),
+ PaddingMode::PKCS7,
+ BlockMode::ECB,
+ &mut None,
+ None,
+ &key_metadata.key,
+ )
+ .unwrap();
+
+ assert!(plain_text.is_some());
+ assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+}
+
+fn build_secure_key_wrapper(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ secure_key: &[u8],
+ transport_key: &[u8],
+ nonce: &[u8],
+ aad: &[u8],
+ wrapping_key_metadata: &KeyMetadata,
+) -> Result<Vec<u8>, Error> {
+ // Encrypt secure key with transport key.
+ let transport_key_alias = format!("ks_transport_key_aes_256_key_test_{}", getuid());
+ let transport_key_metadata =
+ key_generations::import_transport_key(sec_level, Some(transport_key_alias), transport_key)
+ .unwrap();
+ let encrypted_secure_key = encrypt_secure_key(
+ sec_level,
+ secure_key,
+ aad,
+ nonce.to_vec(),
+ 128,
+ &transport_key_metadata.key,
+ )
+ .unwrap();
+
+ // Extract GCM-tag and encrypted secure key data.
+ let encrypted_secure_key = encrypted_secure_key.unwrap();
+ let gcm_tag: Vec<u8> =
+ encrypted_secure_key[secure_key.len()..(encrypted_secure_key.len())].to_vec();
+ let encrypted_secure_key: Vec<u8> = encrypted_secure_key[0..secure_key.len()].to_vec();
+
+ // Get wrapping key puplic part and encrypt the transport key.
+ let cert_bytes = wrapping_key_metadata.certificate.as_ref().unwrap();
+ let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
+ let public_key = cert.public_key().unwrap();
+ let encrypted_transport_key = encrypt_transport_key(transport_key, &public_key).unwrap();
+
+ // Create `SecureKeyWrapper` ASN.1 DER-encoded data.
+ create_wrapped_key(&encrypted_secure_key, &encrypted_transport_key, nonce, &gcm_tag)
+}
+
/// Import RSA key and verify imported key parameters. Try to create an operation using the
/// imported key. Test should be able to create an operation successfully.
#[test]
@@ -289,31 +367,7 @@
let key_metadata = key_generations::import_aes_key(&sec_level, Domain::APP, -1, Some(alias))
.expect("Failed to import AES key.");
- let cipher_text = perform_sample_sym_key_encrypt_op(
- &sec_level,
- PaddingMode::PKCS7,
- BlockMode::ECB,
- &mut None,
- None,
- &key_metadata.key,
- )
- .unwrap();
-
- assert!(cipher_text.is_some());
-
- let plain_text = perform_sample_sym_key_decrypt_op(
- &sec_level,
- &cipher_text.unwrap(),
- PaddingMode::PKCS7,
- BlockMode::ECB,
- &mut None,
- None,
- &key_metadata.key,
- )
- .unwrap();
-
- assert!(plain_text.is_some());
- assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+ perform_sym_key_encrypt_decrypt_op(&sec_level, &key_metadata);
}
/// Import 3DES key and verify key parameters. Try to create an operation using the imported key.
@@ -331,31 +385,7 @@
let key_metadata = key_generations::import_3des_key(&sec_level, Domain::APP, -1, Some(alias))
.expect("Failed to import 3DES key.");
- let cipher_text = perform_sample_sym_key_encrypt_op(
- &sec_level,
- PaddingMode::PKCS7,
- BlockMode::ECB,
- &mut None,
- None,
- &key_metadata.key,
- )
- .unwrap();
-
- assert!(cipher_text.is_some());
-
- let plain_text = perform_sample_sym_key_decrypt_op(
- &sec_level,
- &cipher_text.unwrap(),
- PaddingMode::PKCS7,
- BlockMode::ECB,
- &mut None,
- None,
- &key_metadata.key,
- )
- .unwrap();
-
- assert!(plain_text.is_some());
- assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+ perform_sym_key_encrypt_decrypt_op(&sec_level, &key_metadata);
}
/// Import HMAC key and verify key parameters. Try to create an operation using the imported key.
@@ -372,3 +402,234 @@
perform_sample_hmac_sign_verify_op(&sec_level, &key_metadata.key);
}
+
+/// This test creates a wrapped key data and imports it. Validates the imported wrapped key.
+/// 1. Create a wrapped key material to import, as ASN.1 DER-encoded data corresponding to the
+/// `SecureKeyWrapper` schema defined in IKeyMintDevice.aidl.
+/// 2. Import wrapped key and use it for crypto operations.
+/// Test should successfully import the wrapped key and perform crypto operations.
+#[test]
+fn keystore2_create_wrapped_key_and_import_wrapped_key_success() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let mut secure_key = [0; 32];
+ rand_bytes(&mut secure_key).unwrap();
+
+ let mut transport_key = [0; 32];
+ rand_bytes(&mut transport_key).unwrap();
+
+ let mut nonce = [0; 12];
+ rand_bytes(&mut nonce).unwrap();
+
+ // Import wrapping key.
+ let wrapping_key_alias = format!("ks_wrapping_key_test_import_2_{}_2048", getuid());
+ let wrapping_key_metadata = key_generations::import_wrapping_key(
+ &sec_level,
+ key_generations::RSA_2048_KEY,
+ Some(wrapping_key_alias),
+ )
+ .unwrap();
+
+ // Create the DER-encoded representation of `KeyDescription` schema defined in
+ // `IKeyMintDevice.aidl` and use it as additional authenticated data.
+ let aad = create_wrapped_key_additional_auth_data().unwrap();
+
+ // Build ASN.1 DER-encoded wrapped key material as described in `SecureKeyWrapper` schema.
+ let wrapped_key_data = build_secure_key_wrapper(
+ &sec_level,
+ &secure_key,
+ &transport_key,
+ &nonce,
+ &aad,
+ &wrapping_key_metadata,
+ )
+ .unwrap();
+
+ // Unwrap the key. Import wrapped key.
+ let secured_key_alias = format!("ks_wrapped_aes_key_{}", getuid());
+ let secured_key_metadata = key_generations::import_wrapped_key(
+ &sec_level,
+ Some(secured_key_alias),
+ &wrapping_key_metadata,
+ Some(wrapped_key_data.to_vec()),
+ )
+ .unwrap();
+
+ perform_sym_key_encrypt_decrypt_op(&sec_level, &secured_key_metadata);
+}
+
+/// Create a wrapped key data with invalid Additional Authenticated Data (AAD) and
+/// try to import wrapped key.
+/// 1. Create a wrapped key material with invalid AAD to import, as ASN.1 DER-encoded
+/// data corresponding to the `SecureKeyWrapper` schema defined in IKeyMintDevice.aidl.
+/// 2. Import wrapped key and use it for crypto operations.
+/// Test should fail to import the wrapped key with error code `VERIFICATION_FAILED`.
+#[test]
+fn keystore2_create_wrapped_key_with_invalid_aad_and_import_wrapped_key_fail() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let mut secure_key = [0; 32];
+ rand_bytes(&mut secure_key).unwrap();
+
+ let mut transport_key = [0; 32];
+ rand_bytes(&mut transport_key).unwrap();
+
+ let mut nonce = [0; 12];
+ rand_bytes(&mut nonce).unwrap();
+
+ // Import wrapping key.
+ let wrapping_key_alias = format!("ks_wrapping_key_test_import_2_{}_2048", getuid());
+ let wrapping_key_metadata = key_generations::import_wrapping_key(
+ &sec_level,
+ key_generations::RSA_2048_KEY,
+ Some(wrapping_key_alias),
+ )
+ .unwrap();
+
+ // Use invalid value as the additional authenticated data.
+ let aad = b"foo";
+
+ // Build ASN.1 DER-encoded wrapped key material as described in `SecureKeyWrapper` schema.
+ let wrapped_key_data = build_secure_key_wrapper(
+ &sec_level,
+ &secure_key,
+ &transport_key,
+ &nonce,
+ aad,
+ &wrapping_key_metadata,
+ )
+ .unwrap();
+
+ // Unwrap the key. Import wrapped key.
+ let secured_key_alias = format!("ks_wrapped_aes_key_{}", getuid());
+ let result = key_generations::map_ks_error(key_generations::import_wrapped_key(
+ &sec_level,
+ Some(secured_key_alias),
+ &wrapping_key_metadata,
+ Some(wrapped_key_data.to_vec()),
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::VERIFICATION_FAILED), result.unwrap_err());
+}
+
+/// Import wrapped AES key and use it for crypto operations. Test should import wrapped key and
+/// perform crypto operations successfully.
+#[test]
+fn keystore2_import_wrapped_key_success() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = format!("ks_wrapped_key_test_import_1_{}_256", getuid());
+ let wrapping_key_alias = format!("ks_wrapping_key_test_import_1_{}_2048", getuid());
+
+ let wrapping_key_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .digest(Digest::SHA_2_256)
+ .purpose(KeyPurpose::ENCRYPT)
+ .purpose(KeyPurpose::DECRYPT)
+ .purpose(KeyPurpose::WRAP_KEY)
+ .padding_mode(PaddingMode::RSA_OAEP)
+ .key_size(2048)
+ .rsa_public_exponent(65537)
+ .cert_not_before(0)
+ .cert_not_after(253402300799000);
+
+ let key_metadata = key_generations::import_wrapping_key_and_wrapped_key(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias),
+ Some(wrapping_key_alias),
+ wrapping_key_params,
+ )
+ .expect("Failed to import wrapped key.");
+
+ // Try to perform operations using wrapped key.
+ perform_sym_key_encrypt_decrypt_op(&sec_level, &key_metadata);
+}
+
+/// Import wrapping-key without specifying KeyPurpose::WRAP_KEY in import key parameters. Try to
+/// use this as wrapping-key for importing wrapped-key. Test should fail with an error code
+/// `INCOMPATIBLE_PURPOSE` to import wrapped-key using a wrapping-key which doesn't possess
+/// `WRAP_KEY` purpose.
+#[test]
+fn keystore2_import_wrapped_key_fails_with_wrong_purpose() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let wrapping_key_alias = format!("ks_wrapping_key_test_import_2_{}_2048", getuid());
+ let alias = format!("ks_wrapped_key_test_import_2_{}_256", getuid());
+
+ // In this KeyPurpose::WRAP_KEY is missing.
+ let wrapping_key_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .digest(Digest::SHA_2_256)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .padding_mode(PaddingMode::RSA_OAEP)
+ .key_size(2048)
+ .rsa_public_exponent(65537)
+ .cert_not_before(0)
+ .cert_not_after(253402300799000);
+
+ let result =
+ key_generations::map_ks_error(key_generations::import_wrapping_key_and_wrapped_key(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias),
+ Some(wrapping_key_alias),
+ wrapping_key_params,
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+}
+
+/// Try to import wrapped key whose wrapping key is missing in Android Keystore.
+/// Test should fail to import wrapped key with `ResponseCode::KEY_NOT_FOUND`.
+#[test]
+fn keystore2_import_wrapped_key_fails_with_missing_wrapping_key() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let unwrap_params = authorizations::AuthSetBuilder::new()
+ .digest(Digest::SHA_2_256)
+ .padding_mode(PaddingMode::RSA_OAEP);
+
+ let authenticator_spec: &[AuthenticatorSpec] = &[AuthenticatorSpec {
+ authenticatorType: HardwareAuthenticatorType::NONE,
+ authenticatorId: 0,
+ }];
+
+ let alias = format!("ks_wrapped_key_test_import_3_{}_256", getuid());
+
+ // Wrapping key with this alias doesn't exist.
+ let wrapping_key_alias = format!("ks_wrapping_key_not_exist_{}_2048", getuid());
+
+ let result = key_generations::map_ks_error(sec_level.importWrappedKey(
+ &KeyDescriptor {
+ domain: Domain::APP,
+ nspace: -1,
+ alias: Some(alias),
+ blob: Some(key_generations::WRAPPED_KEY.to_vec()),
+ },
+ &KeyDescriptor {
+ domain: Domain::APP,
+ nspace: -1,
+ alias: Some(wrapping_key_alias),
+ blob: None,
+ },
+ None,
+ &unwrap_params,
+ authenticator_spec,
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index 758e88b..59819df 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -15,7 +15,11 @@
use nix::unistd::{Gid, Uid};
use serde::{Deserialize, Serialize};
+use openssl::encrypt::Encrypter;
+use openssl::error::ErrorStack;
use openssl::hash::MessageDigest;
+use openssl::pkey::PKey;
+use openssl::pkey::Public;
use openssl::rsa::Padding;
use openssl::sign::Verifier;
use openssl::x509::X509;
@@ -348,3 +352,45 @@
blob: None,
})
}
+
+/// Encrypt the secure key with given transport key.
+pub fn encrypt_secure_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ secure_key: &[u8],
+ aad: &[u8],
+ nonce: Vec<u8>,
+ mac_len: i32,
+ key: &KeyDescriptor,
+) -> binder::Result<Option<Vec<u8>>> {
+ let op_params = authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::ENCRYPT)
+ .padding_mode(PaddingMode::NONE)
+ .block_mode(BlockMode::GCM)
+ .nonce(nonce)
+ .mac_length(mac_len);
+
+ let op_response = sec_level.createOperation(key, &op_params, false)?;
+
+ let op = op_response.iOperation.unwrap();
+ op.updateAad(aad)?;
+ op.finish(Some(secure_key), None)
+}
+
+/// Encrypt the transport key with given RSA wrapping key.
+pub fn encrypt_transport_key(
+ transport_key: &[u8],
+ pkey: &PKey<Public>,
+) -> Result<Vec<u8>, ErrorStack> {
+ let mut encrypter = Encrypter::new(pkey).unwrap();
+ encrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap();
+ encrypter.set_rsa_oaep_md(MessageDigest::sha256()).unwrap();
+ encrypter.set_rsa_mgf1_md(MessageDigest::sha1()).unwrap();
+
+ let input = transport_key.to_vec();
+ let buffer_len = encrypter.encrypt_len(&input).unwrap();
+ let mut encoded = vec![0u8; buffer_len];
+ let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap();
+ let encoded = &encoded[..encoded_len];
+
+ Ok(encoded.to_vec())
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index 41e3e36..d705aa4 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+pub mod ffi_test_utils;
pub mod keystore2_client_3des_key_tests;
pub mod keystore2_client_aes_key_tests;
pub mod keystore2_client_attest_key_tests;