rcgen/
key_pair.rs

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