Merge "[dice] Move test hash_derive_sign_verify to open_dice/"
diff --git a/diced/OWNERS b/diced/OWNERS
new file mode 100644
index 0000000..387cd93
--- /dev/null
+++ b/diced/OWNERS
@@ -0,0 +1,3 @@
+alanstokes@google.com
+aliceywang@google.com
+ascull@google.com
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index f9aaabb..e4c4968 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -1047,3 +1047,38 @@
transport_key,
)
}
+
+/// Generate EC key with purpose AGREE_KEY.
+pub fn generate_ec_agree_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ ec_curve: EcCurve,
+ digest: Digest,
+ domain: Domain,
+ nspace: i64,
+ alias: Option<String>,
+) -> binder::Result<KeyMetadata> {
+ let gen_params = AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::AGREE_KEY)
+ .digest(digest)
+ .ec_curve(ec_curve);
+
+ match sec_level.generateKey(
+ &KeyDescriptor { domain, nspace, alias, blob: None },
+ None,
+ &gen_params,
+ 0,
+ b"entropy",
+ ) {
+ Ok(key_metadata) => {
+ assert!(key_metadata.certificate.is_some());
+ if domain == Domain::BLOB {
+ assert!(key_metadata.key.blob.is_some());
+ }
+
+ Ok(key_metadata)
+ }
+ Err(e) => Err(e),
+ }
+}
diff --git a/keystore2/tests/keystore2_client_key_agreement_tests.rs b/keystore2/tests/keystore2_client_key_agreement_tests.rs
new file mode 100644
index 0000000..6b2e3c2
--- /dev/null
+++ b/keystore2/tests/keystore2_client_key_agreement_tests.rs
@@ -0,0 +1,179 @@
+// 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 nix::unistd::getuid;
+
+use openssl::ec::{EcGroup, EcKey};
+use openssl::error::ErrorStack;
+use openssl::nid::Nid;
+use openssl::pkey::{PKey, PKeyRef, Private, Public};
+use openssl::pkey_ctx::PkeyCtx;
+use openssl::x509::X509;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ Digest::Digest, EcCurve::EcCurve, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose,
+ SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+ Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+ KeyMetadata::KeyMetadata,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error,
+};
+
+/// This macro is used to verify that the key agreement works for the given curve.
+macro_rules! test_ec_key_agree {
+ ( $test_name:ident, $ec_curve:expr ) => {
+ #[test]
+ fn $test_name() {
+ perform_ec_key_agreement($ec_curve);
+ }
+ };
+}
+
+// Get the KeyMint key's public part.
+fn get_keymint_public_key(keymint_key: &KeyMetadata) -> Result<PKey<Public>, ErrorStack> {
+ let cert_bytes = keymint_key.certificate.as_ref().unwrap();
+ let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
+ cert.public_key()
+}
+
+// Perform local ECDH between the two keys and check the derived secrets are the same.
+fn check_agreement(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ keymint_key: &KeyDescriptor,
+ keymint_pub_key: &PKey<Public>,
+ local_key: &PKeyRef<Private>,
+ local_pub_key: &[u8],
+) {
+ let authorizations = authorizations::AuthSetBuilder::new().purpose(KeyPurpose::AGREE_KEY);
+ let key_agree_op = sec_level.createOperation(keymint_key, &authorizations, false).unwrap();
+ assert!(key_agree_op.iOperation.is_some());
+
+ let op = key_agree_op.iOperation.unwrap();
+ let secret = op.finish(Some(local_pub_key), None).unwrap();
+ assert!(secret.is_some());
+
+ let mut ctx = PkeyCtx::new(local_key).unwrap();
+ ctx.derive_init().unwrap();
+ ctx.derive_set_peer(keymint_pub_key).unwrap();
+ let mut peer_secret = vec![];
+ ctx.derive_to_vec(&mut peer_secret).unwrap();
+
+ assert_eq!(secret.unwrap(), peer_secret);
+}
+
+fn ec_curve_to_openrssl_curve_name(ec_curve: &EcCurve) -> Nid {
+ match *ec_curve {
+ EcCurve::P_224 => Nid::SECP224R1,
+ EcCurve::P_256 => Nid::X9_62_PRIME256V1,
+ EcCurve::P_384 => Nid::SECP384R1,
+ EcCurve::P_521 => Nid::SECP521R1,
+ _ => Nid::UNDEF,
+ }
+}
+
+/// Generate two EC keys with given curve from KeyMint and OpeanSSL. Perform local ECDH between
+/// them and verify that the derived secrets are the same.
+fn perform_ec_key_agreement(ec_curve: EcCurve) {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let openssl_ec_curve = ec_curve_to_openrssl_curve_name(&ec_curve);
+
+ let alias = format!("ks_ec_test_key_agree_{}", getuid());
+ let keymint_key = key_generations::generate_ec_agree_key(
+ &sec_level,
+ ec_curve,
+ Digest::SHA_2_256,
+ Domain::APP,
+ -1,
+ Some(alias),
+ )
+ .unwrap();
+
+ let keymint_pub_key = get_keymint_public_key(&keymint_key).unwrap();
+
+ let group = EcGroup::from_curve_name(openssl_ec_curve).unwrap();
+ let ec_key = EcKey::generate(&group).unwrap();
+ let local_key = PKey::from_ec_key(ec_key).unwrap();
+ let local_pub_key = local_key.public_key_to_der().unwrap();
+
+ check_agreement(&sec_level, &keymint_key.key, &keymint_pub_key, &local_key, &local_pub_key);
+}
+
+test_ec_key_agree!(test_ec_p224_key_agreement, EcCurve::P_224);
+test_ec_key_agree!(test_ec_p256_key_agreement, EcCurve::P_256);
+test_ec_key_agree!(test_ec_p384_key_agreement, EcCurve::P_384);
+test_ec_key_agree!(test_ec_p521_key_agreement, EcCurve::P_521);
+
+/// Generate two EC keys with curve `CURVE_25519` from KeyMint and OpeanSSL.
+/// Perform local ECDH between them and verify that the derived secrets are the same.
+#[test]
+fn keystore2_ec_25519_agree_key_success() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = format!("ks_ec_25519_test_key_agree_{}", getuid());
+ let keymint_key = key_generations::generate_ec_agree_key(
+ &sec_level,
+ EcCurve::CURVE_25519,
+ Digest::NONE,
+ Domain::APP,
+ -1,
+ Some(alias),
+ )
+ .unwrap();
+
+ let keymint_pub_key = get_keymint_public_key(&keymint_key).unwrap();
+
+ let local_key = PKey::generate_x25519().unwrap();
+ let local_pub_key = local_key.public_key_to_der().unwrap();
+
+ check_agreement(&sec_level, &keymint_key.key, &keymint_pub_key, &local_key, &local_pub_key);
+}
+
+/// Generate two EC keys with different curves and try to perform local ECDH. Since keys are using
+/// different curves operation should fail with `ErrorCode:INVALID_ARGUMENT`.
+#[test]
+fn keystore2_ec_agree_key_with_different_curves_fail() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = format!("ks_test_key_agree_fail{}", getuid());
+ let keymint_key = key_generations::generate_ec_agree_key(
+ &sec_level,
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ Domain::APP,
+ -1,
+ Some(alias),
+ )
+ .unwrap();
+
+ let local_key = PKey::generate_x25519().unwrap();
+ let local_pub_key = local_key.public_key_to_der().unwrap();
+
+ // If the keys are using different curves KeyMint should fail with
+ // ErrorCode:INVALID_ARGUMENT.
+ let authorizations = authorizations::AuthSetBuilder::new().purpose(KeyPurpose::AGREE_KEY);
+ let key_agree_op = sec_level.createOperation(&keymint_key.key, &authorizations, false).unwrap();
+ assert!(key_agree_op.iOperation.is_some());
+
+ let op = key_agree_op.iOperation.unwrap();
+ let result = key_generations::map_ks_error(op.finish(Some(&local_pub_key), None));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INVALID_ARGUMENT), result.unwrap_err());
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index 45c5fb7..07a298a 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -21,6 +21,7 @@
pub mod keystore2_client_grant_key_tests;
pub mod keystore2_client_hmac_key_tests;
pub mod keystore2_client_import_keys_tests;
+pub mod keystore2_client_key_agreement_tests;
pub mod keystore2_client_key_id_domain_tests;
pub mod keystore2_client_list_entries_tests;
pub mod keystore2_client_operation_tests;