Coverage Report

Created: 2026-04-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rcgen-0.14.7/src/key_pair.rs
Line
Count
Source
1
#[cfg(feature = "crypto")]
2
use std::fmt;
3
4
#[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
5
use aws_lc_rs::unstable::signature::PqdsaKeyPair;
6
#[cfg(feature = "pem")]
7
use pem::Pem;
8
#[cfg(feature = "crypto")]
9
use pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
10
use yasna::{DERWriter, DERWriterSeq};
11
12
#[cfg(any(feature = "crypto", feature = "pem"))]
13
use crate::error::ExternalError;
14
#[cfg(all(feature = "crypto", feature = "aws_lc_rs"))]
15
use crate::ring_like::ecdsa_from_private_key_der;
16
#[cfg(all(feature = "crypto", feature = "aws_lc_rs"))]
17
use crate::ring_like::rsa::KeySize;
18
#[cfg(feature = "crypto")]
19
use crate::ring_like::{
20
  error as ring_error,
21
  rand::SystemRandom,
22
  signature::{
23
    self, EcdsaKeyPair, Ed25519KeyPair, KeyPair as RingKeyPair, RsaEncoding, RsaKeyPair,
24
  },
25
  {ecdsa_from_pkcs8, rsa_key_pair_public_modulus_len},
26
};
27
use crate::sign_algo::SignatureAlgorithm;
28
#[cfg(feature = "crypto")]
29
use crate::sign_algo::{algo::*, SignAlgo};
30
use crate::Error;
31
#[cfg(feature = "pem")]
32
use crate::ENCODE_CONFIG;
33
34
/// A key pair variant
35
#[allow(clippy::large_enum_variant)]
36
#[cfg(feature = "crypto")]
37
pub(crate) enum KeyPairKind {
38
  /// A Ecdsa key pair
39
  Ec(EcdsaKeyPair),
40
  /// A Ed25519 key pair
41
  Ed(Ed25519KeyPair),
42
  /// A Pqdsa key pair
43
  #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
44
  Pq(PqdsaKeyPair),
45
  /// A RSA key pair
46
  Rsa(RsaKeyPair, &'static dyn RsaEncoding),
47
}
48
49
#[cfg(feature = "crypto")]
50
impl fmt::Debug for KeyPairKind {
51
0
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52
0
    match self {
53
0
      Self::Ec(key_pair) => write!(f, "{key_pair:?}"),
54
0
      Self::Ed(key_pair) => write!(f, "{key_pair:?}"),
55
      #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
56
      Self::Pq(key_pair) => write!(f, "{key_pair:?}"),
57
0
      Self::Rsa(key_pair, _) => write!(f, "{key_pair:?}"),
58
    }
59
0
  }
60
}
61
62
/// A key pair used to sign certificates and CSRs
63
#[cfg(feature = "crypto")]
64
pub struct KeyPair {
65
  pub(crate) kind: KeyPairKind,
66
  pub(crate) alg: &'static SignatureAlgorithm,
67
  pub(crate) serialized_der: Vec<u8>,
68
}
69
70
#[cfg(feature = "crypto")]
71
impl fmt::Debug for KeyPair {
72
0
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73
0
    f.debug_struct("KeyPair")
74
0
      .field("kind", &self.kind)
75
0
      .field("alg", &self.alg)
76
0
      .field("serialized_der", &"[secret key elided]")
77
0
      .finish()
78
0
  }
