rcgen/
key_pair.rs

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