1use crate::aws_lc::{EVP_PKEY, EVP_PKEY_EC};
7use core::fmt;
8use core::fmt::{Debug, Formatter};
9
10use crate::ec::evp_key_generate;
11use crate::ec::signature::{EcdsaSignatureFormat, EcdsaSigningAlgorithm, PublicKey};
12#[cfg(feature = "fips")]
13use crate::ec::validate_evp_key;
14#[cfg(not(feature = "fips"))]
15use crate::ec::verify_evp_key_nid;
16
17use crate::ec;
18use crate::ec::encoding::rfc5915::{marshal_rfc5915_private_key, parse_rfc5915_private_key};
19use crate::ec::encoding::sec1::{
20 marshal_sec1_private_key, parse_sec1_private_bn, parse_sec1_public_point,
21};
22use crate::encoding::{AsBigEndian, AsDer, EcPrivateKeyBin, EcPrivateKeyRfc5915Der};
23use crate::error::{KeyRejected, Unspecified};
24use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
25use crate::pkcs8::{Document, Version};
26use crate::ptr::LcPtr;
27use crate::rand::SecureRandom;
28use crate::signature::{KeyPair, Signature};
29
30#[allow(clippy::module_name_repetitions)]
32pub struct EcdsaKeyPair {
33 algorithm: &'static EcdsaSigningAlgorithm,
34 evp_pkey: LcPtr<EVP_PKEY>,
35 pubkey: PublicKey,
36}
37
38impl Debug for EcdsaKeyPair {
39 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
40 f.write_str(&format!("EcdsaKeyPair {{ public_key: {:?} }}", self.pubkey))
41 }
42}
43
44unsafe impl Send for EcdsaKeyPair {}
45
46unsafe impl Sync for EcdsaKeyPair {}
47
48impl KeyPair for EcdsaKeyPair {
49 type PublicKey = PublicKey;
50
51 #[inline]
52 fn public_key(&self) -> &Self::PublicKey {
54 &self.pubkey
55 }
56}
57
58impl EcdsaKeyPair {
59 #[allow(clippy::needless_pass_by_value)]
60 fn new(
61 algorithm: &'static EcdsaSigningAlgorithm,
62 evp_pkey: LcPtr<EVP_PKEY>,
63 ) -> Result<Self, ()> {
64 let pubkey = ec::signature::public_key_from_evp_pkey(&evp_pkey, algorithm)?;
65
66 Ok(Self {
67 algorithm,
68 evp_pkey,
69 pubkey,
70 })
71 }
72
73 pub fn generate(alg: &'static EcdsaSigningAlgorithm) -> Result<Self, Unspecified> {
79 let evp_pkey = evp_key_generate(alg.0.id.nid())?;
80
81 Ok(Self::new(alg, evp_pkey)?)
82 }
83
84 pub fn from_pkcs8(
91 alg: &'static EcdsaSigningAlgorithm,
92 pkcs8: &[u8],
93 ) -> Result<Self, KeyRejected> {
94 let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_EC)?;
96
97 #[cfg(not(feature = "fips"))]
98 verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?;
99 #[cfg(feature = "fips")]
100 validate_evp_key(&evp_pkey.as_const(), alg.id.nid())?;
101
102 let key_pair = Self::new(alg, evp_pkey)?;
103
104 Ok(key_pair)
105 }
106
107 pub fn generate_pkcs8(
116 alg: &'static EcdsaSigningAlgorithm,
117 _rng: &dyn SecureRandom,
118 ) -> Result<Document, Unspecified> {
119 let key_pair = Self::generate(alg)?;
120
121 key_pair.to_pkcs8v1()
122 }
123
124 pub fn to_pkcs8v1(&self) -> Result<Document, Unspecified> {
130 Ok(Document::new(
131 self.evp_pkey.marshal_rfc5208_private_key(Version::V1)?,
132 ))
133 }
134
135 pub fn from_private_key_and_public_key(
155 alg: &'static EcdsaSigningAlgorithm,
156 private_key: &[u8],
157 public_key: &[u8],
158 ) -> Result<Self, KeyRejected> {
159 let priv_evp_pkey = parse_sec1_private_bn(private_key, alg.id.nid())?;
160 let pub_evp_pkey = parse_sec1_public_point(public_key, alg.id.nid())?;
161 if !priv_evp_pkey.eq(&pub_evp_pkey) {
163 return Err(KeyRejected::inconsistent_components());
164 }
165
166 let key_pair = Self::new(alg, priv_evp_pkey)?;
167 Ok(key_pair)
168 }
169
170 pub fn from_private_key_der(
183 alg: &'static EcdsaSigningAlgorithm,
184 private_key: &[u8],
185 ) -> Result<Self, KeyRejected> {
186 let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(private_key, EVP_PKEY_EC)
187 .or(parse_rfc5915_private_key(private_key, alg.id.nid()))?;
188 #[cfg(not(feature = "fips"))]
189 verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?;
190 #[cfg(feature = "fips")]
191 validate_evp_key(&evp_pkey.as_const(), alg.id.nid())?;
192
193 Ok(Self::new(alg, evp_pkey)?)
194 }
195
196 #[must_use]
198 pub fn private_key(&self) -> PrivateKey<'_> {
199 PrivateKey(self)
200 }
201
202 #[inline]
215 pub fn sign(&self, _rng: &dyn SecureRandom, message: &[u8]) -> Result<Signature, Unspecified> {
216 let out_sig = self.evp_pkey.sign(
217 message,
218 Some(self.algorithm.digest),
219 No_EVP_PKEY_CTX_consumer,
220 )?;
221
222 Ok(match self.algorithm.sig_format {
223 EcdsaSignatureFormat::ASN1 => Signature::new(|slice| {
224 slice[..out_sig.len()].copy_from_slice(&out_sig);
225 out_sig.len()
226 }),
227 EcdsaSignatureFormat::Fixed => ec::ecdsa_asn1_to_fixed(self.algorithm.id, &out_sig)?,
228 })
229 }
230}
231
232pub struct PrivateKey<'a>(&'a EcdsaKeyPair);
234
235impl Debug for PrivateKey<'_> {
236 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
237 f.write_str(&format!("EcdsaPrivateKey({:?})", self.0.algorithm.id))
238 }
239}
240
241impl AsBigEndian<EcPrivateKeyBin<'static>> for PrivateKey<'_> {
242 fn as_be_bytes(&self) -> Result<EcPrivateKeyBin<'static>, Unspecified> {
249 let buffer = marshal_sec1_private_key(&self.0.evp_pkey)?;
250 Ok(EcPrivateKeyBin::new(buffer))
251 }
252}
253
254impl AsDer<EcPrivateKeyRfc5915Der<'static>> for PrivateKey<'_> {
255 fn as_der(&self) -> Result<EcPrivateKeyRfc5915Der<'static>, Unspecified> {
260 let bytes = marshal_rfc5915_private_key(&self.0.evp_pkey)?;
261 Ok(EcPrivateKeyRfc5915Der::new(bytes))
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use crate::encoding::AsDer;
268 use crate::signature::{
269 EcdsaKeyPair, ECDSA_P256K1_SHA256_ASN1_SIGNING, ECDSA_P256_SHA256_FIXED_SIGNING,
270 ECDSA_P384_SHA3_384_FIXED_SIGNING, ECDSA_P521_SHA512_FIXED_SIGNING,
271 };
272
273 #[test]
274 fn test_reject_wrong_curve() {
275 let supported_algs = [
276 &ECDSA_P256_SHA256_FIXED_SIGNING,
277 &ECDSA_P384_SHA3_384_FIXED_SIGNING,
278 &ECDSA_P521_SHA512_FIXED_SIGNING,
279 &ECDSA_P256K1_SHA256_ASN1_SIGNING,
280 ];
281
282 for marshal_alg in supported_algs {
283 let key_pair = EcdsaKeyPair::generate(marshal_alg).unwrap();
284 let key_pair_doc = key_pair.to_pkcs8v1().unwrap();
285 let key_pair_bytes = key_pair_doc.as_ref();
286
287 for parse_alg in supported_algs {
288 if parse_alg == marshal_alg {
289 continue;
290 }
291
292 let result = EcdsaKeyPair::from_private_key_der(parse_alg, key_pair_bytes);
293 assert!(result.is_err());
294 }
295 }
296 }
297
298 #[test]
299 fn test_from_private_key_der() {
300 let key_pair = EcdsaKeyPair::generate(&ECDSA_P256_SHA256_FIXED_SIGNING).unwrap();
301
302 let bytes_5208 = key_pair.to_pkcs8v1().unwrap();
303 let bytes_5915 = key_pair.private_key().as_der().unwrap();
304
305 let key_pair_5208 = EcdsaKeyPair::from_private_key_der(
306 &ECDSA_P256_SHA256_FIXED_SIGNING,
307 bytes_5208.as_ref(),
308 )
309 .unwrap();
310 let key_pair_5915 = EcdsaKeyPair::from_private_key_der(
311 &ECDSA_P256_SHA256_FIXED_SIGNING,
312 bytes_5915.as_ref(),
313 )
314 .unwrap();
315
316 assert_eq!(key_pair.evp_pkey, key_pair_5208.evp_pkey);
317 assert_eq!(key_pair.evp_pkey, key_pair_5915.evp_pkey);
318 assert_eq!(key_pair_5208.evp_pkey, key_pair_5915.evp_pkey);
319 }
320}