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_ec_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_ec_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
132 .as_const()
133 .marshal_rfc5208_private_key(Version::V1)?,
134 ))
135 }
136
137 pub fn from_private_key_and_public_key(
157 alg: &'static EcdsaSigningAlgorithm,
158 private_key: &[u8],
159 public_key: &[u8],
160 ) -> Result<Self, KeyRejected> {
161 let priv_evp_pkey = parse_sec1_private_bn(private_key, alg.id.nid())?;
162 let pub_evp_pkey = parse_sec1_public_point(public_key, alg.id.nid())?;
163 if !priv_evp_pkey.eq(&pub_evp_pkey) {
165 return Err(KeyRejected::inconsistent_components());
166 }
167
168 let key_pair = Self::new(alg, priv_evp_pkey)?;
169 Ok(key_pair)
170 }
171
172 pub fn from_private_key_der(
185 alg: &'static EcdsaSigningAlgorithm,
186 private_key: &[u8],
187 ) -> Result<Self, KeyRejected> {
188 let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(private_key, EVP_PKEY_EC)
189 .or(parse_rfc5915_private_key(private_key, alg.id.nid()))?;
190 #[cfg(not(feature = "fips"))]
191 verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?;
192 #[cfg(feature = "fips")]
193 validate_ec_evp_key(&evp_pkey.as_const(), alg.id.nid())?;
194
195 Ok(Self::new(alg, evp_pkey)?)
196 }
197
198 #[must_use]
200 pub fn private_key(&self) -> PrivateKey<'_> {
201 PrivateKey(self)
202 }
203
204 #[must_use]
206 pub fn algorithm(&self) -> &'static EcdsaSigningAlgorithm {
207 self.algorithm
208 }
209
210 #[inline]
223 pub fn sign(&self, _rng: &dyn SecureRandom, message: &[u8]) -> Result<Signature, Unspecified> {
224 let out_sig = self.evp_pkey.sign(
225 message,
226 Some(self.algorithm.digest),
227 No_EVP_PKEY_CTX_consumer,
228 )?;
229
230 Ok(match self.algorithm.sig_format {
231 EcdsaSignatureFormat::ASN1 => Signature::new(|slice| {
232 slice[..out_sig.len()].copy_from_slice(&out_sig);
233 out_sig.len()
234 }),
235 EcdsaSignatureFormat::Fixed => ec::ecdsa_asn1_to_fixed(self.algorithm.id, &out_sig)?,
236 })
237 }
238}
239
240pub struct PrivateKey<'a>(&'a EcdsaKeyPair);
242
243impl Debug for PrivateKey<'_> {
244 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
245 f.write_str(&format!("EcdsaPrivateKey({:?})", self.0.algorithm.id))
246 }
247}
248
249impl AsBigEndian<EcPrivateKeyBin<'static>> for PrivateKey<'_> {
250 fn as_be_bytes(&self) -> Result<EcPrivateKeyBin<'static>, Unspecified> {
257 let buffer = marshal_sec1_private_key(&self.0.evp_pkey)?;
258 Ok(EcPrivateKeyBin::new(buffer))
259 }
260}
261
262impl AsDer<EcPrivateKeyRfc5915Der<'static>> for PrivateKey<'_> {
263 fn as_der(&self) -> Result<EcPrivateKeyRfc5915Der<'static>, Unspecified> {
268 let bytes = marshal_rfc5915_private_key(&self.0.evp_pkey)?;
269 Ok(EcPrivateKeyRfc5915Der::new(bytes))
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use crate::encoding::AsDer;
276 use crate::signature::{
277 EcdsaKeyPair, ECDSA_P256K1_SHA256_ASN1_SIGNING, ECDSA_P256_SHA256_FIXED_SIGNING,
278 ECDSA_P384_SHA3_384_FIXED_SIGNING, ECDSA_P521_SHA512_FIXED_SIGNING,
279 };
280
281 #[test]
282 fn test_reject_wrong_curve() {
283 let supported_algs = [
284 &ECDSA_P256_SHA256_FIXED_SIGNING,
285 &ECDSA_P384_SHA3_384_FIXED_SIGNING,
286 &ECDSA_P521_SHA512_FIXED_SIGNING,
287 &ECDSA_P256K1_SHA256_ASN1_SIGNING,
288 ];
289
290 for marshal_alg in supported_algs {
291 let key_pair = EcdsaKeyPair::generate(marshal_alg).unwrap();
292 let key_pair_doc = key_pair.to_pkcs8v1().unwrap();
293 let key_pair_bytes = key_pair_doc.as_ref();
294
295 for parse_alg in supported_algs {
296 if parse_alg == marshal_alg {
297 continue;
298 }
299
300 let result = EcdsaKeyPair::from_private_key_der(parse_alg, key_pair_bytes);
301 assert!(result.is_err());
302 }
303 }
304 }
305
306 #[test]
307 fn test_from_private_key_der() {
308 let key_pair = EcdsaKeyPair::generate(&ECDSA_P256_SHA256_FIXED_SIGNING).unwrap();
309
310 let bytes_5208 = key_pair.to_pkcs8v1().unwrap();
311 let bytes_5915 = key_pair.private_key().as_der().unwrap();
312
313 let key_pair_5208 = EcdsaKeyPair::from_private_key_der(
314 &ECDSA_P256_SHA256_FIXED_SIGNING,
315 bytes_5208.as_ref(),
316 )
317 .unwrap();
318 let key_pair_5915 = EcdsaKeyPair::from_private_key_der(
319 &ECDSA_P256_SHA256_FIXED_SIGNING,
320 bytes_5915.as_ref(),
321 )
322 .unwrap();
323
324 assert_eq!(key_pair.evp_pkey, key_pair_5208.evp_pkey);
325 assert_eq!(key_pair.evp_pkey, key_pair_5915.evp_pkey);
326 assert_eq!(key_pair_5208.evp_pkey, key_pair_5915.evp_pkey);
327 assert_eq!(key_pair_5915.algorithm, &ECDSA_P256_SHA256_FIXED_SIGNING);
328 }
329}