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 Certificate, CertificateParams, Error, Issuer, PublicKeyData, SignatureAlgorithm, SigningKey,
11};
12#[cfg(feature = "x509-parser")]
13use crate::{DistinguishedName, ExtendedKeyUsagePurpose, IsCa, KeyUsagePurpose, SanType};
14
15#[derive(Clone, Debug, PartialEq, Eq, Hash)]
17pub struct PublicKey {
18 raw: Vec<u8>,
19 alg: &'static SignatureAlgorithm,
20}
21
22impl PublicKey {
23 pub fn algorithm(&self) -> &SignatureAlgorithm {
25 self.alg
26 }
27}
28
29impl PublicKeyData for PublicKey {
30 fn der_bytes(&self) -> &[u8] {
31 &self.raw
32 }
33
34 fn algorithm(&self) -> &'static SignatureAlgorithm {
35 self.alg
36 }
37}
38
39#[derive(Clone, Debug, PartialEq, Eq)]
41pub struct CertificateSigningRequest {
42 pub(crate) der: CertificateSigningRequestDer<'static>,
43}
44
45impl CertificateSigningRequest {
46 #[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 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#[derive(Clone, Debug, PartialEq, Eq)]
70pub struct CertificateSigningRequestParams {
71 pub params: CertificateParams,
73 pub public_key: PublicKey,
75}
76
77impl CertificateSigningRequestParams {
78 #[cfg(all(feature = "pem", feature = "x509-parser"))]
82 pub fn from_pem(pem_str: &str) -> Result<Self, Error> {
83 let csr = pem::parse(pem_str).map_err(|_| Error::CouldNotParseCertificationRequest)?;
84 Self::from_der(&csr.contents().into())
85 }
86
87 #[cfg(feature = "x509-parser")]
105 pub fn from_der(csr: &CertificateSigningRequestDer<'_>) -> Result<Self, Error> {
106 use x509_parser::prelude::FromDer;
107
108 let csr = x509_parser::certification_request::X509CertificationRequest::from_der(csr)
109 .map_err(|_| Error::CouldNotParseCertificationRequest)?
110 .1;
111 csr.verify_signature()
112 .map_err(|_| Error::InvalidCertificationRequestSignature)?;
113 let alg_oid = csr
114 .signature_algorithm
115 .algorithm
116 .iter()
117 .ok_or(Error::CouldNotParseCertificationRequest)?
118 .collect::<Vec<_>>();
119 let alg = SignatureAlgorithm::from_oid(&alg_oid)?;
120
121 let info = &csr.certification_request_info;
122 let mut params = CertificateParams {
123 distinguished_name: DistinguishedName::from_name(&info.subject)?,
124 ..CertificateParams::default()
125 };
126 let raw = info.subject_pki.subject_public_key.data.to_vec();
127
128 if let Some(extensions) = csr.requested_extensions() {
129 for ext in extensions {
130 match ext {
131 x509_parser::extensions::ParsedExtension::KeyUsage(key_usage) => {
132 params.key_usages =
134 KeyUsagePurpose::from_u16(key_usage.flags.reverse_bits());
135 },
136 x509_parser::extensions::ParsedExtension::SubjectAlternativeName(san) => {
137 for name in &san.general_names {
138 params
139 .subject_alt_names
140 .push(SanType::try_from_general(name)?);
141 }
142 },
143 x509_parser::extensions::ParsedExtension::ExtendedKeyUsage(eku) => {
144 if eku.any {
145 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::Any);
146 }
147 if eku.server_auth {
148 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::ServerAuth);
149 }
150 if eku.client_auth {
151 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::ClientAuth);
152 }
153 if eku.code_signing {
154 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::CodeSigning);
155 }
156 if eku.email_protection {
157 params.insert_extended_key_usage(
158 ExtendedKeyUsagePurpose::EmailProtection,
159 );
160 }
161 if eku.time_stamping {
162 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::TimeStamping);
163 }
164 if eku.ocsp_signing {
165 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::OcspSigning);
166 }
167 if !eku.other.is_empty() {
168 return Err(Error::UnsupportedExtension);
169 }
170 },
171 x509_parser::extensions::ParsedExtension::BasicConstraints(bc) => {
172 params.is_ca = IsCa::from_basic_constraints(bc)?;
173 },
174 _ => return Err(Error::UnsupportedExtension),
175 }
176 }
177 }
178
179 Ok(Self {
184 params,
185 public_key: PublicKey { alg, raw },
186 })
187 }
188
189 pub fn signed_by(&self, issuer: &Issuer<impl SigningKey>) -> Result<Certificate, Error> {
202 Ok(Certificate {
203 der: self
204 .params
205 .serialize_der_with_signer(&self.public_key, issuer)?,
206 })
207 }
208}
209
210#[cfg(all(test, feature = "x509-parser"))]
211mod tests {
212 use x509_parser::certification_request::X509CertificationRequest;
213 use x509_parser::prelude::{FromDer, ParsedExtension};
214
215 use crate::{
216 BasicConstraints, CertificateParams, CertificateSigningRequestParams,
217 ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose,
218 };
219
220 #[test]
221 fn dont_write_sans_extension_if_no_sans_are_present() {
222 let mut params = CertificateParams::default();
223 params.key_usages.push(KeyUsagePurpose::DigitalSignature);
224 let key_pair = KeyPair::generate().unwrap();
225 let csr = params.serialize_request(&key_pair).unwrap();
226 let (_, parsed_csr) = X509CertificationRequest::from_der(csr.der()).unwrap();
227 assert!(!parsed_csr
228 .requested_extensions()
229 .unwrap()
230 .any(|ext| matches!(ext, ParsedExtension::SubjectAlternativeName(_))));
231 }
232
233 #[test]
234 fn write_extension_request_if_ekus_are_present() {
235 let mut params = CertificateParams::default();
236 params
237 .extended_key_usages
238 .push(ExtendedKeyUsagePurpose::ClientAuth);
239 let key_pair = KeyPair::generate().unwrap();
240 let csr = params.serialize_request(&key_pair).unwrap();
241 let (_, parsed_csr) = X509CertificationRequest::from_der(csr.der()).unwrap();
242 let requested_extensions = parsed_csr
243 .requested_extensions()
244 .unwrap()
245 .collect::<Vec<_>>();
246 assert!(matches!(
247 requested_extensions.first().unwrap(),
248 ParsedExtension::ExtendedKeyUsage(_)
249 ));
250 }
251
252 #[test]
253 fn write_basic_constraints_if_present() {
254 use x509_parser::extensions::BasicConstraints as B;
255
256 let params = CertificateParams {
257 is_ca: IsCa::ExplicitNoCa,
258 ..Default::default()
259 };
260 let key_pair = KeyPair::generate().unwrap();
261 let csr = params.serialize_request(&key_pair).unwrap();
262 let (_, parsed_csr) = X509CertificationRequest::from_der(csr.der()).unwrap();
263 let requested_extensions = parsed_csr
264 .requested_extensions()
265 .unwrap()
266 .collect::<Vec<_>>();
267
268 assert!(matches!(
269 requested_extensions.first().unwrap(),
270 ParsedExtension::BasicConstraints(B {
271 ca: false,
272 path_len_constraint: None
273 })
274 ));
275 }
276
277 #[test]
278 fn serialize_and_deserialize_eq_basic_constraints() {
279 let params = CertificateParams {
280 is_ca: IsCa::Ca(BasicConstraints::Constrained(10)),
281 ..Default::default()
282 };
283 let key_pair = KeyPair::generate().unwrap();
284 let csr = params.serialize_request(&key_pair).unwrap();
285 let csr_de = CertificateSigningRequestParams::from_der(csr.der()).unwrap();
286
287 assert_eq!(csr_de.params.is_ca, params.is_ca);
288 }
289}