1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
16 Digest::Digest, EcCurve::EcCurve, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose,
17 };
18 use android_system_keystore2::aidl::android::system::keystore2::{
19 Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
20 KeyMetadata::KeyMetadata,
21 };
22 use keystore2_test_utils::{authorizations, key_generations, key_generations::Error, SecLevel};
23 use nix::unistd::getuid;
24 use openssl::ec::{EcGroup, EcKey};
25 use openssl::error::ErrorStack;
26 use openssl::nid::Nid;
27 use openssl::pkey::{PKey, PKeyRef, Private, Public};
28 use openssl::pkey_ctx::PkeyCtx;
29 use openssl::x509::X509;
30
31 /// This macro is used to verify that the key agreement works for the given curve.
32 macro_rules! test_ec_key_agree {
33 ( $test_name:ident, $ec_curve:expr ) => {
34 #[test]
35 fn $test_name() {
36 perform_ec_key_agreement($ec_curve);
37 }
38 };
39 }
40
41 // Get the KeyMint key's public part.
get_keymint_public_key(keymint_key: &KeyMetadata) -> Result<PKey<Public>, ErrorStack>42 fn get_keymint_public_key(keymint_key: &KeyMetadata) -> Result<PKey<Public>, ErrorStack> {
43 let cert_bytes = keymint_key.certificate.as_ref().unwrap();
44 let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
45 cert.public_key()
46 }
47
48 // Perform local ECDH between the two keys and check the derived secrets are the same.
check_agreement( sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>, keymint_key: &KeyDescriptor, keymint_pub_key: &PKey<Public>, local_key: &PKeyRef<Private>, local_pub_key: &[u8], )49 fn check_agreement(
50 sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
51 keymint_key: &KeyDescriptor,
52 keymint_pub_key: &PKey<Public>,
53 local_key: &PKeyRef<Private>,
54 local_pub_key: &[u8],
55 ) {
56 let authorizations = authorizations::AuthSetBuilder::new().purpose(KeyPurpose::AGREE_KEY);
57 let key_agree_op = sec_level.createOperation(keymint_key, &authorizations, false).unwrap();
58 assert!(key_agree_op.iOperation.is_some());
59
60 let op = key_agree_op.iOperation.unwrap();
61 let secret = op.finish(Some(local_pub_key), None).unwrap();
62 assert!(secret.is_some());
63
64 let mut ctx = PkeyCtx::new(local_key).unwrap();
65 ctx.derive_init().unwrap();
66 ctx.derive_set_peer(keymint_pub_key).unwrap();
67 let mut peer_secret = vec![];
68 ctx.derive_to_vec(&mut peer_secret).unwrap();
69
70 assert_eq!(secret.unwrap(), peer_secret);
71 }
72
ec_curve_to_openrssl_curve_name(ec_curve: &EcCurve) -> Nid73 fn ec_curve_to_openrssl_curve_name(ec_curve: &EcCurve) -> Nid {
74 match *ec_curve {
75 EcCurve::P_224 => Nid::SECP224R1,
76 EcCurve::P_256 => Nid::X9_62_PRIME256V1,
77 EcCurve::P_384 => Nid::SECP384R1,
78 EcCurve::P_521 => Nid::SECP521R1,
79 _ => Nid::UNDEF,
80 }
81 }
82
83 /// Generate two EC keys with given curve from KeyMint and OpeanSSL. Perform local ECDH between
84 /// them and verify that the derived secrets are the same.
perform_ec_key_agreement(ec_curve: EcCurve)85 fn perform_ec_key_agreement(ec_curve: EcCurve) {
86 let sl = SecLevel::tee();
87 let openssl_ec_curve = ec_curve_to_openrssl_curve_name(&ec_curve);
88
89 let alias = format!("ks_ec_test_key_agree_{}", getuid());
90 let keymint_key = key_generations::generate_ec_agree_key(
91 &sl,
92 ec_curve,
93 Digest::SHA_2_256,
94 Domain::APP,
95 -1,
96 Some(alias),
97 )
98 .unwrap();
99
100 let keymint_pub_key = get_keymint_public_key(&keymint_key).unwrap();
101
102 let group = EcGroup::from_curve_name(openssl_ec_curve).unwrap();
103 let ec_key = EcKey::generate(&group).unwrap();
104 let local_key = PKey::from_ec_key(ec_key).unwrap();
105 let local_pub_key = local_key.public_key_to_der().unwrap();
106
107 check_agreement(&sl.binder, &keymint_key.key, &keymint_pub_key, &local_key, &local_pub_key);
108 }
109
110 test_ec_key_agree!(test_ec_p224_key_agreement, EcCurve::P_224);
111 test_ec_key_agree!(test_ec_p256_key_agreement, EcCurve::P_256);
112 test_ec_key_agree!(test_ec_p384_key_agreement, EcCurve::P_384);
113 test_ec_key_agree!(test_ec_p521_key_agreement, EcCurve::P_521);
114
115 /// Generate two EC keys with curve `CURVE_25519` from KeyMint and OpenSSL.
116 /// Perform local ECDH between them and verify that the derived secrets are the same.
117 #[test]
keystore2_ec_25519_agree_key_success()118 fn keystore2_ec_25519_agree_key_success() {
119 let sl = SecLevel::tee();
120
121 let alias = format!("ks_ec_25519_test_key_agree_{}", getuid());
122 let keymint_key = key_generations::generate_ec_agree_key(
123 &sl,
124 EcCurve::CURVE_25519,
125 Digest::NONE,
126 Domain::APP,
127 -1,
128 Some(alias),
129 )
130 .unwrap();
131
132 let keymint_pub_key = get_keymint_public_key(&keymint_key).unwrap();
133
134 let local_key = PKey::generate_x25519().unwrap();
135 let local_pub_key = local_key.public_key_to_der().unwrap();
136
137 check_agreement(&sl.binder, &keymint_key.key, &keymint_pub_key, &local_key, &local_pub_key);
138 }
139
140 /// Generate two EC keys with different curves and try to perform local ECDH. Since keys are using
141 /// different curves operation should fail with `ErrorCode:INVALID_ARGUMENT`.
142 #[test]
keystore2_ec_agree_key_with_different_curves_fail()143 fn keystore2_ec_agree_key_with_different_curves_fail() {
144 let sl = SecLevel::tee();
145
146 let alias = format!("ks_test_key_agree_fail{}", getuid());
147 let keymint_key = key_generations::generate_ec_agree_key(
148 &sl,
149 EcCurve::P_256,
150 Digest::SHA_2_256,
151 Domain::APP,
152 -1,
153 Some(alias),
154 )
155 .unwrap();
156
157 let local_key = PKey::generate_x25519().unwrap();
158 let local_pub_key = local_key.public_key_to_der().unwrap();
159
160 // If the keys are using different curves KeyMint should fail with
161 // ErrorCode:INVALID_ARGUMENT.
162 let authorizations = authorizations::AuthSetBuilder::new().purpose(KeyPurpose::AGREE_KEY);
163 let key_agree_op = sl.binder.createOperation(&keymint_key.key, &authorizations, false).unwrap();
164 assert!(key_agree_op.iOperation.is_some());
165
166 let op = key_agree_op.iOperation.unwrap();
167 let result = key_generations::map_ks_error(op.finish(Some(&local_pub_key), None));
168 assert!(result.is_err());
169 assert_eq!(Error::Km(ErrorCode::INVALID_ARGUMENT), result.unwrap_err());
170 }
171