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, 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")]
104 pub fn from_der(csr: &CertificateSigningRequestDer<'_>) -> Result<Self, Error> {
105 use x509_parser::prelude::FromDer;
106
107 let csr = x509_parser::certification_request::X509CertificationRequest::from_der(csr)
108 .map_err(|_| Error::CouldNotParseCertificationRequest)?
109 .1;
110 csr.verify_signature()
111 .map_err(|_| Error::InvalidCertificationRequestSignature)?;
112 let alg_oid = csr
113 .signature_algorithm
114 .algorithm
115 .iter()
116 .ok_or(Error::CouldNotParseCertificationRequest)?
117 .collect::<Vec<_>>();
118 let alg = SignatureAlgorithm::from_oid(&alg_oid)?;
119
120 let info = &csr.certification_request_info;
121 let mut params = CertificateParams {
122 distinguished_name: DistinguishedName::from_name(&info.subject)?,
123 ..CertificateParams::default()
124 };
125 let raw = info.subject_pki.subject_public_key.data.to_vec();
126
127 if let Some(extensions) = csr.requested_extensions() {
128 for ext in extensions {
129 match ext {
130 x509_parser::extensions::ParsedExtension::KeyUsage(key_usage) => {
131 params.key_usages =
133 KeyUsagePurpose::from_u16(key_usage.flags.reverse_bits());
134 },
135 x509_parser::extensions::ParsedExtension::SubjectAlternativeName(san) => {
136 for name in &san.general_names {
137 params
138 .subject_alt_names
139 .push(SanType::try_from_general(name)?);
140 }
141 },
142 x509_parser::extensions::ParsedExtension::ExtendedKeyUsage(eku) => {
143 if eku.any {
144 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::Any);
145 }
146 if eku.server_auth {
147 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::ServerAuth);
148 }
149 if eku.client_auth {
150 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::ClientAuth);
151 }
152 if eku.code_signing {
153 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::CodeSigning);
154 }
155 if eku.email_protection {
156 params.insert_extended_key_usage(
157 ExtendedKeyUsagePurpose::EmailProtection,
158 );
159 }
160 if eku.time_stamping {
161 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::TimeStamping);
162 }
163 if eku.ocsp_signing {
164 params.insert_extended_key_usage(ExtendedKeyUsagePurpose::OcspSigning);
165 }
166 if !eku.other.is_empty() {
167 return Err(Error::UnsupportedExtension);
168 }
169 },
170 _ => return Err(Error::UnsupportedExtension),
171 }
172 }
173 }
174
175 Ok(Self {
181 params,
182 public_key: PublicKey { alg, raw },
183 })
184 }
185
186 pub fn signed_by(&self, issuer: &Issuer<impl SigningKey>) -> Result<Certificate, Error> {
199 Ok(Certificate {
200 der: self
201 .params
202 .serialize_der_with_signer(&self.public_key, issuer)?,
203 })
204 }
205}
206
207#[cfg(all(test, feature = "x509-parser"))]
208mod tests {
209 use x509_parser::certification_request::X509CertificationRequest;
210 use x509_parser::prelude::{FromDer, ParsedExtension};
211
212 use crate::{CertificateParams, ExtendedKeyUsagePurpose, KeyPair, KeyUsagePurpose};
213
214 #[test]
215 fn dont_write_sans_extension_if_no_sans_are_present() {
216 let mut params = CertificateParams::default();
217 params.key_usages.push(KeyUsagePurpose::DigitalSignature);
218 let key_pair = KeyPair::generate().unwrap();
219 let csr = params.serialize_request(&key_pair).unwrap();
220 let (_, parsed_csr) = X509CertificationRequest::from_der(csr.der()).unwrap();
221 assert!(!parsed_csr
222 .requested_extensions()
223 .unwrap()
224 .any(|ext| matches!(ext, ParsedExtension::SubjectAlternativeName(_))));
225 }
226
227 #[test]
228 fn write_extension_request_if_ekus_are_present() {
229 let mut params = CertificateParams::default();
230 params
231 .extended_key_usages
232 .push(ExtendedKeyUsagePurpose::ClientAuth);
233 let key_pair = KeyPair::generate().unwrap();
234 let csr = params.serialize_request(&key_pair).unwrap();
235 let (_, parsed_csr) = X509CertificationRequest::from_der(csr.der()).unwrap();
236 let requested_extensions = parsed_csr
237 .requested_extensions()
238 .unwrap()
239 .collect::<Vec<_>>();
240 assert!(matches!(
241 requested_extensions.first().unwrap(),
242 ParsedExtension::ExtendedKeyUsage(_)
243 ));
244 }
245}