1 //! X509 Certificate builder
2 
3 use alloc::vec;
4 use core::fmt;
5 use der::{asn1::BitString, referenced::OwnedToRef, Encode};
6 use signature::{rand_core::CryptoRngCore, Keypair, RandomizedSigner, Signer};
7 use spki::{
8     DynSignatureAlgorithmIdentifier, EncodePublicKey, SignatureBitStringEncoding,
9     SubjectPublicKeyInfoOwned, SubjectPublicKeyInfoRef,
10 };
11 
12 use crate::{
13     certificate::{Certificate, TbsCertificate, Version},
14     ext::{
15         pkix::{
16             AuthorityKeyIdentifier, BasicConstraints, KeyUsage, KeyUsages, SubjectKeyIdentifier,
17         },
18         AsExtension, Extension, Extensions,
19     },
20     name::Name,
21     request::{attributes::AsAttribute, CertReq, CertReqInfo, ExtensionReq},
22     serial_number::SerialNumber,
23     time::Validity,
24 };
25 
26 /// Error type
27 #[derive(Debug)]
28 #[non_exhaustive]
29 pub enum Error {
30     /// ASN.1 DER-related errors.
31     Asn1(der::Error),
32 
33     /// Public key errors propagated from the [`spki::Error`] type.
34     PublicKey(spki::Error),
35 
36     /// Signing error propagated for the [`signature::Error`] type.
37     Signature(signature::Error),
38 }
39 
40 #[cfg(feature = "std")]
41 impl std::error::Error for Error {}
42 
43 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result44     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45         match self {
46             Error::Asn1(err) => write!(f, "ASN.1 error: {}", err),
47             Error::PublicKey(err) => write!(f, "public key error: {}", err),
48             Error::Signature(err) => write!(f, "signature error: {}", err),
49         }
50     }
51 }
52 
53 impl From<der::Error> for Error {
from(err: der::Error) -> Error54     fn from(err: der::Error) -> Error {
55         Error::Asn1(err)
56     }
57 }
58 
59 impl From<spki::Error> for Error {
from(err: spki::Error) -> Error60     fn from(err: spki::Error) -> Error {
61         Error::PublicKey(err)
62     }
63 }
64 
65 impl From<signature::Error> for Error {
from(err: signature::Error) -> Error66     fn from(err: signature::Error) -> Error {
67         Error::Signature(err)
68     }
69 }
70 
71 type Result<T> = core::result::Result<T, Error>;
72 
73 /// The type of certificate to build
74 #[derive(Clone, Debug, Eq, PartialEq)]
75 pub enum Profile {
76     /// Build a root CA certificate
77     Root,
78     /// Build an intermediate sub CA certificate
79     SubCA {
80         /// issuer   Name,
81         /// represents the name signing the certificate
82         issuer: Name,
83         /// pathLenConstraint       INTEGER (0..MAX) OPTIONAL
84         /// BasicConstraints as defined in [RFC 5280 Section 4.2.1.9].
85         path_len_constraint: Option<u8>,
86     },
87     /// Build an end certificate
88     Leaf {
89         /// issuer   Name,
90         /// represents the name signing the certificate
91         issuer: Name,
92         /// should the key agreement flag of KeyUsage be enabled
93         enable_key_agreement: bool,
94         /// should the key encipherment flag of KeyUsage be enabled
95         enable_key_encipherment: bool,
96         /// should the subject key identifier extension be included
97         ///
98         /// From [RFC 5280 Section 4.2.1.2]:
99         ///  For end entity certificates, subject key identifiers SHOULD be
100         ///  derived from the public key.  Two common methods for generating key
101         ///  identifiers from the public key are identified above.
102         #[cfg(feature = "hazmat")]
103         include_subject_key_identifier: bool,
104     },
105     #[cfg(feature = "hazmat")]
106     /// Opt-out of the default extensions
107     Manual {
108         /// issuer   Name,
109         /// represents the name signing the certificate
110         /// A `None` will make it a self-signed certificate
111         issuer: Option<Name>,
112     },
113 }
114 
115 impl Profile {
get_issuer(&self, subject: &Name) -> Name116     fn get_issuer(&self, subject: &Name) -> Name {
117         match self {
118             Profile::Root => subject.clone(),
119             Profile::SubCA { issuer, .. } => issuer.clone(),
120             Profile::Leaf { issuer, .. } => issuer.clone(),
121             #[cfg(feature = "hazmat")]
122             Profile::Manual { issuer, .. } => issuer.as_ref().unwrap_or(subject).clone(),
123         }
124     }
125 
build_extensions( &self, spk: SubjectPublicKeyInfoRef<'_>, issuer_spk: SubjectPublicKeyInfoRef<'_>, tbs: &TbsCertificate, ) -> Result<vec::Vec<Extension>>126     fn build_extensions(
127         &self,
128         spk: SubjectPublicKeyInfoRef<'_>,
129         issuer_spk: SubjectPublicKeyInfoRef<'_>,
130         tbs: &TbsCertificate,
131     ) -> Result<vec::Vec<Extension>> {
132         #[cfg(feature = "hazmat")]
133         // User opted out of default extensions set.
134         if let Profile::Manual { .. } = self {
135             return Ok(vec::Vec::default());
136         }
137 
138         let mut extensions: vec::Vec<Extension> = vec::Vec::new();
139 
140         match self {
141             #[cfg(feature = "hazmat")]
142             Profile::Leaf {
143                 include_subject_key_identifier: false,
144                 ..
145             } => {}
146             _ => extensions.push(
147                 SubjectKeyIdentifier::try_from(spk)?.to_extension(&tbs.subject, &extensions)?,
148             ),
149         }
150 
151         // Build Authority Key Identifier
152         match self {
153             Profile::Root => {}
154             _ => {
155                 extensions.push(
156                     AuthorityKeyIdentifier::try_from(issuer_spk.clone())?
157                         .to_extension(&tbs.subject, &extensions)?,
158                 );
159             }
160         }
161 
162         // Build Basic Contraints extensions
163         extensions.push(match self {
164             Profile::Root => BasicConstraints {
165                 ca: true,
166                 path_len_constraint: None,
167             }
168             .to_extension(&tbs.subject, &extensions)?,
169             Profile::SubCA {
170                 path_len_constraint,
171                 ..
172             } => BasicConstraints {
173                 ca: true,
174                 path_len_constraint: *path_len_constraint,
175             }
176             .to_extension(&tbs.subject, &extensions)?,
177             Profile::Leaf { .. } => BasicConstraints {
178                 ca: false,
179                 path_len_constraint: None,
180             }
181             .to_extension(&tbs.subject, &extensions)?,
182             #[cfg(feature = "hazmat")]
183             Profile::Manual { .. } => unreachable!(),
184         });
185 
186         // Build Key Usage extension
187         match self {
188             Profile::Root | Profile::SubCA { .. } => {
189                 extensions.push(
190                     KeyUsage(KeyUsages::KeyCertSign | KeyUsages::CRLSign)
191                         .to_extension(&tbs.subject, &extensions)?,
192                 );
193             }
194             Profile::Leaf {
195                 enable_key_agreement,
196                 enable_key_encipherment,
197                 ..
198             } => {
199                 let mut key_usage = KeyUsages::DigitalSignature | KeyUsages::NonRepudiation;
200                 if *enable_key_encipherment {
201                     key_usage |= KeyUsages::KeyEncipherment;
202                 }
203                 if *enable_key_agreement {
204                     key_usage |= KeyUsages::KeyAgreement;
205                 }
206 
207                 extensions.push(KeyUsage(key_usage).to_extension(&tbs.subject, &extensions)?);
208             }
209             #[cfg(feature = "hazmat")]
210             Profile::Manual { .. } => unreachable!(),
211         }
212 
213         Ok(extensions)
214     }
215 }
216 
217 /// X509 Certificate builder
218 ///
219 /// ```
220 /// use der::Decode;
221 /// use x509_cert::spki::SubjectPublicKeyInfoOwned;
222 /// use x509_cert::builder::{CertificateBuilder, Profile};
223 /// use x509_cert::name::Name;
224 /// use x509_cert::serial_number::SerialNumber;
225 /// use x509_cert::time::Validity;
226 /// use std::str::FromStr;
227 ///
228 /// # const RSA_2048_DER: &[u8] = include_bytes!("../tests/examples/rsa2048-pub.der");
229 /// # const RSA_2048_PRIV_DER: &[u8] = include_bytes!("../tests/examples/rsa2048-priv.der");
230 /// # use rsa::{pkcs1v15::SigningKey, pkcs1::DecodeRsaPrivateKey};
231 /// # use sha2::Sha256;
232 /// # use std::time::Duration;
233 /// # use der::referenced::RefToOwned;
234 /// # fn rsa_signer() -> SigningKey<Sha256> {
235 /// #     let private_key = rsa::RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER).unwrap();
236 /// #     let signing_key = SigningKey::<Sha256>::new_with_prefix(private_key);
237 /// #     signing_key
238 /// # }
239 ///
240 /// let serial_number = SerialNumber::from(42u32);
241 /// let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
242 /// let profile = Profile::Root;
243 /// let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
244 ///
245 /// let pub_key = SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER).expect("get rsa pub key");
246 ///
247 /// let mut signer = rsa_signer();
248 /// let mut builder = CertificateBuilder::new(
249 ///     profile,
250 ///     serial_number,
251 ///     validity,
252 ///     subject,
253 ///     pub_key,
254 ///     &signer,
255 /// )
256 /// .expect("Create certificate");
257 /// ```
258 pub struct CertificateBuilder<'s, S> {
259     tbs: TbsCertificate,
260     extensions: Extensions,
261     cert_signer: &'s S,
262 }
263 
264 impl<'s, S> CertificateBuilder<'s, S>
265 where
266     S: Keypair + DynSignatureAlgorithmIdentifier,
267     S::VerifyingKey: EncodePublicKey,
268 {
269     /// Creates a new certificate builder
new( profile: Profile, serial_number: SerialNumber, mut validity: Validity, subject: Name, subject_public_key_info: SubjectPublicKeyInfoOwned, cert_signer: &'s S, ) -> Result<Self>270     pub fn new(
271         profile: Profile,
272         serial_number: SerialNumber,
273         mut validity: Validity,
274         subject: Name,
275         subject_public_key_info: SubjectPublicKeyInfoOwned,
276         cert_signer: &'s S,
277     ) -> Result<Self> {
278         let verifying_key = cert_signer.verifying_key();
279         let signer_pub = verifying_key
280             .to_public_key_der()?
281             .decode_msg::<SubjectPublicKeyInfoOwned>()?;
282 
283         let signature_alg = cert_signer.signature_algorithm_identifier()?;
284         let issuer = profile.get_issuer(&subject);
285 
286         validity.not_before.rfc5280_adjust_utc_time()?;
287         validity.not_after.rfc5280_adjust_utc_time()?;
288 
289         let tbs = TbsCertificate {
290             version: Version::V3,
291             serial_number,
292             signature: signature_alg,
293             issuer,
294             validity,
295             subject,
296             subject_public_key_info,
297             extensions: None,
298 
299             // We will not generate unique identifier because as per RFC5280 Section 4.1.2.8:
300             //   CAs conforming to this profile MUST NOT generate
301             //   certificates with unique identifiers.
302             //
303             // https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.8
304             issuer_unique_id: None,
305             subject_unique_id: None,
306         };
307 
308         let extensions = profile.build_extensions(
309             tbs.subject_public_key_info.owned_to_ref(),
310             signer_pub.owned_to_ref(),
311             &tbs,
312         )?;
313         Ok(Self {
314             tbs,
315             extensions,
316             cert_signer,
317         })
318     }
319 
320     /// Add an extension to this certificate
add_extension<E: AsExtension>(&mut self, extension: &E) -> Result<()>321     pub fn add_extension<E: AsExtension>(&mut self, extension: &E) -> Result<()> {
322         let ext = extension.to_extension(&self.tbs.subject, &self.extensions)?;
323         self.extensions.push(ext);
324 
325         Ok(())
326     }
327 }
328 
329 /// Builder for X509 Certificate Requests
330 ///
331 /// ```
332 /// # use p256::{pkcs8::DecodePrivateKey, NistP256, ecdsa::DerSignature};
333 /// # const PKCS8_PRIVATE_KEY_DER: &[u8] = include_bytes!("../tests/examples/p256-priv.der");
334 /// # fn ecdsa_signer() -> ecdsa::SigningKey<NistP256> {
335 /// #     let secret_key = p256::SecretKey::from_pkcs8_der(PKCS8_PRIVATE_KEY_DER).unwrap();
336 /// #     ecdsa::SigningKey::from(secret_key)
337 /// # }
338 /// use x509_cert::{
339 ///     builder::{Builder, RequestBuilder},
340 ///     ext::pkix::{name::GeneralName, SubjectAltName},
341 ///     name::Name,
342 /// };
343 /// use std::str::FromStr;
344 ///
345 /// use std::net::{IpAddr, Ipv4Addr};
346 /// let subject = Name::from_str("CN=service.domination.world").unwrap();
347 ///
348 /// let signer = ecdsa_signer();
349 /// let mut builder = RequestBuilder::new(subject, &signer).expect("Create certificate request");
350 /// builder
351 ///     .add_extension(&SubjectAltName(vec![GeneralName::from(IpAddr::V4(
352 ///         Ipv4Addr::new(192, 0, 2, 0),
353 ///     ))]))
354 ///     .unwrap();
355 ///
356 /// let cert_req = builder.build::<DerSignature>().unwrap();
357 /// ```
358 pub struct RequestBuilder<'s, S> {
359     info: CertReqInfo,
360     extension_req: ExtensionReq,
361     req_signer: &'s S,
362 }
363 
364 impl<'s, S> RequestBuilder<'s, S>
365 where
366     S: Keypair + DynSignatureAlgorithmIdentifier,
367     S::VerifyingKey: EncodePublicKey,
368 {
369     /// Creates a new certificate request builder
new(subject: Name, req_signer: &'s S) -> Result<Self>370     pub fn new(subject: Name, req_signer: &'s S) -> Result<Self> {
371         let version = Default::default();
372         let verifying_key = req_signer.verifying_key();
373         let public_key = verifying_key
374             .to_public_key_der()?
375             .decode_msg::<SubjectPublicKeyInfoOwned>()?;
376         let attributes = Default::default();
377         let extension_req = Default::default();
378 
379         Ok(Self {
380             info: CertReqInfo {
381                 version,
382                 subject,
383                 public_key,
384                 attributes,
385             },
386             extension_req,
387             req_signer,
388         })
389     }
390 
391     /// Add an extension to this certificate request
add_extension<E: AsExtension>(&mut self, extension: &E) -> Result<()>392     pub fn add_extension<E: AsExtension>(&mut self, extension: &E) -> Result<()> {
393         let ext = extension.to_extension(&self.info.subject, &self.extension_req.0)?;
394 
395         self.extension_req.0.push(ext);
396 
397         Ok(())
398     }
399 
400     /// Add an attribute to this certificate request
add_attribute<A: AsAttribute>(&mut self, attribute: &A) -> Result<()>401     pub fn add_attribute<A: AsAttribute>(&mut self, attribute: &A) -> Result<()> {
402         let attr = attribute.to_attribute()?;
403 
404         self.info.attributes.insert(attr)?;
405         Ok(())
406     }
407 }
408 
409 /// Trait for X509 builders
410 ///
411 /// This trait defines the interface between builder and the signers.
412 pub trait Builder: Sized {
413     /// The builder's object signer
414     type Signer;
415 
416     /// Type built by this builder
417     type Output: Sized;
418 
419     /// Return a reference to the signer.
signer(&self) -> &Self::Signer420     fn signer(&self) -> &Self::Signer;
421 
422     /// Assemble the final object from signature.
assemble(self, signature: BitString) -> Result<Self::Output>423     fn assemble(self, signature: BitString) -> Result<Self::Output>;
424 
425     /// Finalize and return a serialization of the object for signature.
finalize(&mut self) -> der::Result<vec::Vec<u8>>426     fn finalize(&mut self) -> der::Result<vec::Vec<u8>>;
427 
428     /// Run the object through the signer and build it.
build<Signature>(mut self) -> Result<Self::Output> where Self::Signer: Signer<Signature>, Signature: SignatureBitStringEncoding,429     fn build<Signature>(mut self) -> Result<Self::Output>
430     where
431         Self::Signer: Signer<Signature>,
432         Signature: SignatureBitStringEncoding,
433     {
434         let blob = self.finalize()?;
435 
436         let signature = self.signer().try_sign(&blob)?.to_bitstring()?;
437 
438         self.assemble(signature)
439     }
440 
441     /// Run the object through the signer and build it.
build_with_rng<Signature>(mut self, rng: &mut impl CryptoRngCore) -> Result<Self::Output> where Self::Signer: RandomizedSigner<Signature>, Signature: SignatureBitStringEncoding,442     fn build_with_rng<Signature>(mut self, rng: &mut impl CryptoRngCore) -> Result<Self::Output>
443     where
444         Self::Signer: RandomizedSigner<Signature>,
445         Signature: SignatureBitStringEncoding,
446     {
447         let blob = self.finalize()?;
448 
449         let signature = self
450             .signer()
451             .try_sign_with_rng(rng, &blob)?
452             .to_bitstring()?;
453 
454         self.assemble(signature)
455     }
456 }
457 
458 impl<'s, S> Builder for CertificateBuilder<'s, S>
459 where
460     S: Keypair + DynSignatureAlgorithmIdentifier,
461     S::VerifyingKey: EncodePublicKey,
462 {
463     type Signer = S;
464     type Output = Certificate;
465 
signer(&self) -> &Self::Signer466     fn signer(&self) -> &Self::Signer {
467         self.cert_signer
468     }
469 
finalize(&mut self) -> der::Result<vec::Vec<u8>>470     fn finalize(&mut self) -> der::Result<vec::Vec<u8>> {
471         if !self.extensions.is_empty() {
472             self.tbs.extensions = Some(self.extensions.clone());
473         }
474 
475         if self.tbs.extensions.is_none() {
476             if self.tbs.issuer_unique_id.is_some() || self.tbs.subject_unique_id.is_some() {
477                 self.tbs.version = Version::V2;
478             } else {
479                 self.tbs.version = Version::V1;
480             }
481         }
482 
483         self.tbs.to_der()
484     }
485 
assemble(self, signature: BitString) -> Result<Self::Output>486     fn assemble(self, signature: BitString) -> Result<Self::Output> {
487         let signature_algorithm = self.tbs.signature.clone();
488 
489         Ok(Certificate {
490             tbs_certificate: self.tbs,
491             signature_algorithm,
492             signature,
493         })
494     }
495 }
496 
497 impl<'s, S> Builder for RequestBuilder<'s, S>
498 where
499     S: Keypair + DynSignatureAlgorithmIdentifier,
500     S::VerifyingKey: EncodePublicKey,
501 {
502     type Signer = S;
503     type Output = CertReq;
504 
signer(&self) -> &Self::Signer505     fn signer(&self) -> &Self::Signer {
506         self.req_signer
507     }
508 
finalize(&mut self) -> der::Result<vec::Vec<u8>>509     fn finalize(&mut self) -> der::Result<vec::Vec<u8>> {
510         self.info
511             .attributes
512             .insert(self.extension_req.clone().try_into()?)?;
513 
514         self.info.to_der()
515     }
516 
assemble(self, signature: BitString) -> Result<Self::Output>517     fn assemble(self, signature: BitString) -> Result<Self::Output> {
518         let algorithm = self.req_signer.signature_algorithm_identifier()?;
519 
520         Ok(CertReq {
521             info: self.info,
522             algorithm,
523             signature,
524         })
525     }
526 }
527