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_SHA256 {
268				KeyPairKind::Ec(ecdsa_from_pkcs8(
269					&signature::ECDSA_P521_SHA256_ASN1_SIGNING,
270					&serialized_der,
271					rng,
272				)?)
273			} else if alg == &PKCS_ECDSA_P521_SHA384 {
274				KeyPairKind::Ec(ecdsa_from_pkcs8(
275					&signature::ECDSA_P521_SHA384_ASN1_SIGNING,
276					&serialized_der,
277					rng,
278				)?)
279			} else if alg == &PKCS_ECDSA_P521_SHA512 {
280				KeyPairKind::Ec(ecdsa_from_pkcs8(
281					&signature::ECDSA_P521_SHA512_ASN1_SIGNING,
282					&serialized_der,
283					rng,
284				)?)
285			} else {
286				panic!("Unknown SignatureAlgorithm specified!");
287			}
288
289			#[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))]
290			panic!("Unknown SignatureAlgorithm specified!");
291		};
292
293		Ok(KeyPair {
294			kind,
295			alg,
296			serialized_der,
297		})
298	}
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	pub fn from_pem_and_sign_algo(
312		pem_str: &str,
313		alg: &'static SignatureAlgorithm,
314	) -> Result<Self, Error> {
315		let private_key = pem::parse(pem_str)._err()?;
316		let private_key: &[_] = private_key.contents();
317		Self::from_der_and_sign_algo(
318			&PrivateKeyDer::try_from(private_key).map_err(|_| Error::CouldNotParseKeyPair)?,
319			alg,
320		)
321	}
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	pub fn from_der_and_sign_algo(
340		key: &PrivateKeyDer<'_>,
341		alg: &'static SignatureAlgorithm,
342	) -> 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			let is_pkcs8 = matches!(key, PrivateKeyDer::Pkcs8(_));
354
355			let rsa_key_pair_from = if is_pkcs8 {
356				RsaKeyPair::from_pkcs8
357			} else {
358				RsaKeyPair::from_der
359			};
360
361			let serialized_der = key.secret_der().to_vec();
362
363			let kind = if alg == &PKCS_ED25519 {
364				KeyPairKind::Ed(Ed25519KeyPair::from_pkcs8_maybe_unchecked(&serialized_der)._err()?)
365			} else if alg == &PKCS_ECDSA_P256_SHA256 {
366				KeyPairKind::Ec(ecdsa_from_private_key_der(
367					&signature::ECDSA_P256_SHA256_ASN1_SIGNING,
368					&serialized_der,
369				)?)
370			} else if alg == &PKCS_ECDSA_P384_SHA384 {
371				KeyPairKind::Ec(ecdsa_from_private_key_der(
372					&signature::ECDSA_P384_SHA384_ASN1_SIGNING,
373					&serialized_der,
374				)?)
375			} else if alg == &PKCS_ECDSA_P521_SHA512 {
376				KeyPairKind::Ec(ecdsa_from_private_key_der(
377					&signature::ECDSA_P521_SHA512_ASN1_SIGNING,
378					&serialized_der,
379				)?)
380			} else if alg == &PKCS_RSA_SHA256 {
381				let rsakp = rsa_key_pair_from(&serialized_der)._err()?;
382				KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256)
383			} else if alg == &PKCS_RSA_SHA384 {
384				let rsakp = rsa_key_pair_from(&serialized_der)._err()?;
385				KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA384)
386			} else if alg == &PKCS_RSA_SHA512 {
387				let rsakp = rsa_key_pair_from(&serialized_der)._err()?;
388				KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA512)
389			} else if alg == &PKCS_RSA_PSS_SHA256 {
390				let rsakp = rsa_key_pair_from(&serialized_der)._err()?;
391				KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA256)
392			} else {
393				panic!("Unknown SignatureAlgorithm specified!");
394			};
395
396			Ok(KeyPair {
397				kind,
398				alg,
399				serialized_der,
400			})
401		}
402	}
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	pub fn public_key_raw(&self) -> &[u8] {
413		self.der_bytes()
414	}
415
416	/// Check if this key pair can be used with the given signature algorithm
417	pub fn is_compatible(&self, signature_algorithm: &SignatureAlgorithm) -> bool {
418		self.alg == signature_algorithm
419	}
420
421	/// Returns (possibly multiple) compatible [`SignatureAlgorithm`]'s
422	/// that the key can be used with
423	pub fn compatible_algs(&self) -> impl Iterator<Item = &'static SignatureAlgorithm> {
424		std::iter::once(self.alg)
425	}
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	pub fn public_key_pem(&self) -> String {
432		let contents = self.subject_public_key_info();
433		let p = Pem::new("PUBLIC KEY", contents);
434		pem::encode_config(&p, ENCODE_CONFIG)
435	}
436
437	/// Serializes the key pair (including the private key) in PKCS#8 format in DER
438	pub fn serialize_der(&self) -> Vec<u8> {
439		self.serialized_der.clone()
440	}
441
442	/// Returns a reference to the serialized key pair (including the private key)
443	/// in PKCS#8 format in DER
444	pub fn serialized_der(&self) -> &[u8] {
445		&self.serialized_der
446	}
447
448	/// Serializes the key pair (including the private key) in PKCS#8 format in PEM
449	#[cfg(feature = "pem")]
450	pub fn serialize_pem(&self) -> String {
451		let contents = self.serialize_der();
452		let p = Pem::new("PRIVATE KEY", contents);
453		pem::encode_config(&p, ENCODE_CONFIG)
454	}
455}
456
457#[cfg(feature = "crypto")]
458impl SigningKey for KeyPair {
459	fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error> {
460		Ok(match &self.kind {
461			KeyPairKind::Ec(kp) => {
462				let system_random = SystemRandom::new();
463				let signature = kp.sign(&system_random, msg)._err()?;
464				signature.as_ref().to_owned()
465			},
466			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			KeyPairKind::Rsa(kp, padding_alg) => {
474				let system_random = SystemRandom::new();
475				let mut signature = vec![0; rsa_key_pair_public_modulus_len(kp)];
476				kp.sign(*padding_alg, &system_random, msg, &mut signature)
477					._err()?;
478				signature
479			},
480		})
481	}
482}
483
484#[cfg(feature = "crypto")]
485impl PublicKeyData for KeyPair {
486	fn der_bytes(&self) -> &[u8] {
487		match &self.kind {
488			KeyPairKind::Ec(kp) => kp.public_key().as_ref(),
489			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			KeyPairKind::Rsa(kp, _) => kp.public_key().as_ref(),
493		}
494	}
495
496	fn algorithm(&self) -> &'static SignatureAlgorithm {
497		self.alg
498	}
499}
500
501#[cfg(feature = "crypto")]
502impl TryFrom<&[u8]> for KeyPair {
503	type Error = Error;
504
505	fn try_from(key: &[u8]) -> Result<KeyPair, Error> {
506		let key = &PrivateKeyDer::try_from(key).map_err(|_| Error::CouldNotParseKeyPair)?;
507
508		key.try_into()
509	}
510}
511
512#[cfg(feature = "crypto")]
513impl TryFrom<Vec<u8>> for KeyPair {
514	type Error = Error;
515
516	fn try_from(key: Vec<u8>) -> Result<KeyPair, Error> {
517		let key = &PrivateKeyDer::try_from(key).map_err(|_| Error::CouldNotParseKeyPair)?;
518
519		key.try_into()
520	}
521}
522
523#[cfg(feature = "crypto")]
524impl TryFrom<&PrivatePkcs8KeyDer<'_>> for KeyPair {
525	type Error = Error;
526
527	fn try_from(key: &PrivatePkcs8KeyDer) -> Result<KeyPair, Error> {
528		key.secret_pkcs8_der().try_into()
529	}
530}
531
532#[cfg(feature = "crypto")]
533impl TryFrom<&PrivateKeyDer<'_>> for KeyPair {
534	type Error = Error;
535
536	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		let (kind, alg) = {
567			let is_pkcs8 = matches!(key, PrivateKeyDer::Pkcs8(_));
568
569			let key = key.secret_der();
570
571			let rsa_key_pair_from = if is_pkcs8 {
572				RsaKeyPair::from_pkcs8
573			} else {
574				RsaKeyPair::from_der
575			};
576
577			let (kind, alg) = if let Ok(edkp) = Ed25519KeyPair::from_pkcs8_maybe_unchecked(key) {
578				(KeyPairKind::Ed(edkp), &PKCS_ED25519)
579			} else if let Ok(eckp) =
580				ecdsa_from_private_key_der(&signature::ECDSA_P256_SHA256_ASN1_SIGNING, key)
581			{
582				(KeyPairKind::Ec(eckp), &PKCS_ECDSA_P256_SHA256)
583			} else if let Ok(eckp) =
584				ecdsa_from_private_key_der(&signature::ECDSA_P384_SHA384_ASN1_SIGNING, key)
585			{
586				(KeyPairKind::Ec(eckp), &PKCS_ECDSA_P384_SHA384)
587			} else if let Ok(eckp) =
588				ecdsa_from_private_key_der(&signature::ECDSA_P521_SHA512_ASN1_SIGNING, key)
589			{
590				(KeyPairKind::Ec(eckp), &PKCS_ECDSA_P521_SHA512)
591			} else if let Ok(rsakp) = rsa_key_pair_from(key) {
592				(
593					KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256),
594					&PKCS_RSA_SHA256,
595				)
596			} else {
597				return Err(Error::CouldNotParseKeyPair);
598			};
599			(kind, alg)
600		};
601
602		Ok(KeyPair {
603			kind,
604			alg,
605			serialized_der: key.secret_der().into(),
606		})
607	}
608}
609
610#[cfg(feature = "crypto")]
611impl From<KeyPair> for PrivatePkcs8KeyDer<'static> {
612	fn from(val: KeyPair) -> Self {
613		val.serialize_der().into()
614	}
615}
616
617#[cfg(feature = "crypto")]
618impl From<KeyPair> for PrivateKeyDer<'static> {
619	fn from(val: KeyPair) -> Self {
620		Self::from(PrivatePkcs8KeyDer::from(val))
621	}
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]
628pub enum RsaKeySize {
629	/// 2048 bits
630	_2048,
631	/// 3072 bits
632	_3072,
633	/// 4096 bits
634	_4096,
635}
636
637pub(crate) fn sign_der(
638	key: &impl SigningKey,
639	f: impl FnOnce(&mut DERWriterSeq<'_>) -> Result<(), Error>,
640) -> Result<Vec<u8>, Error> {
641	yasna::try_construct_der(|writer| {
642		writer.write_sequence(|writer| {
643			let data = yasna::try_construct_der(|writer| writer.write_sequence(f))?;
644			writer.next().write_der(&data);
645
646			// Write signatureAlgorithm
647			key.algorithm().write_alg_ident(writer.next());
648
649			// Write signature
650			let sig = key.sign(&data)?;
651			let writer = writer.next();
652			writer.write_bitvec_bytes(&sig, sig.len() * 8);
653
654			Ok(())
655		})
656	})
657}
658
659impl<S: SigningKey + ?Sized> SigningKey for &S {
660	fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error> {
661		(*self).sign(msg)
662	}
663}
664
665/// A key that can be used to sign messages
666pub 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")]
672impl<T> ExternalError<T> for Result<T, ring_error::KeyRejected> {
673	fn _err(self) -> Result<T, Error> {
674		self.map_err(|e| Error::RingKeyRejected(e.to_string()))
675	}
676}
677
678#[cfg(feature = "crypto")]
679impl<T> ExternalError<T> for Result<T, ring_error::Unspecified> {
680	fn _err(self) -> Result<T, Error> {
681		self.map_err(|_| Error::RingUnspecified)
682	}
683}
684
685#[cfg(feature = "pem")]
686impl<T> ExternalError<T> for Result<T, pem::PemError> {
687	fn _err(self) -> Result<T, Error> {
688		self.map_err(|e| Error::PemError(e.to_string()))
689	}
690}
691
692/// A public key
693#[derive(Clone, Debug, Eq, PartialEq)]
694pub struct SubjectPublicKeyInfo {
695	pub(crate) alg: &'static SignatureAlgorithm,
696	pub(crate) subject_public_key: Vec<u8>,
697}
698
699impl 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
742impl PublicKeyData for SubjectPublicKeyInfo {
743	fn der_bytes(&self) -> &[u8] {
744		&self.subject_public_key
745	}
746
747	fn algorithm(&self) -> &'static SignatureAlgorithm {
748		self.alg
749	}
750}
751
752impl<K: PublicKeyData + ?Sized> PublicKeyData for &K {
753	fn der_bytes(&self) -> &[u8] {
754		(*self).der_bytes()
755	}
756
757	fn algorithm(&self) -> &'static SignatureAlgorithm {
758		(*self).algorithm()
759	}
760}
761
762/// The public key data of a key pair
763pub 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	fn subject_public_key_info(&self) -> Vec<u8> {
769		yasna::construct_der(|writer| serialize_public_key_der(self, writer))
770	}
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
779pub(crate) fn serialize_public_key_der(key: &(impl PublicKeyData + ?Sized), writer: DERWriter) {
780	writer.write_sequence(|writer| {
781		key.algorithm().write_oids_sign_alg(writer.next());
782		let pk = key.der_bytes();
783		writer.next().write_bitvec_bytes(pk, pk.len() * 8);
784	})
785}
786
787#[cfg(all(test, feature = "crypto"))]
788mod 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}