79
}
80
81
#[cfg(feature = "crypto")]
82
impl KeyPair {
83
  /// Generate a new random [`PKCS_ECDSA_P256_SHA256`] key pair
84
  #[cfg(feature = "crypto")]
85
0
  pub fn generate() -> Result<Self, Error> {
86
0
    Self::generate_for(&PKCS_ECDSA_P256_SHA256)
87
0
  }
88
89
  /// Generate a new random key pair for the specified signature algorithm
90
  ///
91
  /// If you're not sure which algorithm to use, [`PKCS_ECDSA_P256_SHA256`] is a good choice.
92
  /// If passed an RSA signature algorithm, it depends on the backend whether we return
93
  /// a generated key or an error for key generation being unavailable.
94
  /// Currently, only `aws-lc-rs` supports RSA key generation.
95
  #[cfg(feature = "crypto")]
96
0
  pub fn generate_for(alg: &'static SignatureAlgorithm) -> Result<Self, Error> {
97
0
    let rng = &SystemRandom::new();
98
99
0
    match alg.sign_alg {
100
0
      SignAlgo::EcDsa(sign_alg) => {
101
0
        let key_pair_doc = EcdsaKeyPair::generate_pkcs8(sign_alg, rng)._err()?;
102
0
        let key_pair_serialized = key_pair_doc.as_ref().to_vec();
103
104
0
        let key_pair = ecdsa_from_pkcs8(sign_alg, key_pair_doc.as_ref(), rng).unwrap();
105
0
        Ok(KeyPair {
106
0
          kind: KeyPairKind::Ec(key_pair),
107
0
          alg,
108
0
          serialized_der: key_pair_serialized,
109
0
        })
110
      },
111
0
      SignAlgo::EdDsa(_sign_alg) => {
112
0
        let key_pair_doc = Ed25519KeyPair::generate_pkcs8(rng)._err()?;
113
0
        let key_pair_serialized = key_pair_doc.as_ref().to_vec();
114
115
0
        let key_pair = Ed25519KeyPair::from_pkcs8(key_pair_doc.as_ref()).unwrap();
116
0
        Ok(KeyPair {
117
0
          kind: KeyPairKind::Ed(key_pair),
118
0
          alg,
119
0
          serialized_der: key_pair_serialized,
120
0
        })
121
      },
122
      #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
123
      SignAlgo::PqDsa(sign_alg) => {
124
        let key_pair = PqdsaKeyPair::generate(sign_alg)._err()?;
125
        let key_pair_serialized = key_pair.to_pkcs8()._err()?.as_ref().to_vec();
126
127
        Ok(KeyPair {
128
          kind: KeyPairKind::Pq(key_pair),
129
          alg,
130
          serialized_der: key_pair_serialized,
131
        })
132
      },
133
      #[cfg(feature = "aws_lc_rs")]
134
0
      SignAlgo::Rsa(sign_alg) => Self::generate_rsa_inner(alg, sign_alg, KeySize::Rsa2048),
135
      // Ring doesn't have RSA key generation yet:
136
      // https://github.com/briansmith/ring/issues/219
137
      // https://github.com/briansmith/ring/pull/733
138
      #[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))]
139
      SignAlgo::Rsa(_sign_alg) => Err(Error::KeyGenerationUnavailable),
140
    }
141
0
  }
142
143
  /// Generates a new random RSA key pair for the specified key size
144
  ///
145
  /// If passed a signature algorithm that is not RSA, it will return
146
  /// [`Error::KeyGenerationUnavailable`].
147
  #[cfg(all(feature = "crypto", feature = "aws_lc_rs"))]
148
0
  pub fn generate_rsa_for(
149
0
    alg: &'static SignatureAlgorithm,
150
0
    key_size: RsaKeySize,
151
0
  ) -> Result<Self, Error> {
152
0
    match alg.sign_alg {
153
0
      SignAlgo::Rsa(sign_alg) => {
154
0
        let key_size = match key_size {
155
0
          RsaKeySize::_2048 => KeySize::Rsa2048,
156
0
          RsaKeySize::_3072 => KeySize::Rsa3072,
157
0
          RsaKeySize::_4096 => KeySize::Rsa4096,
158
        };
159
0
        Self::generate_rsa_inner(alg, sign_alg, key_size)
160
      },
161
0
      _ => Err(Error::KeyGenerationUnavailable),
162
    }
163
0
  }
164
165
  #[cfg(all(feature = "crypto", feature = "aws_lc_rs"))]
166
0
  fn generate_rsa_inner(
167
0
    alg: &'static SignatureAlgorithm,
168
0
    sign_alg: &'static dyn RsaEncoding,
169
0
    key_size: KeySize,
170
0
  ) -> Result<Self, Error> {
171
    use aws_lc_rs::encoding::AsDer;
172
0
    let key_pair = RsaKeyPair::generate(key_size)._err()?;
173
0
    let key_pair_serialized = key_pair.as_der()._err()?.as_ref().to_vec();
174
175
0
    Ok(KeyPair {
176
0
      kind: KeyPairKind::Rsa(key_pair, sign_alg),
177
0
      alg,
178
0
      serialized_der: key_pair_serialized,
179
0
    })
180
0
  }
181
182
  /// Returns the key pair's signature algorithm
183
0
  pub fn algorithm(&self) -> &'static SignatureAlgorithm {
184
0
    self.alg
185
0
  }
186
187
  /// Parses the key pair from the ASCII PEM format
188
  ///
189
  /// If `aws_lc_rs` feature is used, then the key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958, SEC1/RFC 5915, or PKCS#1/RFC 3447;
190
  /// Appears as "PRIVATE KEY", "RSA PRIVATE KEY", or "EC PRIVATE KEY" in PEM files.
191
  ///
192
  /// Otherwise if the `ring` feature is used, then the key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958;
193
  /// Appears as "PRIVATE KEY" in PEM files.
194
  #[cfg(all(feature = "pem", feature = "crypto"))]
195
0
  pub fn from_pem(pem_str: &str) -> Result<Self, Error> {
196
0
    let private_key = pem::parse(pem_str)._err()?;
197
0
    Self::try_from(private_key.contents())
198
0
  }
199
200
  /// Obtains the key pair from a DER formatted key
201
  /// using the specified [`SignatureAlgorithm`]
202
  ///
203
  /// The key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958;
204
  ///
205
  /// Appears as "PRIVATE KEY" in PEM files
206
  /// Same as [from_pkcs8_pem_and_sign_algo](Self::from_pkcs8_pem_and_sign_algo).
207
  #[cfg(all(feature = "pem", feature = "crypto"))]
208
0
  pub fn from_pkcs8_pem_and_sign_algo(
209
0
    pem_str: &str,
210
0
    alg: &'static SignatureAlgorithm,
211
0
  ) -> Result<Self, Error> {
212
0
    let private_key = pem::parse(pem_str)._err()?;
213
0
    let private_key_der: &[_] = private_key.contents();
214
0
    Self::from_pkcs8_der_and_sign_algo(&PrivatePkcs8KeyDer::from(private_key_der), alg)
215
0
  }
