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