• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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