216
217
  /// Obtains the key pair from a DER formatted key using the specified [`SignatureAlgorithm`]
218
  ///
219
  /// If you have a [`PrivatePkcs8KeyDer`], you can usually rely on the [`TryFrom`] implementation
220
  /// to obtain a [`KeyPair`] -- it will determine the correct [`SignatureAlgorithm`] for you.
221
  /// However, sometimes multiple signature algorithms fit for the same DER key. In those instances,
222
  /// you can use this function to precisely specify the `SignatureAlgorithm`.
223
  ///
224
  /// [`rustls_pemfile::private_key()`] is often used to obtain a [`PrivateKeyDer`] from PEM
225
  /// input. If the obtained [`PrivateKeyDer`] is a `Pkcs8` variant, you can use its contents
226
  /// as input for this function. Alternatively, if you already have a byte slice containing DER,
227
  /// it can trivially be converted into [`PrivatePkcs8KeyDer`] using the [`Into`] trait.
228
  ///
229
  /// [`rustls_pemfile::private_key()`]: https://docs.rs/rustls-pemfile/latest/rustls_pemfile/fn.private_key.html
230
  /// [`PrivateKeyDer`]: https://docs.rs/rustls-pki-types/latest/rustls_pki_types/enum.PrivateKeyDer.html
231
  #[cfg(feature = "crypto")]
232
0
  pub fn from_pkcs8_der_and_sign_algo(
233
0
    pkcs8: &PrivatePkcs8KeyDer<'_>,
234
0
    alg: &'static SignatureAlgorithm,
235
0
  ) -> Result<Self, Error> {
236
0
    let rng = &SystemRandom::new();
237
0
    let serialized_der = pkcs8.secret_pkcs8_der().to_vec();
238
239
0
    let kind = if alg == &PKCS_ED25519 {
240
0
      KeyPairKind::Ed(Ed25519KeyPair::from_pkcs8_maybe_unchecked(&serialized_der)._err()?)
241
0
    } else if alg == &PKCS_ECDSA_P256_SHA256 {
242
0
      KeyPairKind::Ec(ecdsa_from_pkcs8(
243
0
        &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
244
0
        &serialized_der,
245
0
        rng,
246
0
      )?)
247
0
    } else if alg == &PKCS_ECDSA_P384_SHA384 {
248
0
      KeyPairKind::Ec(ecdsa_from_pkcs8(
249
0
        &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
250
0
        &serialized_der,
251
0
        rng,
252
0
      )?)
253
0
    } else if alg == &PKCS_RSA_SHA256 {
254
0
      let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?;
255
0
      KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256)
256
0
    } else if alg == &PKCS_RSA_SHA384 {
257
0
      let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?;
258
0
      KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA384)
259
0
    } else if alg == &PKCS_RSA_SHA512 {
260
0
      let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?;
261
0
      KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA512)
262
0
    } else if alg == &PKCS_RSA_PSS_SHA256 {
263
0
      let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?;
264
0
      KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA256)
265
    } else {
266
      #[cfg(feature = "aws_lc_rs")]
267
0
      if alg == &PKCS_ECDSA_P521_SHA256 {
268
0
        KeyPairKind::Ec(ecdsa_from_pkcs8(
269
0
          &signature::ECDSA_P521_SHA256_ASN1_SIGNING,
270
0
          &serialized_der,
271
0
          rng,
272
0
        )?)
273
0
      } else if alg == &PKCS_ECDSA_P521_SHA384 {
274
0
        KeyPairKind::Ec(ecdsa_from_pkcs8(
275
0
          &signature::ECDSA_P521_SHA384_ASN1_SIGNING,
276
0
          &serialized_der,
277
0
          rng,
278
0
        )?)
279
0
      } else if alg == &PKCS_ECDSA_P521_SHA512 {
280
0
        KeyPairKind::Ec(ecdsa_from_pkcs8(
281
0
          &signature::ECDSA_P521_SHA512_ASN1_SIGNING,
282
0
          &serialized_der,
283
0
          rng,
284
0
        )?)
285
      } else {
286
0
        panic!("Unknown SignatureAlgorithm specified!");
287
      }
288
289
      #[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))]
290
      panic!("Unknown SignatureAlgorithm specified!");
291
    };
292
293
0
    Ok(KeyPair {
294
0
      kind,
295
0
      alg,
296
0
      serialized_der,
297
0
    })
298
0
  }
299
300
  /// Obtains the key pair from a PEM formatted key
301
  /// using the specified [`SignatureAlgorithm`]
302
  ///
303
  /// If `aws_lc_rs` feature is used, then the key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958, SEC1/RFC 5915, or PKCS#1/RFC 3447;
304
  /// Appears as "PRIVATE KEY", "RSA PRIVATE KEY", or "EC PRIVATE KEY" in PEM files.
305
  ///
306
  /// Otherwise if the `ring` feature is used, then the key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958;
307
  /// Appears as "PRIVATE KEY" in PEM files.
308
  ///
309
  /// Same as [from_pem_and_sign_algo](Self::from_pem_and_sign_algo).
