1use crate::aws_lc::{EVP_PKEY, EVP_PKEY_EC};
7use crate::digest::Digest;
8use crate::ec::evp_key_generate;
9use crate::ec::signature::{EcdsaSignatureFormat, EcdsaSigningAlgorithm, PublicKey};
10#[cfg(feature = "fips")]
11use crate::ec::validate_ec_evp_key;
12#[cfg(not(feature = "fips"))]
13use crate::ec::verify_evp_key_nid;
14use core::fmt;
15use core::fmt::{Debug, Formatter};
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#[derive(Clone)]
32#[allow(clippy::module_name_repetitions)]
33pub struct EcdsaKeyPair {
34 algorithm: &'static EcdsaSigningAlgorithm,
35 evp_pkey: LcPtr<EVP_PKEY>,
36 pubkey: PublicKey,
37}
38
39impl Debug for EcdsaKeyPair {
40 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
41 f.write_str(&format!("EcdsaKeyPair {{ public_key: {:?} }}", self.pubkey))
42 }
43}
44
45unsafe impl Send for EcdsaKeyPair {}
46
47unsafe impl Sync for EcdsaKeyPair {}
48
49impl KeyPair for EcdsaKeyPair {
50 type PublicKey = PublicKey;
51
52 #[inline]
53 fn public_key(&self) -> &Self::PublicKey {
55 &self.pubkey
56 }
57}
58
59impl EcdsaKeyPair {
60 #[allow(clippy::needless_pass_by_value)]
61 fn new(
62 algorithm: &'static EcdsaSigningAlgorithm,
63 evp_pkey: LcPtr<EVP_PKEY>,
64 ) -> Result<Self, ()> {
65 let pubkey = ec::signature::public_key_from_evp_pkey(&evp_pkey, algorithm)?;
66
67 Ok(Self {
68 algorithm,
69 evp_pkey,
70 pubkey,
71 })
72 }
73
74 pub fn generate(alg: &'static EcdsaSigningAlgorithm) -> Result<Self, Unspecified> {
80 let evp_pkey = evp_key_generate(alg.0.id.nid())?;
81
82 Ok(Self::new(alg, evp_pkey)?)
83 }
84
85 pub fn from_pkcs8(
92 alg: &'static EcdsaSigningAlgorithm,
93 pkcs8: &[u8],
94 ) -> Result<Self, KeyRejected> {
95 let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_EC)?;
97
98 #[cfg(not(feature = "fips"))]
99 verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?;
100 #[cfg(feature = "fips")]
101 validate_ec_evp_key(&evp_pkey.as_const(), alg.id.nid())?;
102
103 let key_pair = Self::new(alg, evp_pkey)?;
104
105 Ok(key_pair)
106 }
107
108 pub fn generate_pkcs8(
117 alg: &'static EcdsaSigningAlgorithm,
118 _rng: &dyn SecureRandom,
119 ) -> Result<Document, Unspecified> {
120 let key_pair = Self::generate(alg)?;
121
122 key_pair.to_pkcs8v1()
123 }
124
125 pub fn to_pkcs8v1(&self) -> Result<Document, Unspecified> {
131 Ok(Document::new(
132 self.evp_pkey
133 .as_const()
134 .marshal_rfc5208_private_key(Version::V1)?,
135 ))
136 }
137
138 pub fn from_private_key_and_public_key(
158 alg: &'static EcdsaSigningAlgorithm,
159 private_key: &[u8],
160 public_key: &[u8],
161 ) -> Result<Self, KeyRejected> {
162 let priv_evp_pkey = parse_sec1_private_bn(private_key, alg.id.nid())?;
163 let pub_evp_pkey = parse_sec1_public_point(public_key, alg.id.nid())?;
164 if !priv_evp_pkey.eq(&pub_evp_pkey) {
166 return Err(KeyRejected::inconsistent_components());
167 }
168
169 let key_pair = Self::new(alg, priv_evp_pkey)?;
170 Ok(key_pair)
171 }
172
173 pub fn from_private_key_der(
186 alg: &'static EcdsaSigningAlgorithm,
187 private_key: &[u8],
188 ) -> Result<Self, KeyRejected> {
189 let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(private_key, EVP_PKEY_EC)
190 .or(parse_rfc5915_private_key(private_key, alg.id.nid()))?;
191 #[cfg(not(feature = "fips"))]
192 verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?;
193 #[cfg(feature = "fips")]
194 validate_ec_evp_key(&evp_pkey.as_const(), alg.id.nid())?;
195
196 Ok(Self::new(alg, evp_pkey)?)
197 }
198
199 #[must_use]
201 pub fn private_key(&self) -> PrivateKey<'_> {
202 PrivateKey(self)
203 }
204
205 #[must_use]
207 pub fn algorithm(&self) -> &'static EcdsaSigningAlgorithm {
208 self.algorithm
209 }
210
211 #[inline]
224 pub fn sign(&self, _rng: &dyn SecureRandom, message: &[u8]) -> Result<Signature, Unspecified> {
225 let out_sig = self.evp_pkey.sign(
226 message,
227 Some(self.algorithm.digest),
228 No_EVP_PKEY_CTX_consumer,
229 )?;
230
231 Ok(match self.algorithm.sig_format {
232 EcdsaSignatureFormat::ASN1 => Signature::new(|slice| {
233 slice[..out_sig.len()].copy_from_slice(&out_sig);
234 out_sig.len()
235 }),
236 EcdsaSignatureFormat::Fixed => ec::ecdsa_asn1_to_fixed(self.algorithm.id, &out_sig)?,
237 })
238 }
239
240 #[inline]
248 pub fn sign_digest(&self, digest: &Digest) -> Result<Signature, Unspecified> {
249 let out_sig = self
250 .evp_pkey
251 .sign_digest(digest, No_EVP_PKEY_CTX_consumer)?;
252 if self.algorithm.digest != digest.algorithm() {
253 return Err(Unspecified);
254 }
255
256 Ok(match self.algorithm.sig_format {
257 EcdsaSignatureFormat::ASN1 => Signature::new(|slice| {
258 slice[..out_sig.len()].copy_from_slice(&out_sig);
259 out_sig.len()
260 }),
261 EcdsaSignatureFormat::Fixed => ec::ecdsa_asn1_to_fixed(self.algorithm.id, &out_sig)?,
262 })
263 }
264}
265
266pub struct PrivateKey<'a>(&'a EcdsaKeyPair);
268
269impl Debug for PrivateKey<'_> {
270 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
271 f.write_str(&format!("EcdsaPrivateKey({:?})", self.0.algorithm.id))
272 }
273}
274
275impl AsBigEndian<EcPrivateKeyBin<'static>> for PrivateKey<'_> {
276 fn as_be_bytes(&self) -> Result<EcPrivateKeyBin<'static>, Unspecified> {
283 let buffer = marshal_sec1_private_key(&self.0.evp_pkey)?;
284 Ok(EcPrivateKeyBin::new(buffer))
285 }
286}
287
288impl AsDer<EcPrivateKeyRfc5915Der<'static>> for PrivateKey<'_> {
289 fn as_der(&self) -> Result<EcPrivateKeyRfc5915Der<'static>, Unspecified> {
294 let bytes = marshal_rfc5915_private_key(&self.0.evp_pkey)?;
295 Ok(EcPrivateKeyRfc5915Der::new(bytes))
296 }
297}
298
299#[cfg(test)]
300mod tests {
301 use crate::encoding::AsDer;
302 use crate::signature::{
303 EcdsaKeyPair, ECDSA_P256K1_SHA256_ASN1_SIGNING, ECDSA_P256_SHA256_FIXED_SIGNING,
304 ECDSA_P384_SHA3_384_FIXED_SIGNING, ECDSA_P521_SHA512_FIXED_SIGNING,
305 };
306
307 #[test]
308 fn test_reject_wrong_curve() {
309 let supported_algs = [
310 &ECDSA_P256_SHA256_FIXED_SIGNING,
311 &ECDSA_P384_SHA3_384_FIXED_SIGNING,
312 &ECDSA_P521_SHA512_FIXED_SIGNING,
313 &ECDSA_P256K1_SHA256_ASN1_SIGNING,
314 ];
315
316 for marshal_alg in supported_algs {
317 let key_pair = EcdsaKeyPair::generate(marshal_alg).unwrap();
318 let key_pair_doc = key_pair.to_pkcs8v1().unwrap();
319 let key_pair_bytes = key_pair_doc.as_ref();
320
321 for parse_alg in supported_algs {
322 if parse_alg == marshal_alg {
323 continue;
324 }
325
326 let result = EcdsaKeyPair::from_private_key_der(parse_alg, key_pair_bytes);
327 assert!(result.is_err());
328 }
329 }
330 }
331
332 #[test]
333 fn test_from_private_key_der() {
334 let key_pair = EcdsaKeyPair::generate(&ECDSA_P256_SHA256_FIXED_SIGNING).unwrap();
335
336 let bytes_5208 = key_pair.to_pkcs8v1().unwrap();
337 let bytes_5915 = key_pair.private_key().as_der().unwrap();
338
339 let key_pair_5208 = EcdsaKeyPair::from_private_key_der(
340 &ECDSA_P256_SHA256_FIXED_SIGNING,
341 bytes_5208.as_ref(),
342 )
343 .unwrap();
344 let key_pair_5915 = EcdsaKeyPair::from_private_key_der(
345 &ECDSA_P256_SHA256_FIXED_SIGNING,
346 bytes_5915.as_ref(),
347 )
348 .unwrap();
349
350 assert_eq!(key_pair.evp_pkey, key_pair_5208.evp_pkey);
351 assert_eq!(key_pair.evp_pkey, key_pair_5915.evp_pkey);
352 assert_eq!(key_pair_5208.evp_pkey, key_pair_5915.evp_pkey);
353 assert_eq!(key_pair_5915.algorithm, &ECDSA_P256_SHA256_FIXED_SIGNING);
354 }
355}