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