310
  #[cfg(all(feature = "pem", feature = "crypto"))]
311
0
  pub fn from_pem_and_sign_algo(
312
0
    pem_str: &str,
313
0
    alg: &'static SignatureAlgorithm,
314
0
  ) -> Result<Self, Error> {
315
0
    let private_key = pem::parse(pem_str)._err()?;
316
0
    let private_key: &[_] = private_key.contents();
317
0
    Self::from_der_and_sign_algo(
318
0
      &PrivateKeyDer::try_from(private_key).map_err(|_| Error::CouldNotParseKeyPair)?,
319
0
      alg,
320
    )
321
0
  }
322
323
  /// Obtains the key pair from a DER formatted key
324
  /// using the specified [`SignatureAlgorithm`]
325
  ///
326
  /// Note that using the `ring` feature, this function only support [`PrivateKeyDer::Pkcs8`] variant.
327
  /// Consider using the `aws_lc_rs` features to support [`PrivateKeyDer`] fully.
328
  ///
329
  /// If you have a [`PrivateKeyDer`], you can usually rely on the [`TryFrom`] implementation
330
  /// to obtain a [`KeyPair`] -- it will determine the correct [`SignatureAlgorithm`] for you.
331
  /// However, sometimes multiple signature algorithms fit for the same DER key. In those instances,
332
  /// you can use this function to precisely specify the `SignatureAlgorithm`.
333
  ///
334
  /// You can use [`rustls_pemfile::private_key`] to get the `key` input. If
335
  /// you have already a byte slice, just calling `try_into()` will convert it to a [`PrivateKeyDer`].
336
  ///
337
  /// [`rustls_pemfile::private_key`]: https://docs.rs/rustls-pemfile/latest/rustls_pemfile/fn.private_key.html
338
  #[cfg(feature = "crypto")]
339
0
  pub fn from_der_and_sign_algo(
340
0
    key: &PrivateKeyDer<'_>,
341
0
    alg: &'static SignatureAlgorithm,
342
0
  ) -> Result<Self, Error> {
343
    #[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))]
344
    {
345
      if let PrivateKeyDer::Pkcs8(key) = key {
346
        Self::from_pkcs8_der_and_sign_algo(key, alg)
347
      } else {
348
        Err(Error::CouldNotParseKeyPair)
349
      }
350
    }
351
    #[cfg(feature = "aws_lc_rs")]
352
    {
353
0
      let is_pkcs8 = matches!(key, PrivateKeyDer::Pkcs8(_));
354
355
0
      let rsa_key_pair_from = if is_pkcs8 {
356
0
        RsaKeyPair::from_pkcs8
357
0
      } else {
358
0
        RsaKeyPair::from_der
359
0
      };
360
361
0
      let serialized_der = key.secret_der().to_vec();
362
363
0
      let kind = if alg == &PKCS_ED25519 {
364
0
        KeyPairKind::Ed(Ed25519KeyPair::from_pkcs8_maybe_unchecked(&serialized_der)._err()?)
365
0
      } else if alg == &PKCS_ECDSA_P256_SHA256 {
366
0
        KeyPairKind::Ec(ecdsa_from_private_key_der(
367
0
          &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
368
0
          &serialized_der,
369
0
        )?)
370
0
      } else if alg == &PKCS_ECDSA_P384_SHA384 {
371
0
        KeyPairKind::Ec(ecdsa_from_private_key_der(
372
0
          &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
373
0
          &serialized_der,
374
0
        )?)
375
0
      } else if alg == &PKCS_ECDSA_P521_SHA512 {
376
0
        KeyPairKind::Ec(ecdsa_from_private_key_der(
377
0
          &signature::ECDSA_P521_SHA512_ASN1_SIGNING,
378
0
          &serialized_der,
379
0
        )?)
380
0
      } else if alg == &PKCS_RSA_SHA256 {
381
0
        let rsakp = rsa_key_pair_from(&serialized_der)._err()?;
382
0
        KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256)
383
0
      } else if alg == &PKCS_RSA_SHA384 {
384
0
        let rsakp = rsa_key_pair_from(&serialized_der)._err()?;
385
0
        KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA384)
386
0
      } else if alg == &PKCS_RSA_SHA512 {
387
0
        let rsakp = rsa_key_pair_from(&serialized_der)._err()?;
388
0
        KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA512)
389
0
      } else if alg == &PKCS_RSA_PSS_SHA256 {
390
0
        let rsakp = rsa_key_pair_from(&serialized_der)._err()?;
391
0
        KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA256)
392
      } else {
393
0
        panic!("Unknown SignatureAlgorithm specified!");
394
      };
395
396
0
      Ok(KeyPair {
397
0
        kind,
398
0
        alg,
399
0
        serialized_der,
400
0
      })
401
    }
402
0
  }
403
404
  /// Get the raw public key of this key pair
405
  ///
406
  /// The key is in raw format, as how [`KeyPair::public_key()`][public_key]
407
  /// would output, and how [`UnparsedPublicKey::verify()`][verify]
408
  /// would accept.
409
  ///
410
  /// [public_key]: crate::ring_like::signature::KeyPair::public_key()
411
  /// [verify]: crate::ring_like::signature::UnparsedPublicKey::verify()
