rcgen/
csr.rs

1use std::hash::Hash;
2
3#[cfg(feature = "pem")]
4use pem::Pem;
5use pki_types::CertificateSigningRequestDer;
6
7#[cfg(feature = "pem")]
8use crate::ENCODE_CONFIG;
9use crate::{
10	key_pair::serialize_public_key_der, Certificate, CertificateParams, Error, Issuer, KeyPair,
11	PublicKeyData, SignatureAlgorithm,
12};
13#[cfg(feature = "x509-parser")]
14use crate::{DistinguishedName, SanType};
15
16/// A public key, extracted from a CSR
17#[derive(Debug, PartialEq, Eq, Hash)]
18pub struct PublicKey {
19	raw: Vec<u8>,
20	alg: &'static SignatureAlgorithm,
21}
22
23impl PublicKey {
24	/// The algorithm used to generate the public key and sign the CSR.
25	pub fn algorithm(&self) -> &SignatureAlgorithm {
26		self.alg
27	}
28}
29
30impl PublicKeyData for PublicKey {
31	fn der_bytes(&self) -> &[u8] {
32		&self.raw
33	}
34
35	fn algorithm(&self) -> &SignatureAlgorithm {
36		self.alg
37	}
38}
39
40/// A certificate signing request (CSR) that can be encoded to PEM or DER.
41pub struct CertificateSigningRequest {
42	pub(crate) der: CertificateSigningRequestDer<'static>,
43}
44
45impl CertificateSigningRequest {
46	/// Get the PEM-encoded bytes of the certificate signing request.
47	#[cfg(feature = "pem")]
48	pub fn pem(&self) -> Result<String, Error> {
49		let p = Pem::new("CERTIFICATE REQUEST", &*self.der);
50		Ok(pem::encode_config(&p, ENCODE_CONFIG))
51	}
52
53	/// Get the DER-encoded bytes of the certificate signing request.
54	///
55	/// [`CertificateSigningRequestDer`] implements `Deref<Target = [u8]>` and `AsRef<[u8]>`,
56	/// so you can easily extract the DER bytes from the return value.
57	pub fn der(&self) -> &CertificateSigningRequestDer<'static> {
58		&self.der
59	}
60}
61
62impl From<CertificateSigningRequest> for CertificateSigningRequestDer<'static> {
63	fn from(csr: CertificateSigningRequest) -> Self {
64		csr.der
65	}
66}
67
68/// Parameters for a certificate signing request
69pub struct CertificateSigningRequestParams {
70	/// Parameters for the certificate to be signed.
71	pub params: CertificateParams,
72	/// Public key to include in the certificate signing request.
73	pub public_key: PublicKey,
74}
75
76impl CertificateSigningRequestParams {
77	/// Parse a certificate signing request from the ASCII PEM format
78	///
79	/// See [`from_der`](Self::from_der) for more details.
80	#[cfg(all(feature = "pem", feature = "x509-parser"))]
81	pub fn from_pem(pem_str: &str) -> Result<Self, Error> {
82		let csr = pem::parse(pem_str).or(Err(Error::CouldNotParseCertificationRequest))?;
83		Self::from_der(&csr.contents().into())
84	}
85
86	/// Parse a certificate signing request from DER-encoded bytes
87	///
88	/// Currently, this only supports the `Subject Alternative Name` extension.
89	/// On encountering other extensions, this function will return an error.
90	///
91	/// [`rustls_pemfile::csr()`] is often used to obtain a [`CertificateSigningRequestDer`] from
92	/// PEM input. If you already have a byte slice containing DER, it can trivially be converted
93	/// into [`CertificateSigningRequestDer`] using the [`Into`] trait.
94	///
95	/// [`rustls_pemfile::csr()`]: https://docs.rs/rustls-pemfile/latest/rustls_pemfile/fn.csr.html
96	#[cfg(feature = "x509-parser")]
97	pub fn from_der(csr: &CertificateSigningRequestDer<'_>) -> Result<Self, Error> {
98		use crate::KeyUsagePurpose;
99		use x509_parser::prelude::FromDer;
100
101		let csr = x509_parser::certification_request::X509CertificationRequest::from_der(csr)
102			.map_err(|_| Error::CouldNotParseCertificationRequest)?
103			.1;
104		csr.verify_signature().map_err(|_| Error::RingUnspecified)?;
105		let alg_oid = csr
106			.signature_algorithm
107			.algorithm
108			.iter()
109			.ok_or(Error::CouldNotParseCertificationRequest)?
110			.collect::<Vec<_>>();
111		let alg = SignatureAlgorithm::from_oid(&alg_oid)?;
112
113		let info = &csr.certification_request_info;
114		let mut params = CertificateParams {
115			distinguished_name: DistinguishedName::from_name(&info.subject)?,
116			..CertificateParams::default()
117		};
118		let raw = info.subject_pki.subject_public_key.data.to_vec();
119
120		if let Some(extensions) = csr.requested_extensions() {
121			for ext in extensions {
122				match ext {
123					x509_parser::extensions::ParsedExtension::KeyUsage(key_usage) => {
124						// This x509 parser stores flags in reversed bit BIT STRING order
125						params.key_usages =
126							KeyUsagePurpose::from_u16(key_usage.flags.reverse_bits());
127					},
128					x509_parser::extensions::ParsedExtension::SubjectAlternativeName(san) => {
129						for name in &san.general_names {
130							params
131								.subject_alt_names
132								.push(SanType::try_from_general(name)?);
133						}
134					},
135					x509_parser::extensions::ParsedExtension::ExtendedKeyUsage(eku) => {
136						if eku.any {
137							params.insert_extended_key_usage(crate::ExtendedKeyUsagePurpose::Any);
138						}
139						if eku.server_auth {
140							params.insert_extended_key_usage(
141								crate::ExtendedKeyUsagePurpose::ServerAuth,
142							);
143						}
144						if eku.client_auth {
145							params.insert_extended_key_usage(
146								crate::ExtendedKeyUsagePurpose::ClientAuth,
147							);
148						}
149						if eku.code_signing {
150							params.insert_extended_key_usage(
151								crate::ExtendedKeyUsagePurpose::CodeSigning,
152							);
153						}
154						if eku.email_protection {
155							params.insert_extended_key_usage(
156								crate::ExtendedKeyUsagePurpose::EmailProtection,
157							);
158						}
159						if eku.time_stamping {
160							params.insert_extended_key_usage(
161								crate::ExtendedKeyUsagePurpose::TimeStamping,
162							);
163						}
164						if eku.ocsp_signing {
165							params.insert_extended_key_usage(
166								crate::ExtendedKeyUsagePurpose::OcspSigning,
167							);
168						}
169						if !eku.other.is_empty() {
170							return Err(Error::UnsupportedExtension);
171						}
172					},
173					_ => return Err(Error::UnsupportedExtension),
174				}
175			}
176		}
177
178		// Not yet handled:
179		// * is_ca
180		// * extended_key_usages
181		// * name_constraints
182		// and any other extensions.
183
184		Ok(Self {
185			params,
186			public_key: PublicKey { alg, raw },
187		})
188	}
189
190	/// Generate a new certificate based on the requested parameters, signed by the provided
191	/// issuer.
192	///
193	/// The returned certificate will have its issuer field set to the subject of the provided
194	/// `issuer`, and the authority key identifier extension will be populated using the subject
195	/// public key of `issuer`. It will be signed by `issuer_key`.
196	///
197	/// Note that no validation of the `issuer` certificate is performed. Rcgen will not require
198	/// the certificate to be a CA certificate, or have key usage extensions that allow signing.
199	///
200	/// The returned [`Certificate`] may be serialized using [`Certificate::der`] and
201	/// [`Certificate::pem`].
202	pub fn signed_by(
203		self,
204		issuer: &Certificate,
205		issuer_key: &KeyPair,
206	) -> Result<Certificate, Error> {
207		let issuer = Issuer {
208			distinguished_name: &issuer.params.distinguished_name,
209			key_identifier_method: &issuer.params.key_identifier_method,
210			key_usages: &issuer.params.key_usages,
211			key_pair: issuer_key,
212		};
213
214		let der = self
215			.params
216			.serialize_der_with_signer(&self.public_key, issuer)?;
217		let subject_public_key_info = yasna::construct_der(|writer| {
218			serialize_public_key_der(&self.public_key, writer);
219		});
220		Ok(Certificate {
221			params: self.params,
222			subject_public_key_info,
223			der,
224		})
225	}
226}