1use alloc::vec;
4use core::fmt;
5use der::{asn1::BitString, referenced::OwnedToRef, Encode};
6use signature::{rand_core::CryptoRngCore, Keypair, RandomizedSigner, Signer};
7use spki::{
8 DynSignatureAlgorithmIdentifier, EncodePublicKey, SignatureBitStringEncoding,
9 SubjectPublicKeyInfoOwned, SubjectPublicKeyInfoRef,
10};
11
12use 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#[derive(Debug)]
28#[non_exhaustive]
29pub enum Error {
30 Asn1(der::Error),
32
33 PublicKey(spki::Error),
35
36 Signature(signature::Error),
38}
39
40#[cfg(feature = "std")]
41impl std::error::Error for Error {}
42
43impl fmt::Display for Error {
44 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
53impl From<der::Error> for Error {
54 fn from(err: der::Error) -> Error {
55 Error::Asn1(err)
56 }
57}
58
59impl From<spki::Error> for Error {
60 fn from(err: spki::Error) -> Error {
61 Error::PublicKey(err)
62 }
63}
64
65impl From<signature::Error> for Error {
66 fn from(err: signature::Error) -> Error {
67 Error::Signature(err)
68 }
69}
70
71type Result<T> = core::result::Result<T, Error>;
72
73#[derive(Clone, Debug, Eq, PartialEq)]
75pub enum Profile {
76 Root,
78 SubCA {
80 issuer: Name,
83 path_len_constraint: Option<u8>,
86 },
87 Leaf {
89 issuer: Name,
92 enable_key_agreement: bool,
94 enable_key_encipherment: bool,
96 #[cfg(feature = "hazmat")]
103 include_subject_key_identifier: bool,
104 },
105 #[cfg(feature = "hazmat")]
106 Manual {
108 issuer: Option<Name>,
112 },
113}
114
115impl Profile {
116 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
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 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 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 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 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
217pub struct CertificateBuilder<'s, S> {
259 tbs: TbsCertificate,
260 extensions: Extensions,
261 cert_signer: &'s S,
262}
263
264impl<'s, S> CertificateBuilder<'s, S>
265where
266 S: Keypair + DynSignatureAlgorithmIdentifier,
267 S::VerifyingKey: EncodePublicKey,
268{
269 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 = SubjectPublicKeyInfoOwned::from_key(verifying_key)?;
280
281 let signature_alg = cert_signer.signature_algorithm_identifier()?;
282 let issuer = profile.get_issuer(&subject);
283
284 validity.not_before.rfc5280_adjust_utc_time()?;
285 validity.not_after.rfc5280_adjust_utc_time()?;
286
287 let tbs = TbsCertificate {
288 version: Version::V3,
289 serial_number,
290 signature: signature_alg,
291 issuer,
292 validity,
293 subject,
294 subject_public_key_info,
295 extensions: None,
296
297 issuer_unique_id: None,
303 subject_unique_id: None,
304 };
305
306 let extensions = profile.build_extensions(
307 tbs.subject_public_key_info.owned_to_ref(),
308 signer_pub.owned_to_ref(),
309 &tbs,
310 )?;
311 Ok(Self {
312 tbs,
313 extensions,
314 cert_signer,
315 })
316 }
317
318 pub fn add_extension<E: AsExtension>(&mut self, extension: &E) -> Result<()> {
320 let ext = extension.to_extension(&self.tbs.subject, &self.extensions)?;
321 self.extensions.push(ext);
322
323 Ok(())
324 }
325}
326
327pub struct RequestBuilder<'s, S> {
357 info: CertReqInfo,
358 extension_req: ExtensionReq,
359 req_signer: &'s S,
360}
361
362impl<'s, S> RequestBuilder<'s, S>
363where
364 S: Keypair + DynSignatureAlgorithmIdentifier,
365 S::VerifyingKey: EncodePublicKey,
366{
367 pub fn new(subject: Name, req_signer: &'s S) -> Result<Self> {
369 let version = Default::default();
370 let verifying_key = req_signer.verifying_key();
371 let public_key = SubjectPublicKeyInfoOwned::from_key(verifying_key)?;
372 let attributes = Default::default();
373 let extension_req = Default::default();
374
375 Ok(Self {
376 info: CertReqInfo {
377 version,
378 subject,
379 public_key,
380 attributes,
381 },
382 extension_req,
383 req_signer,
384 })
385 }
386
387 pub fn add_extension<E: AsExtension>(&mut self, extension: &E) -> Result<()> {
389 let ext = extension.to_extension(&self.info.subject, &self.extension_req.0)?;
390
391 self.extension_req.0.push(ext);
392
393 Ok(())
394 }
395
396 pub fn add_attribute<A: AsAttribute>(&mut self, attribute: &A) -> Result<()> {
398 let attr = attribute.to_attribute()?;
399
400 self.info.attributes.insert(attr)?;
401 Ok(())
402 }
403}
404
405pub trait Builder: Sized {
409 type Signer;
411
412 type Output: Sized;
414
415 fn signer(&self) -> &Self::Signer;
417
418 fn assemble(self, signature: BitString) -> Result<Self::Output>;
420
421 fn finalize(&mut self) -> der::Result<vec::Vec<u8>>;
423
424 fn build<Signature>(mut self) -> Result<Self::Output>
426 where
427 Self::Signer: Signer<Signature>,
428 Signature: SignatureBitStringEncoding,
429 {
430 let blob = self.finalize()?;
431
432 let signature = self.signer().try_sign(&blob)?.to_bitstring()?;
433
434 self.assemble(signature)
435 }
436
437 fn build_with_rng<Signature>(mut self, rng: &mut impl CryptoRngCore) -> Result<Self::Output>
439 where
440 Self::Signer: RandomizedSigner<Signature>,
441 Signature: SignatureBitStringEncoding,
442 {
443 let blob = self.finalize()?;
444
445 let signature = self
446 .signer()
447 .try_sign_with_rng(rng, &blob)?
448 .to_bitstring()?;
449
450 self.assemble(signature)
451 }
452}
453
454impl<'s, S> Builder for CertificateBuilder<'s, S>
455where
456 S: Keypair + DynSignatureAlgorithmIdentifier,
457 S::VerifyingKey: EncodePublicKey,
458{
459 type Signer = S;
460 type Output = Certificate;
461
462 fn signer(&self) -> &Self::Signer {
463 self.cert_signer
464 }
465
466 fn finalize(&mut self) -> der::Result<vec::Vec<u8>> {
467 if !self.extensions.is_empty() {
468 self.tbs.extensions = Some(self.extensions.clone());
469 }
470
471 if self.tbs.extensions.is_none() {
472 if self.tbs.issuer_unique_id.is_some() || self.tbs.subject_unique_id.is_some() {
473 self.tbs.version = Version::V2;
474 } else {
475 self.tbs.version = Version::V1;
476 }
477 }
478
479 self.tbs.to_der()
480 }
481
482 fn assemble(self, signature: BitString) -> Result<Self::Output> {
483 let signature_algorithm = self.tbs.signature.clone();
484
485 Ok(Certificate {
486 tbs_certificate: self.tbs,
487 signature_algorithm,
488 signature,
489 })
490 }
491}
492
493impl<'s, S> Builder for RequestBuilder<'s, S>
494where
495 S: Keypair + DynSignatureAlgorithmIdentifier,
496 S::VerifyingKey: EncodePublicKey,
497{
498 type Signer = S;
499 type Output = CertReq;
500
501 fn signer(&self) -> &Self::Signer {
502 self.req_signer
503 }
504
505 fn finalize(&mut self) -> der::Result<vec::Vec<u8>> {
506 self.info
507 .attributes
508 .insert(self.extension_req.clone().try_into()?)?;
509
510 self.info.to_der()
511 }
512
513 fn assemble(self, signature: BitString) -> Result<Self::Output> {
514 let algorithm = self.req_signer.signature_algorithm_identifier()?;
515
516 Ok(CertReq {
517 info: self.info,
518 algorithm,
519 signature,
520 })
521 }
522}