412
0
  pub fn public_key_raw(&self) -> &[u8] {
413
0
    self.der_bytes()
414
0
  }
415
416
  /// Check if this key pair can be used with the given signature algorithm
417
0
  pub fn is_compatible(&self, signature_algorithm: &SignatureAlgorithm) -> bool {
418
0
    self.alg == signature_algorithm
419
0
  }
420
421
  /// Returns (possibly multiple) compatible [`SignatureAlgorithm`]'s
422
  /// that the key can be used with
423
0
  pub fn compatible_algs(&self) -> impl Iterator<Item = &'static SignatureAlgorithm> {
424
0
    std::iter::once(self.alg)
425
0
  }
426
427
  /// Return the key pair's public key in PEM format
428
  ///
429
  /// The returned string can be interpreted with `openssl pkey --inform PEM -pubout -pubin -text`
430
  #[cfg(feature = "pem")]
431
0
  pub fn public_key_pem(&self) -> String {
432
0
    let contents = self.subject_public_key_info();
433
0
    let p = Pem::new("PUBLIC KEY", contents);
434
0
    pem::encode_config(&p, ENCODE_CONFIG)
435
0
  }
436
437
  /// Serializes the key pair (including the private key) in PKCS#8 format in DER
438
0
  pub fn serialize_der(&self) -> Vec<u8> {
439
0
    self.serialized_der.clone()
440
0
  }
441
442
  /// Returns a reference to the serialized key pair (including the private key)
443
  /// in PKCS#8 format in DER
444
0
  pub fn serialized_der(&self) -> &[u8] {
445
0
    &self.serialized_der
446
0
  }
447
448
  /// Serializes the key pair (including the private key) in PKCS#8 format in PEM
449
  #[cfg(feature = "pem")]
450
0
  pub fn serialize_pem(&self) -> String {
451
0
    let contents = self.serialize_der();
452
0
    let p = Pem::new("PRIVATE KEY", contents);
453
0
    pem::encode_config(&p, ENCODE_CONFIG)
454
0
  }
455
}
456
457
#[cfg(feature = "crypto")]
458
impl SigningKey for KeyPair {
459
0
  fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error> {
460
0
    Ok(match &self.kind {
461
0
      KeyPairKind::Ec(kp) => {
462
0
        let system_random = SystemRandom::new();
463
0
        let signature = kp.sign(&system_random, msg)._err()?;
464
0
        signature.as_ref().to_owned()
465
      },
466
0
      KeyPairKind::Ed(kp) => kp.sign(msg).as_ref().to_owned(),
467
      #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
468
      KeyPairKind::Pq(kp) => {
469
        let mut signature = vec![0; kp.algorithm().signature_len()];
470
        kp.sign(msg, &mut signature)._err()?;
471
        signature
472
      },
473
0
      KeyPairKind::Rsa(kp, padding_alg) => {
474
0
        let system_random = SystemRandom::new();
475
0
        let mut signature = vec![0; rsa_key_pair_public_modulus_len(kp)];
476
0
        kp.sign(*padding_alg, &system_random, msg, &mut signature)
477
0
          ._err()?;
478
0
        signature
479
      },
480
    })
481
0
  }
482
}
483
484
#[cfg(feature = "crypto")]
485
impl PublicKeyData for KeyPair {
486
0
  fn der_bytes(&self) -> &[u8] {
487
0
    match &self.kind {
488
0
      KeyPairKind::Ec(kp) => kp.public_key().as_ref(),
489
0
      KeyPairKind::Ed(kp) => kp.public_key().as_ref(),
490
      #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))]
491
      KeyPairKind::Pq(kp) => kp.public_key().as_ref(),
492
0
      KeyPairKind::Rsa(kp, _) => kp.public_key().as_ref(),
493
    }
494
0
  }
495
496
0
  fn algorithm(&self) -> &'static SignatureAlgorithm {
497
0
    self.alg
498
0
  }
499
}
500
501
#[cfg(feature = "crypto")]
502
impl TryFrom<&[u8]> for KeyPair {
503
  type Error = Error;
504
505
0
  fn try_from(key: &[u8]) -> Result<KeyPair, Error> {
506
0
    let key = &PrivateKeyDer::try_from(key).map_err(|_| Error::CouldNotParseKeyPair)?;
507
508
0
    key.try_into()
509
0
  }
510
}
511
512
#[cfg(feature = "crypto")]
513
impl TryFrom<Vec<u8>> for KeyPair {
514
  type Error = Error;
515
516
0
  fn try_from(key: Vec<u8>) -> Result<KeyPair, Error> {
517
0
    let key = &PrivateKeyDer::try_from(key).map_err(|_| Error::CouldNotParseKeyPair)?;
518
519
0
    key.try_into()
520
0
  }
521
}
522
523
#[cfg(feature = "crypto")]
524
impl TryFrom<&PrivatePkcs8KeyDer<'_>> for KeyPair {
525
  type Error = Error;
526
527
0
  fn try_from(key: &PrivatePkcs8KeyDer) -> Result<KeyPair, Error> {
528
0
    key.secret_pkcs8_der().try_into()
529
0
  }
