1#[cfg(feature = "fips")]
7use crate::aws_lc::EC_KEY_check_fips;
8#[cfg(not(feature = "fips"))]
9use crate::aws_lc::EC_KEY_check_key;
10use crate::aws_lc::{
11 ECDSA_SIG_from_bytes, ECDSA_SIG_get0_r, ECDSA_SIG_get0_s, EC_GROUP_get_curve_name,
12 EC_KEY_get0_group, EC_group_p224, EC_group_p256, EC_group_p384, EC_group_p521,
13 EC_group_secp256k1, EVP_PKEY_CTX_set_ec_paramgen_curve_nid, EVP_PKEY_get0_EC_KEY,
14 NID_X9_62_prime256v1, NID_secp224r1, NID_secp256k1, NID_secp384r1, NID_secp521r1, EC_GROUP,
15 EC_KEY, EVP_PKEY, EVP_PKEY_EC,
16};
17use crate::ec::signature::AlgorithmID;
18use crate::error::{KeyRejected, Unspecified};
19#[cfg(feature = "fips")]
20use crate::fips::indicator_check;
21use crate::ptr::{ConstPointer, LcPtr};
22use crate::signature::Signature;
23use std::os::raw::c_int;
26use std::ptr::null;
27
28pub(crate) mod encoding;
29pub(crate) mod key_pair;
30pub(crate) mod signature;
31
32const ELEM_MAX_BITS: usize = 521;
33pub(crate) const ELEM_MAX_BYTES: usize = (ELEM_MAX_BITS + 7) / 8;
34
35pub(crate) const PUBLIC_KEY_MAX_LEN: usize = 1 + (2 * ELEM_MAX_BYTES);
37
38fn verify_ec_key_nid(
39 ec_key: &ConstPointer<EC_KEY>,
40 expected_curve_nid: i32,
41) -> Result<(), KeyRejected> {
42 let ec_group =
43 ec_key.project_const_lifetime(unsafe { |ec_key| EC_KEY_get0_group(**ec_key) })?;
44 let key_nid = unsafe { EC_GROUP_get_curve_name(*ec_group) };
45
46 if key_nid != expected_curve_nid {
47 return Err(KeyRejected::wrong_algorithm());
48 }
49 Ok(())
50}
51
52#[inline]
53#[cfg(not(feature = "fips"))]
54pub(crate) fn verify_evp_key_nid(
55 evp_pkey: &ConstPointer<EVP_PKEY>,
56 expected_curve_nid: i32,
57) -> Result<(), KeyRejected> {
58 let ec_key =
59 evp_pkey.project_const_lifetime(unsafe { |evp_pkey| EVP_PKEY_get0_EC_KEY(**evp_pkey) })?;
60 verify_ec_key_nid(&ec_key, expected_curve_nid)?;
61
62 Ok(())
63}
64
65#[inline]
66pub(crate) fn validate_ec_evp_key(
67 evp_pkey: &ConstPointer<EVP_PKEY>,
68 expected_curve_nid: i32,
69) -> Result<(), KeyRejected> {
70 let ec_key =
71 evp_pkey.project_const_lifetime(unsafe { |evp_pkey| EVP_PKEY_get0_EC_KEY(**evp_pkey) })?;
72 verify_ec_key_nid(&ec_key, expected_curve_nid)?;
73
74 #[cfg(not(feature = "fips"))]
75 if 1 != unsafe { EC_KEY_check_key(*ec_key) } {
76 return Err(KeyRejected::inconsistent_components());
77 }
78
79 #[cfg(feature = "fips")]
80 if 1 != indicator_check!(unsafe { EC_KEY_check_fips(*ec_key) }) {
81 return Err(KeyRejected::inconsistent_components());
82 }
83
84 Ok(())
85}
86
87#[inline]
88pub(crate) fn evp_key_generate(nid: c_int) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
89 let params_fn = |ctx| {
90 if 1 == unsafe { EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) } {
91 Ok(())
92 } else {
93 Err(())
94 }
95 };
96 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_EC, Some(params_fn))
97}
98
99#[inline]
100#[allow(non_upper_case_globals)]
101pub(crate) fn ec_group_from_nid(nid: i32) -> Result<ConstPointer<'static, EC_GROUP>, Unspecified> {
102 Ok(unsafe {
103 ConstPointer::new_static(match nid {
104 NID_secp224r1 => EC_group_p224(),
105 NID_X9_62_prime256v1 => EC_group_p256(),
106 NID_secp384r1 => EC_group_p384(),
107 NID_secp521r1 => EC_group_p521(),
108 NID_secp256k1 => EC_group_secp256k1(),
109 _ => {
110 null()
112 }
113 })?
114 })
115}
116
117#[inline]
118fn ecdsa_asn1_to_fixed(alg_id: &'static AlgorithmID, sig: &[u8]) -> Result<Signature, Unspecified> {
119 let expected_number_size = alg_id.private_key_size();
120
121 let ecdsa_sig = LcPtr::new(unsafe { ECDSA_SIG_from_bytes(sig.as_ptr(), sig.len()) })?;
122
123 let r_bn = ecdsa_sig
124 .project_const_lifetime(unsafe { |ecdsa_sig| ECDSA_SIG_get0_r(*ecdsa_sig.as_const()) })?;
125 let r_buffer = r_bn.to_be_bytes();
126
127 let s_bn = ecdsa_sig
128 .project_const_lifetime(unsafe { |ecdsa_sig| ECDSA_SIG_get0_s(*ecdsa_sig.as_const()) })?;
129 let s_buffer = s_bn.to_be_bytes();
130
131 Ok(Signature::new(|slice| {
132 let (r_start, r_end) = (expected_number_size - r_buffer.len(), expected_number_size);
133 let (s_start, s_end) = (
134 2 * expected_number_size - s_buffer.len(),
135 2 * expected_number_size,
136 );
137
138 slice[r_start..r_end].copy_from_slice(r_buffer.as_slice());
139 slice[s_start..s_end].copy_from_slice(s_buffer.as_slice());
140 2 * expected_number_size
141 }))
142}
143
144#[inline]
145pub(crate) const fn compressed_public_key_size_bytes(curve_field_bits: usize) -> usize {
146 1 + (curve_field_bits + 7) / 8
147}
148
149#[inline]
150pub(crate) const fn uncompressed_public_key_size_bytes(curve_field_bits: usize) -> usize {
151 1 + 2 * ((curve_field_bits + 7) / 8)
152}
153
154#[cfg(test)]
155mod tests {
156 use crate::encoding::{
157 AsBigEndian, AsDer, EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, PublicKeyX509Der,
158 };
159 use crate::signature::{
160 EcdsaKeyPair, KeyPair, UnparsedPublicKey, ECDSA_P256_SHA256_FIXED,
161 ECDSA_P256_SHA256_FIXED_SIGNING,
162 };
163 use crate::test::from_dirty_hex;
164 use crate::{signature, test};
165
166 #[test]
167 fn test_from_pkcs8() {
168 let input = from_dirty_hex(
169 r"308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420090460075f15d
170 2a256248000fb02d83ad77593dde4ae59fc5e96142dffb2bd07a14403420004cf0d13a3a7577231ea1b66cf4
171 021cd54f21f4ac4f5f2fdd28e05bc7d2bd099d1374cd08d2ef654d6f04498db462f73e0282058dd661a4c9b0
172 437af3f7af6e724",
173 );
174
175 let result = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, &input);
176 assert!(result.is_ok());
177 let key_pair = result.unwrap();
178 assert_eq!("EcdsaKeyPair { public_key: EcdsaPublicKey(\"04cf0d13a3a7577231ea1b66cf4021cd54f21f4ac4f5f2fdd28e05bc7d2bd099d1374cd08d2ef654d6f04498db462f73e0282058dd661a4c9b0437af3f7af6e724\") }",
179 format!("{key_pair:?}"));
180 assert_eq!(
181 "EcdsaPrivateKey(ECDSA_P256)",
182 format!("{:?}", key_pair.private_key())
183 );
184 let pub_key = key_pair.public_key();
185 let der_pub_key: PublicKeyX509Der = pub_key.as_der().unwrap();
186
187 assert_eq!(
188 from_dirty_hex(
189 r"3059301306072a8648ce3d020106082a8648ce3d03010703420004cf0d13a3a7577231ea1b66cf402
190 1cd54f21f4ac4f5f2fdd28e05bc7d2bd099d1374cd08d2ef654d6f04498db462f73e0282058dd661a4c9
191 b0437af3f7af6e724",
192 )
193 .as_slice(),
194 der_pub_key.as_ref()
195 );
196 }
197
198 #[test]
199 fn test_ecdsa_asn1_verify() {
200 let alg = &signature::ECDSA_P256_SHA256_ASN1;
210 let msg = "";
211 let public_key = from_dirty_hex(
212 r"0430345fd47ea21a11129be651b0884bfac698377611acc9f689458e1
213 3b9ed7d4b9d7599a68dcf125e7f31055ccb374cd04f6d6fd2b217438a63f6f667d50ef2f0",
214 );
215 let sig = from_dirty_hex(
216 r"30440220341f6779b75e98bb42e01095dd48356cbf9002dc704ac8bd2a8240b8
217 8d3796c60220555843b1b4e264fe6ffe6e2b705a376c05c09404303ffe5d2711f3e3b3a010a1",
218 );
219 let unparsed_pub_key = signature::UnparsedPublicKey::new(alg, &public_key);
220
221 let actual_result = unparsed_pub_key.verify(msg.as_bytes(), &sig);
222 assert!(actual_result.is_ok(), "Key: {}", test::to_hex(public_key));
223 }
224
225 #[test]
226 fn public_key_formats() {
227 const MESSAGE: &[u8] = b"message to be signed";
228
229 let key_pair = EcdsaKeyPair::generate(&ECDSA_P256_SHA256_FIXED_SIGNING).unwrap();
230 let public_key = key_pair.public_key();
231 let as_ref_bytes = public_key.as_ref();
232 let compressed = AsBigEndian::<EcPublicKeyCompressedBin>::as_be_bytes(public_key).unwrap();
233 let uncompressed =
234 AsBigEndian::<EcPublicKeyUncompressedBin>::as_be_bytes(public_key).unwrap();
235 let pub_x509 = AsDer::<PublicKeyX509Der>::as_der(public_key).unwrap();
236 assert_eq!(as_ref_bytes, uncompressed.as_ref());
237 assert_ne!(compressed.as_ref()[0], 0x04);
238
239 let rng = crate::rand::SystemRandom::new();
240
241 let signature = key_pair.sign(&rng, MESSAGE).unwrap();
242
243 for pub_key_bytes in [
244 as_ref_bytes,
245 compressed.as_ref(),
246 uncompressed.as_ref(),
247 pub_x509.as_ref(),
248 ] {
249 UnparsedPublicKey::new(&ECDSA_P256_SHA256_FIXED, pub_key_bytes)
250 .verify(MESSAGE, signature.as_ref())
251 .unwrap();
252 }
253 }
254}