530
}
531
532
#[cfg(feature = "crypto")]
533
impl TryFrom<&PrivateKeyDer<'_>> for KeyPair {
534
  type Error = Error;
535
536
0
  fn try_from(key: &PrivateKeyDer) -> Result<KeyPair, Error> {
537
    #[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))]
538
    let (kind, alg) = {
539
      let PrivateKeyDer::Pkcs8(pkcs8) = key else {
540
        return Err(Error::CouldNotParseKeyPair);
541
      };
542
      let pkcs8 = pkcs8.secret_pkcs8_der();
543
      let rng = SystemRandom::new();
544
      let (kind, alg) = if let Ok(edkp) = Ed25519KeyPair::from_pkcs8_maybe_unchecked(pkcs8) {
545
        (KeyPairKind::Ed(edkp), &PKCS_ED25519)
546
      } else if let Ok(eckp) =
547
        ecdsa_from_pkcs8(&signature::ECDSA_P256_SHA256_ASN1_SIGNING, pkcs8, &rng)
548
      {
549
        (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P256_SHA256)
550
      } else if let Ok(eckp) =
551
        ecdsa_from_pkcs8(&signature::ECDSA_P384_SHA384_ASN1_SIGNING, pkcs8, &rng)
552
      {
553
        (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P384_SHA384)
554
      } else if let Ok(rsakp) = RsaKeyPair::from_pkcs8(pkcs8) {
555
        (
556
          KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256),
557
          &PKCS_RSA_SHA256,
558
        )
559
      } else {
560
        return Err(Error::CouldNotParseKeyPair);
561
      };
562
563
      (kind, alg)
564
    };
565
    #[cfg(feature = "aws_lc_rs")]
566
0
    let (kind, alg) = {
567
0
      let is_pkcs8 = matches!(key, PrivateKeyDer::Pkcs8(_));
568
569
0
      let key = key.secret_der();
570
571
0
      let rsa_key_pair_from = if is_pkcs8 {
572
0
        RsaKeyPair::from_pkcs8
573
0
      } else {
574
0
        RsaKeyPair::from_der
575
0
      };
576
577
0
      let (kind, alg) = if let Ok(edkp) = Ed25519KeyPair::from_pkcs8_maybe_unchecked(key) {
578
0
        (KeyPairKind::Ed(edkp), &PKCS_ED25519)
579
0
      } else if let Ok(eckp) =
580
0
        ecdsa_from_private_key_der(&signature::ECDSA_P256_SHA256_ASN1_SIGNING, key)
581
      {
582
0
        (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P256_SHA256)
583
0
      } else if let Ok(eckp) =
584
0
        ecdsa_from_private_key_der(&signature::ECDSA_P384_SHA384_ASN1_SIGNING, key)
585
      {
586
0
        (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P384_SHA384)
587
0
      } else if let Ok(eckp) =
588
0
        ecdsa_from_private_key_der(&signature::ECDSA_P521_SHA512_ASN1_SIGNING, key)
589
      {
590
0
        (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P521_SHA512)
591
0
      } else if let Ok(rsakp) = rsa_key_pair_from(key) {
592
0
        (
593
0
          KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256),
594
0
          &PKCS_RSA_SHA256,
595
0
        )
596
      } else {
597
0
        return Err(Error::CouldNotParseKeyPair);
598
      };
599
0
      (kind, alg)
600
    };
601
602
0
    Ok(KeyPair {
603
0
      kind,
604
0
      alg,
605
0
      serialized_der: key.secret_der().into(),
606
0
    })
607
0
  }
608
}
609
610
#[cfg(feature = "crypto")]
611
impl From<KeyPair> for PrivatePkcs8KeyDer<'static> {
612
0
  fn from(val: KeyPair) -> Self {
613
0
    val.serialize_der().into()
614
0
  }
615
}
616
617
#[cfg(feature = "crypto")]
618
impl From<KeyPair> for PrivateKeyDer<'static> {
619
0
  fn from(val: KeyPair) -> Self {
620
0
    Self::from(PrivatePkcs8KeyDer::from(val))
621
0
  }
622
}
623
624
/// The key size used for RSA key generation
625
#[cfg(all(feature = "crypto", feature = "aws_lc_rs"))]
626
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
627
#[non_exhaustive]
628
pub enum RsaKeySize {
629
  /// 2048 bits
630
  _2048,
631
  /// 3072 bits
632
  _3072,
633
  /// 4096 bits
634
  _4096,
635
}
636
637
0
pub(crate) fn sign_der(
638
0
  key: &impl SigningKey,
639
0
  f: impl FnOnce(&mut DERWriterSeq<'_>) -> Result<(), Error>,
640
0
) -> Result<Vec<u8>, Error> {
641
0
  yasna::try_construct_der(|writer| {
642
0
    writer.write_sequence(|writer| {
643
0
      let data = yasna::try_construct_der(|writer| writer.write_sequence(f))?;
Unexecuted instantiation: rcgen::key_pair::sign_der::<rcgen::key_pair::KeyPair, <rcgen::certificate::CertificateParams>::serialize_request_with_attributes<rcgen::key_pair::KeyPair>::{closure#0}>::{closure#0}::{closure#0}::{closure#0}
Unexecuted instantiation: rcgen::key_pair::sign_der::<_, _>::{closure#0}::{closure#0}::{closure#0}
644
0
      writer.next().write_der(&data);
645
646
      // Write signatureAlgorithm
647
0
      key.algorithm().write_alg_ident(writer.next());
648
649
      // Write signature
650
0
      let sig = key.sign(&data)?;
651
0
      let writer = writer.next();
652
0
      writer.write_bitvec_bytes(&sig, sig.len() * 8);
653
654
0
      Ok(())
655
0
    })
Unexecuted instantiation: rcgen::key_pair::sign_der::<rcgen::key_pair::KeyPair, <rcgen::certificate::CertificateParams>::serialize_request_with_attributes<rcgen::key_pair::KeyPair>::{closure#0}>::{closure#0}::{closure#0}
Unexecuted instantiation: rcgen::key_pair::sign_der::<_, _>::{closure#0}::{closure#0}
656
0
  })
Unexecuted instantiation: rcgen::key_pair::sign_der::<rcgen::key_pair::KeyPair, <rcgen::certificate::CertificateParams>::serialize_request_with_attributes<rcgen::key_pair::KeyPair>::{closure#0}>::{closure#0}
Unexecuted instantiation: rcgen::key_pair::sign_der::<_, _>::{closure#0}
657
0
}
Unexecuted instantiation: rcgen::key_pair::sign_der::<rcgen::key_pair::KeyPair, <rcgen::certificate::CertificateParams>::serialize_request_with_attributes<rcgen::key_pair::KeyPair>::{closure#0}>
Unexecuted instantiation: rcgen::key_pair::sign_der::<_, _>
658
659
impl<S: SigningKey + ?Sized> SigningKey for &S {
660
0
  fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error> {
661
0
    (*self).sign(msg)
662
0
  }
663
}
664
665
/// A key that can be used to sign messages
666
pub trait SigningKey: PublicKeyData {
667
  /// Signs `msg` using the selected algorithm
668
  fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error>;
669
}
670
671
#[cfg(feature = "crypto")]
672
impl<T> ExternalError<T> for Result<T, ring_error::KeyRejected> {
673
0
  fn _err(self) -> Result<T, Error> {
674
0
    self.map_err(|e| Error::RingKeyRejected(e.to_string()))
Unexecuted instantiation: <core::result::Result<aws_lc_rs::ed25519::Ed25519KeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::ed25519::Ed25519KeyPair>>::_err::{closure#0}
Unexecuted instantiation: <core::result::Result<aws_lc_rs::ec::key_pair::EcdsaKeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::ec::key_pair::EcdsaKeyPair>>::_err::{closure#0}
Unexecuted instantiation: <core::result::Result<aws_lc_rs::rsa::key::KeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::rsa::key::KeyPair>>::_err::{closure#0}
675
0
  }
Unexecuted instantiation: <core::result::Result<aws_lc_rs::ed25519::Ed25519KeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::ed25519::Ed25519KeyPair>>::_err
Unexecuted instantiation: <core::result::Result<aws_lc_rs::ec::key_pair::EcdsaKeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::ec::key_pair::EcdsaKeyPair>>::_err
Unexecuted instantiation: <core::result::Result<aws_lc_rs::rsa::key::KeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::rsa::key::KeyPair>>::_err
676
}
677
678
#[cfg(feature = "crypto")]
679
impl<T> ExternalError<T> for Result<T, ring_error::Unspecified> {
680
0
  fn _err(self) -> Result<T, Error> {
681
0
    self.map_err(|_| Error::RingUnspecified)
682
0
  }
Unexecuted instantiation: <core::result::Result<aws_lc_rs::pkcs8::Document, aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<aws_lc_rs::pkcs8::Document>>::_err
Unexecuted instantiation: <core::result::Result<aws_lc_rs::encoding::Pkcs8V1Der, aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<aws_lc_rs::encoding::Pkcs8V1Der>>::_err
Unexecuted instantiation: <core::result::Result<aws_lc_rs::signature::Signature, aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<aws_lc_rs::signature::Signature>>::_err
Unexecuted instantiation: <core::result::Result<aws_lc_rs::rsa::key::KeyPair, aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<aws_lc_rs::rsa::key::KeyPair>>::_err
Unexecuted instantiation: <core::result::Result<(), aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<()>>::_err
683
}
684
685
#[cfg(feature = "pem")]
686
impl<T> ExternalError<T> for Result<T, pem::PemError> {
687
0
  fn _err(self) -> Result<T, Error> {
688
0
    self.map_err(|e| Error::PemError(e.to_string()))
689
0
  }
690
}
691
692
/// A public key
693
#[derive(Clone, Debug, Eq, PartialEq)]
694
pub struct SubjectPublicKeyInfo {
695
  pub(crate) alg: &'static SignatureAlgorithm,
696
  pub(crate) subject_public_key: Vec<u8>,
697
}
698
699
impl SubjectPublicKeyInfo {
700
  /// Create a `SubjectPublicKey` value from a PEM-encoded SubjectPublicKeyInfo string
701
  #[cfg(all(feature = "x509-parser", feature = "pem"))]
702
  pub fn from_pem(pem_str: &str) -> Result<Self, Error> {
703
    Self::from_der(&pem::parse(pem_str)._err()?.into_contents())
704
  }
705
706
  /// Create a `SubjectPublicKey` value from DER-encoded SubjectPublicKeyInfo bytes
707
  #[cfg(feature = "x509-parser")]
708
  pub fn from_der(spki_der: &[u8]) -> Result<Self, Error> {
709
    use x509_parser::prelude::FromDer;
710
    use x509_parser::x509::{AlgorithmIdentifier, SubjectPublicKeyInfo};
711
712
    let (rem, spki) =
713
      SubjectPublicKeyInfo::from_der(spki_der).map_err(|e| Error::X509(e.to_string()))?;
714
    if !rem.is_empty() {
715
      return Err(Error::X509(
716
        "trailing bytes in SubjectPublicKeyInfo".to_string(),
717
      ));
718
    }
719
720
    let alg = SignatureAlgorithm::iter()
721
      .find(|alg| {
722
        let bytes = yasna::construct_der(|writer| {
723
          alg.write_oids_sign_alg(writer);
724
        });
725
        let Ok((rest, aid)) = AlgorithmIdentifier::from_der(&bytes) else {
726
          return false;
727
        };
728
        if !rest.is_empty() {
729
          return false;
730
        }
731
        aid == spki.algorithm
732
      })
733
      .ok_or(Error::UnsupportedSignatureAlgorithm)?;
734
735
    Ok(Self {
736
      alg,
737
      subject_public_key: Vec::from(spki.subject_public_key.as_ref()),
738
    })
739
  }
740
}
741
742
impl PublicKeyData for SubjectPublicKeyInfo {
743
0
  fn der_bytes(&self) -> &[u8] {
744
0
    &self.subject_public_key
745
0
  }
746
747
0
  fn algorithm(&self) -> &'static SignatureAlgorithm {
748
0
    self.alg
749
0
  }
750
}
751
752
impl<K: PublicKeyData + ?Sized> PublicKeyData for &K {
753
0
  fn der_bytes(&self) -> &[u8] {
754
0
    (*self).der_bytes()
755
0
  }
756
757
0
  fn algorithm(&self) -> &'static SignatureAlgorithm {
758
0
    (*self).algorithm()
759
0
  }
760
}
761
762
/// The public key data of a key pair
763
pub trait PublicKeyData {
764
  /// The public key data in DER format
765
  ///
766
  /// The key is formatted according to the X.509 SubjectPublicKeyInfo struct.
767
  /// See [RFC 5280 section 4.1](https://tools.ietf.org/html/rfc5280#section-4.1).
768
0
  fn subject_public_key_info(&self) -> Vec<u8> {
769
0
    yasna::construct_der(|writer| serialize_public_key_der(self, writer))
770
0
  }
771
772
  /// The public key in DER format
773
  fn der_bytes(&self) -> &[u8];
774
775
  /// The algorithm used by the key pair
776
  fn algorithm(&self) -> &'static SignatureAlgorithm;
777
}
778
779
0
pub(crate) fn serialize_public_key_der(key: &(impl PublicKeyData + ?Sized), writer: DERWriter) {
780
0
  writer.write_sequence(|writer| {
781
0
    key.algorithm().write_oids_sign_alg(writer.next());
782
0
    let pk = key.der_bytes();
783
0
    writer.next().write_bitvec_bytes(pk, pk.len() * 8);
784
0
  })
785
0
}
786
787
#[cfg(all(test, feature = "crypto"))]
788
mod test {
789
  use super::*;
790
  use crate::ring_like::rand::SystemRandom;
791
  use crate::ring_like::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING};
792
793
  #[cfg(all(feature = "x509-parser", feature = "pem"))]
794
  #[test]
795
  fn test_subject_public_key_parsing() {
796
    for alg in [
797
      &PKCS_ED25519,
798
      &PKCS_ECDSA_P256_SHA256,
799
      &PKCS_ECDSA_P384_SHA384,
800
      #[cfg(feature = "aws_lc_rs")]
801
      &PKCS_ECDSA_P521_SHA512,
802
      #[cfg(feature = "aws_lc_rs")]
803
      &PKCS_RSA_SHA256,
804
    ] {
805
      let kp = KeyPair::generate_for(alg).expect("keygen");
806
      let pem = kp.public_key_pem();
807
      let der = kp.subject_public_key_info();
808
809
      let pkd_pem = SubjectPublicKeyInfo::from_pem(&pem).expect("from pem");
810
      assert_eq!(kp.der_bytes(), pkd_pem.der_bytes());
811
812
      let pkd_der = SubjectPublicKeyInfo::from_der(&der).expect("from der");
813
      assert_eq!(kp.der_bytes(), pkd_der.der_bytes());
814
    }
815
  }
816
817
  #[test]
818
  fn test_algorithm() {
819
    let rng = SystemRandom::new();
820
    let pkcs8 = EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, &rng).unwrap();
821
    let der = pkcs8.as_ref().to_vec();
822
823
    let key_pair = KeyPair::try_from(der).unwrap();
824
    assert_eq!(key_pair.algorithm(), &PKCS_ECDSA_P256_SHA256);
825
  }
826
}