1 use crate::hash::HashAlgorithm;
2 use crate::key::{PrivateKey, PublicKey};
3 use crate::pem::{parse_pem, Pem, PemError};
4 use crate::signature::{SignatureAlgorithm, SignatureError};
5 use crate::x509::csr::{Csr, CsrError};
6 use crate::x509::date::UTCDate;
7 use crate::x509::key_id_gen_method::{KeyIdGenError, KeyIdGenMethod};
8 use crate::x509::name::{DirectoryName, GeneralNames};
9 use picky_asn1::bit_string::BitString;
10 use picky_asn1::wrapper::{ApplicationTag0, ApplicationTag3, IntegerAsn1};
11 use picky_asn1_der::Asn1DerError;
12 use picky_asn1_x509::{
13 oids, AlgorithmIdentifier, AuthorityKeyIdentifier, BasicConstraints, Certificate, ExtendedKeyUsage, Extension,
14 ExtensionView, Extensions, KeyIdentifier, KeyUsage, Name, SubjectPublicKeyInfo, TBSCertificate, Validity, Version,
15 };
16 use std::cell::RefCell;
17 use thiserror::Error;
18
19 #[derive(Debug, Error)]
20 pub enum CertError {
21 /// couldn't generate certificate
22 #[error("couldn't generate certificate: {source}")]
23 CertGeneration { source: Box<CertError> },
24
25 /// invalid certificate
26 #[error("invalid certificate '{id}': {source}")]
27 InvalidCertificate { id: String, source: Box<CertError> },
28
29 /// ASN1 serialization error
30 #[error("(ASN1) couldn't serialize {element}: {source}")]
31 Asn1Serialization {
32 element: &'static str,
33 source: Asn1DerError,
34 },
35
36 /// ASN1 deserialization error
37 #[error("(ASN1) couldn't deserialize {element}: {source}")]
38 Asn1Deserialization {
39 element: &'static str,
40 source: Asn1DerError,
41 },
42
43 /// signature error
44 #[error("signature error: {source}")]
45 Signature { source: SignatureError },
46
47 /// key id generation error
48 #[error("key id generation error: {source}")]
49 KeyIdGen { source: KeyIdGenError },
50
51 /// CA chain error
52 #[error("CA chain error: {source}")]
53 InvalidChain { source: CaChainError },
54
55 /// CSR error
56 #[error("CSR error: {source}")]
57 InvalidCsr { source: CsrError },
58
59 /// extension not found
60 #[error("extension not found: {name}")]
61 ExtensionNotFound { name: &'static str },
62
63 /// missing required builder argument
64 #[error("missing required builder argument `{arg}`")]
65 MissingBuilderArgument { arg: &'static str },
66
67 /// certificate is not yet valid
68 #[error("certificate is not yet valid (not before: {not_before}, now: {now})")]
69 CertificateNotYetValid { not_before: UTCDate, now: UTCDate },
70
71 /// certificate expired
72 #[error("certificate expired (not after: {not_after}, now: {now})")]
73 CertificateExpired { not_after: UTCDate, now: UTCDate },
74
75 /// invalid PEM label error
76 #[error("invalid PEM label: {label}")]
77 InvalidPemLabel { label: String },
78
79 /// invalid PEM provided
80 #[error("invalid PEM provided: {source}")]
81 Pem { source: PemError },
82 }
83
84 impl From<PemError> for CertError {
from(e: PemError) -> Self85 fn from(e: PemError) -> Self {
86 Self::Pem { source: e }
87 }
88 }
89
90 #[derive(Debug, Error)]
91 pub enum CaChainError {
92 /// chain depth does't satisfy basic constraints extension
93 #[error(
94 "chain depth doesn't satisfy basic constraints extension: certificate '{cert_id}' has pathlen of {pathlen}"
95 )]
96 TooDeep { cert_id: String, pathlen: u8 },
97
98 /// chain is missing a root certificate
99 #[error("chain is missing a root certificate")]
100 NoRoot,
101
102 /// issuer certificate is not a CA
103 #[error("issuer certificate '{issuer_id}' is not a CA")]
104 IssuerIsNotCA { issuer_id: String },
105
106 /// authority key id doesn't match
107 #[error("authority key id doesn't match (expected: {}, got: {})", base64::encode(&.expected), base64::encode(&.actual))]
108 AuthorityKeyIdMismatch { expected: Vec<u8>, actual: Vec<u8> },
109
110 /// issuer name doesn't match
111 #[error("issuer name doesn't match (expected: {expected}, got: {actual})")]
112 IssuerNameMismatch { expected: String, actual: String },
113 }
114
115 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
116 pub enum CertType {
117 Root,
118 Intermediate,
119 Leaf,
120 Unknown,
121 }
122
123 const CERT_PEM_LABEL: &str = "CERTIFICATE";
124
125 #[derive(Clone, Debug, PartialEq)]
126 pub struct Cert(Certificate);
127
128 impl From<Certificate> for Cert {
from(certificate: Certificate) -> Self129 fn from(certificate: Certificate) -> Self {
130 Self(certificate)
131 }
132 }
133
134 impl From<Cert> for Certificate {
from(certificate: Cert) -> Self135 fn from(certificate: Cert) -> Self {
136 certificate.0
137 }
138 }
139
140 macro_rules! find_ext {
141 ($oid:expr, $certificate:ident, $ext_name:literal) => {{
142 let key_identifier_oid = $oid;
143 ($certificate.tbs_certificate.extensions.0)
144 .0
145 .iter()
146 .find(|ext| ext.extn_id() == &key_identifier_oid)
147 .ok_or(CertError::ExtensionNotFound { name: $ext_name })
148 }};
149 }
150
151 impl Cert {
from_der<T: ?Sized + AsRef<[u8]>>(der: &T) -> Result<Self, CertError>152 pub fn from_der<T: ?Sized + AsRef<[u8]>>(der: &T) -> Result<Self, CertError> {
153 Ok(Self(picky_asn1_der::from_bytes(der.as_ref()).map_err(|e| {
154 CertError::Asn1Deserialization {
155 source: e,
156 element: "certificate",
157 }
158 })?))
159 }
160
from_pem(pem: &Pem) -> Result<Self, CertError>161 pub fn from_pem(pem: &Pem) -> Result<Self, CertError> {
162 match pem.label() {
163 CERT_PEM_LABEL => Self::from_der(pem.data()),
164 _ => Err(CertError::InvalidPemLabel {
165 label: pem.label().to_owned(),
166 }),
167 }
168 }
169
from_pem_str(pem_str: &str) -> Result<Self, CertError>170 pub fn from_pem_str(pem_str: &str) -> Result<Self, CertError> {
171 let pem = parse_pem(pem_str)?;
172 Self::from_pem(&pem)
173 }
174
to_der(&self) -> Result<Vec<u8>, CertError>175 pub fn to_der(&self) -> Result<Vec<u8>, CertError> {
176 picky_asn1_der::to_vec(&self.0).map_err(|e| CertError::Asn1Serialization {
177 source: e,
178 element: "certificate",
179 })
180 }
181
to_pem(&self) -> Result<Pem<'static>, CertError>182 pub fn to_pem(&self) -> Result<Pem<'static>, CertError> {
183 Ok(Pem::new(CERT_PEM_LABEL, self.to_der()?))
184 }
185
ty(&self) -> CertType186 pub fn ty(&self) -> CertType {
187 if let Some(ca) = self.basic_constraints().map(|bc| bc.ca()).unwrap_or(None) {
188 if ca {
189 if self.subject_name() == self.issuer_name() {
190 CertType::Root
191 } else {
192 CertType::Intermediate
193 }
194 } else {
195 CertType::Leaf
196 }
197 } else {
198 CertType::Unknown
199 }
200 }
201
serial_number(&self) -> &IntegerAsn1202 pub fn serial_number(&self) -> &IntegerAsn1 {
203 &self.0.tbs_certificate.serial_number
204 }
205
signature_algorithm(&self) -> &AlgorithmIdentifier206 pub fn signature_algorithm(&self) -> &AlgorithmIdentifier {
207 &self.0.tbs_certificate.signature
208 }
209
valid_not_before(&self) -> UTCDate210 pub fn valid_not_before(&self) -> UTCDate {
211 self.0.tbs_certificate.validity.not_before.clone().into()
212 }
213
valid_not_after(&self) -> UTCDate214 pub fn valid_not_after(&self) -> UTCDate {
215 self.0.tbs_certificate.validity.not_after.clone().into()
216 }
217
subject_key_identifier(&self) -> Result<&[u8], CertError>218 pub fn subject_key_identifier(&self) -> Result<&[u8], CertError> {
219 let certificate = &self.0;
220
221 let ext = find_ext!(oids::subject_key_identifier(), certificate, "subject key identifier")?;
222 match ext.extn_value() {
223 ExtensionView::SubjectKeyIdentifier(ski) => Ok(&ski.0),
224 _ => unreachable!("invalid extension (expected subject key identifier)"),
225 }
226 }
227
authority_key_identifier(&self) -> Result<&AuthorityKeyIdentifier, CertError>228 pub fn authority_key_identifier(&self) -> Result<&AuthorityKeyIdentifier, CertError> {
229 let certificate = &self.0;
230
231 let ext = find_ext!(
232 oids::authority_key_identifier(),
233 certificate,
234 "authority key identifier"
235 )?;
236 match ext.extn_value() {
237 ExtensionView::AuthorityKeyIdentifier(aki) => Ok(aki),
238 _ => unreachable!("invalid extension (expected authority key identifier)"),
239 }
240 }
241
basic_constraints(&self) -> Result<&BasicConstraints, CertError>242 pub fn basic_constraints(&self) -> Result<&BasicConstraints, CertError> {
243 let certificate = &self.0;
244 let ext = find_ext!(oids::basic_constraints(), certificate, "basic constraints")?;
245 match ext.extn_value() {
246 ExtensionView::BasicConstraints(bc) => Ok(bc),
247 _ => unreachable!("invalid extension (expected basic constraints)"),
248 }
249 }
250
subject_name(&self) -> DirectoryName251 pub fn subject_name(&self) -> DirectoryName {
252 self.0.tbs_certificate.subject.clone().into()
253 }
254
issuer_name(&self) -> DirectoryName255 pub fn issuer_name(&self) -> DirectoryName {
256 self.0.tbs_certificate.issuer.clone().into()
257 }
258
extensions(&self) -> &[Extension]259 pub fn extensions(&self) -> &[Extension] {
260 (self.0.tbs_certificate.extensions.0).0.as_slice()
261 }
262
public_key(&self) -> &PublicKey263 pub fn public_key(&self) -> &PublicKey {
264 (&self.0.tbs_certificate.subject_public_key_info).into()
265 }
266
into_public_key(self) -> PublicKey267 pub fn into_public_key(self) -> PublicKey {
268 self.0.tbs_certificate.subject_public_key_info.into()
269 }
270
is_parent_of(&self, other: &Cert) -> Result<(), CertError>271 pub fn is_parent_of(&self, other: &Cert) -> Result<(), CertError> {
272 if let Ok(other_aki) = other.authority_key_identifier() {
273 if let Some(other_aki) = other_aki.key_identifier() {
274 let parent_ski = self
275 .subject_key_identifier()
276 .map_err(|e| CertError::InvalidCertificate {
277 source: Box::new(e),
278 id: self.subject_name().to_string(),
279 })?;
280
281 if parent_ski != other_aki {
282 return Err(CaChainError::AuthorityKeyIdMismatch {
283 expected: other_aki.to_vec(),
284 actual: parent_ski.to_vec(),
285 })
286 .map_err(|e| CertError::InvalidChain { source: e })
287 .map_err(|e| CertError::InvalidCertificate {
288 source: Box::new(e),
289 id: other.subject_name().to_string(),
290 });
291 }
292 }
293 }
294
295 let other_issuer_name = other.issuer_name();
296 let self_subject_name = self.subject_name();
297 if other_issuer_name != self_subject_name {
298 return Err(CaChainError::IssuerNameMismatch {
299 expected: other_issuer_name.to_string(),
300 actual: self_subject_name.to_string(),
301 })
302 .map_err(|e| CertError::InvalidChain { source: e })
303 .map_err(|e| CertError::InvalidCertificate {
304 source: Box::new(e),
305 id: other.subject_name().to_string(),
306 });
307 }
308
309 Ok(())
310 }
311
verifier<'a, 'b, Chain: Iterator<Item = &'b Cert>>(&'a self) -> CertValidator<'a, 'b, Chain>312 pub fn verifier<'a, 'b, Chain: Iterator<Item = &'b Cert>>(&'a self) -> CertValidator<'a, 'b, Chain> {
313 CertValidator {
314 cert: self,
315 inner: RefCell::new(CertValidatorInner {
316 strictness: Default::default(),
317 now: None,
318 chain: None,
319 }),
320 }
321 }
322 }
323
324 // === certificate verifier === /
325
326 #[derive(Debug, Clone)]
327 enum ValidityCheck<'a> {
328 Interval { lower: &'a UTCDate, upper: &'a UTCDate },
329 Exact(&'a UTCDate),
330 }
331
332 #[derive(Debug, Clone)]
333 struct CheckStrictness {
334 require_not_before_check: bool,
335 require_not_after_check: bool,
336 require_chain_check: bool,
337 }
338
339 impl Default for CheckStrictness {
default() -> Self340 fn default() -> Self {
341 Self {
342 require_not_before_check: true,
343 require_not_after_check: true,
344 require_chain_check: true,
345 }
346 }
347 }
348
349 #[derive(Clone, Debug)]
350 struct CertValidatorInner<'a, 'b, Chain: Iterator<Item = &'b Cert>> {
351 strictness: CheckStrictness,
352 now: Option<ValidityCheck<'a>>,
353 chain: Option<Chain>,
354 }
355
356 /// Utility to verify x509 `Cert`s
357 #[derive(Clone, Debug)]
358 pub struct CertValidator<'a, 'b, Chain: Iterator<Item = &'b Cert>> {
359 cert: &'a Cert,
360 inner: RefCell<CertValidatorInner<'a, 'b, Chain>>,
361 }
362
363 impl<'a, 'b, Chain: Iterator<Item = &'b Cert>> CertValidator<'a, 'b, Chain> {
364 #[inline]
exact_date(&self, exact: &'a UTCDate) -> &Self365 pub fn exact_date(&self, exact: &'a UTCDate) -> &Self {
366 self.inner.borrow_mut().now = Some(ValidityCheck::Exact(exact));
367 self
368 }
369
370 #[inline]
interval_date(&self, lower: &'a UTCDate, upper: &'a UTCDate) -> &Self371 pub fn interval_date(&self, lower: &'a UTCDate, upper: &'a UTCDate) -> &Self {
372 self.inner.borrow_mut().now = Some(ValidityCheck::Interval { lower, upper });
373 self
374 }
375
376 #[inline]
chain(&self, chain: Chain) -> &Self377 pub fn chain(&self, chain: Chain) -> &Self {
378 self.inner.borrow_mut().chain = Some(chain);
379 self
380 }
381
382 #[inline]
require_not_before_check(&self) -> &Self383 pub fn require_not_before_check(&self) -> &Self {
384 self.inner.borrow_mut().strictness.require_not_before_check = true;
385 self
386 }
387
388 #[inline]
require_not_after_check(&self) -> &Self389 pub fn require_not_after_check(&self) -> &Self {
390 self.inner.borrow_mut().strictness.require_not_after_check = true;
391 self
392 }
393
394 #[inline]
require_chain_check(&self) -> &Self395 pub fn require_chain_check(&self) -> &Self {
396 self.inner.borrow_mut().strictness.require_chain_check = true;
397 self
398 }
399
400 #[inline]
ignore_not_before_check(&self) -> &Self401 pub fn ignore_not_before_check(&self) -> &Self {
402 self.inner.borrow_mut().strictness.require_not_before_check = false;
403 self
404 }
405
406 #[inline]
ignore_not_after_check(&self) -> &Self407 pub fn ignore_not_after_check(&self) -> &Self {
408 self.inner.borrow_mut().strictness.require_not_after_check = false;
409 self
410 }
411
412 #[inline]
ignore_chain_check(&self) -> &Self413 pub fn ignore_chain_check(&self) -> &Self {
414 self.inner.borrow_mut().strictness.require_chain_check = false;
415 self
416 }
417
verify(&self) -> Result<(), CertError>418 pub fn verify(&self) -> Result<(), CertError> {
419 let mut inner = self.inner.borrow_mut();
420
421 if (inner.strictness.require_not_after_check || inner.strictness.require_not_before_check)
422 && inner.now.is_none()
423 {
424 return Err(CertError::MissingBuilderArgument { arg: "now" });
425 }
426
427 if let Some(now) = &inner.now {
428 verify_cert_validity(self.cert, &inner.strictness, now.clone()).map_err(|e| {
429 CertError::InvalidCertificate {
430 source: Box::new(e),
431 id: self.cert.subject_name().to_string(),
432 }
433 })?;
434 }
435
436 if !inner.strictness.require_chain_check {
437 return Ok(());
438 }
439
440 let chain = if let Some(chain) = inner.chain.take() {
441 chain
442 } else {
443 return Err(CertError::MissingBuilderArgument { arg: "chain" });
444 };
445
446 let mut current_cert = self.cert;
447
448 for (number_certs, parent_cert) in chain.enumerate() {
449 // check basic constraints
450 match parent_cert
451 .basic_constraints()
452 .map(|bc| (bc.ca(), bc.pathlen()))
453 .unwrap_or((None, None))
454 {
455 (Some(false), _) => {
456 return Err(CaChainError::IssuerIsNotCA {
457 issuer_id: parent_cert.subject_name().to_string(),
458 })
459 .map_err(|e| CertError::InvalidChain { source: e });
460 }
461 (_, Some(pathlen)) if usize::from(pathlen) < number_certs => {
462 return Err(CaChainError::TooDeep {
463 cert_id: parent_cert.subject_name().to_string(),
464 pathlen,
465 })
466 .map_err(|e| CertError::InvalidChain { source: e });
467 }
468 _ => {}
469 }
470
471 // verify parent validity
472 if let Some(now) = &inner.now {
473 verify_cert_validity(parent_cert, &inner.strictness, now.clone()).map_err(|e| {
474 CertError::InvalidCertificate {
475 source: Box::new(e),
476 id: parent_cert.subject_name().to_string(),
477 }
478 })?;
479 }
480
481 // check parent_cert is the parent of current_cert
482 parent_cert.is_parent_of(current_cert)?;
483
484 // validate current cert signature using parent public key
485 let hash_type = SignatureAlgorithm::from_algorithm_identifier(¤t_cert.0.signature_algorithm)
486 .map_err(|e| CertError::Signature { source: e })?;
487 let public_key = &parent_cert.0.tbs_certificate.subject_public_key_info;
488 let msg = picky_asn1_der::to_vec(¤t_cert.0.tbs_certificate)
489 .map_err(|e| CertError::Asn1Serialization {
490 source: e,
491 element: "tbs certificate",
492 })
493 .map_err(|e| CertError::InvalidCertificate {
494 source: Box::new(e),
495 id: current_cert.subject_name().to_string(),
496 })?;
497 hash_type
498 .verify(
499 &public_key.clone().into(),
500 &msg,
501 current_cert.0.signature_value.0.payload_view(),
502 )
503 .map_err(|e| CertError::Signature { source: e })
504 .map_err(|e| CertError::InvalidCertificate {
505 source: Box::new(e),
506 id: current_cert.subject_name().to_string(),
507 })?;
508
509 current_cert = parent_cert;
510 }
511
512 // make sure `current_cert` (the last certificate of the chain) is a root CA
513 if current_cert.ty() != CertType::Root {
514 return Err(CaChainError::NoRoot).map_err(|e| CertError::InvalidChain { source: e });
515 }
516
517 Ok(())
518 }
519 }
520
verify_cert_validity(cert: &Cert, strictness: &CheckStrictness, now: ValidityCheck<'_>) -> Result<(), CertError>521 fn verify_cert_validity(cert: &Cert, strictness: &CheckStrictness, now: ValidityCheck<'_>) -> Result<(), CertError> {
522 let validity = &cert.0.tbs_certificate.validity;
523 let not_before: UTCDate = validity.not_before.clone().into();
524 let not_after: UTCDate = validity.not_after.clone().into();
525
526 match now {
527 ValidityCheck::Interval { lower, upper } => {
528 if not_before.gt(upper) && strictness.require_not_before_check {
529 return Err(CertError::CertificateNotYetValid {
530 not_before,
531 now: upper.clone(),
532 });
533 }
534
535 if not_after.lt(lower) && strictness.require_not_after_check {
536 return Err(CertError::CertificateExpired {
537 not_after,
538 now: lower.clone(),
539 });
540 }
541 }
542 ValidityCheck::Exact(now) => {
543 if not_before.gt(now) && strictness.require_not_before_check {
544 return Err(CertError::CertificateNotYetValid {
545 not_before,
546 now: now.clone(),
547 });
548 }
549
550 if not_after.lt(now) && strictness.require_not_after_check {
551 return Err(CertError::CertificateExpired {
552 not_after,
553 now: now.clone(),
554 });
555 }
556 }
557 }
558
559 Ok(())
560 }
561
562 // === builder === //
563
564 #[derive(Clone, Debug)]
565 enum SubjectInfos {
566 Csr(Csr),
567 NameAndPublicKey { name: DirectoryName, public_key: PublicKey },
568 }
569
570 #[derive(Clone, Debug)]
571 struct IssuerInfos<'a> {
572 name: DirectoryName,
573 key: &'a PrivateKey,
574 self_signed: bool,
575 }
576
577 // Statically checks the field actually exists and returns a &'static str of the field name
578 macro_rules! field_str {
579 ($field:ident) => {{
580 const _: fn() = || {
581 let CertificateBuilderInner { $field: _, .. };
582 };
583 stringify!($field)
584 }};
585 }
586
587 #[derive(Default, Clone, Debug)]
588 struct CertificateBuilderInner<'a> {
589 valid_from: Option<UTCDate>,
590 valid_to: Option<UTCDate>,
591 subject_infos: Option<SubjectInfos>,
592 issuer_infos: Option<IssuerInfos<'a>>,
593 authority_key_identifier: Option<Vec<u8>>,
594 ca: Option<bool>,
595 pathlen: Option<u8>,
596 signature_hash_type: Option<SignatureAlgorithm>,
597 key_id_gen_method: Option<KeyIdGenMethod>,
598 key_usage: Option<KeyUsage>,
599 extended_key_usage: Option<ExtendedKeyUsage>,
600 subject_alt_name: Option<GeneralNames>,
601 issuer_alt_name: Option<GeneralNames>,
602 serial_number: Option<Vec<u8>>,
603 inherit_extensions_from_csr_attributes: bool,
604 }
605
606 #[derive(Default, Clone, Debug)]
607 pub struct CertificateBuilder<'a> {
608 inner: RefCell<CertificateBuilderInner<'a>>,
609 }
610
611 impl<'a> CertificateBuilder<'a> {
new() -> Self612 pub fn new() -> Self {
613 Self::default()
614 }
615
616 /// Required
617 #[inline]
validity(&self, valid_from: UTCDate, valid_to: UTCDate) -> &Self618 pub fn validity(&self, valid_from: UTCDate, valid_to: UTCDate) -> &Self {
619 let mut inner_mut = self.inner.borrow_mut();
620 inner_mut.valid_from = Some(valid_from);
621 inner_mut.valid_to = Some(valid_to);
622 drop(inner_mut);
623 self
624 }
625
626 /// Required (alternatives: `subject_from_csr`, `self_signed`)
627 #[inline]
subject(&self, subject_name: DirectoryName, public_key: PublicKey) -> &Self628 pub fn subject(&self, subject_name: DirectoryName, public_key: PublicKey) -> &Self {
629 self.inner.borrow_mut().subject_infos = Some(SubjectInfos::NameAndPublicKey {
630 name: subject_name,
631 public_key,
632 });
633 self
634 }
635
636 /// Required (alternatives: `subject`, `self_signed`)
637 #[inline]
subject_from_csr(&self, csr: Csr) -> &Self638 pub fn subject_from_csr(&self, csr: Csr) -> &Self {
639 self.inner.borrow_mut().subject_infos = Some(SubjectInfos::Csr(csr));
640 self
641 }
642
643 /// Required (alternative: `self_signed`, `issuer_cert`)
644 #[inline]
issuer(&self, issuer_name: DirectoryName, issuer_key: &'a PrivateKey) -> &Self645 pub fn issuer(&self, issuer_name: DirectoryName, issuer_key: &'a PrivateKey) -> &Self {
646 self.inner.borrow_mut().issuer_infos = Some(IssuerInfos {
647 name: issuer_name,
648 key: issuer_key,
649 self_signed: false,
650 });
651 self
652 }
653
654 /// Required (alternative: `issuer`, `issuer_cert`)
655 #[inline]
self_signed(&self, name: DirectoryName, key: &'a PrivateKey) -> &Self656 pub fn self_signed(&self, name: DirectoryName, key: &'a PrivateKey) -> &Self {
657 self.inner.borrow_mut().issuer_infos = Some(IssuerInfos {
658 name,
659 key,
660 self_signed: true,
661 });
662 self
663 }
664
665 /// Required (alternative: `issuer`, `self_signed`)
666 #[inline]
issuer_cert(&self, issuer_cert: &Cert, issuer_key: &'a PrivateKey) -> &Self667 pub fn issuer_cert(&self, issuer_cert: &Cert, issuer_key: &'a PrivateKey) -> &Self {
668 let builder = self.issuer(issuer_cert.subject_name(), &issuer_key);
669
670 if let Ok(issuer_ski) = issuer_cert.subject_key_identifier() {
671 self.authority_key_identifier(issuer_ski.to_vec())
672 } else {
673 builder
674 }
675 }
676
677 /// Optional (alternative: `issuer_cert`, `self_signed`)
678 #[inline]
authority_key_identifier(&self, aki: Vec<u8>) -> &Self679 pub fn authority_key_identifier(&self, aki: Vec<u8>) -> &Self {
680 self.inner.borrow_mut().authority_key_identifier = Some(aki);
681 self
682 }
683
684 /// Optional
685 #[inline]
ca(&self, ca: bool) -> &Self686 pub fn ca(&self, ca: bool) -> &Self {
687 self.inner.borrow_mut().ca = Some(ca);
688 self
689 }
690
691 /// Optional
692 #[inline]
pathlen(&self, pathlen: u8) -> &Self693 pub fn pathlen(&self, pathlen: u8) -> &Self {
694 self.inner.borrow_mut().pathlen = Some(pathlen);
695 self
696 }
697
698 /// Optional
699 #[inline]
signature_hash_type(&self, signature_hash_type: SignatureAlgorithm) -> &Self700 pub fn signature_hash_type(&self, signature_hash_type: SignatureAlgorithm) -> &Self {
701 self.inner.borrow_mut().signature_hash_type = Some(signature_hash_type);
702 self
703 }
704
705 /// Optional
706 #[inline]
key_id_gen_method(&self, key_id_gen_method: KeyIdGenMethod) -> &Self707 pub fn key_id_gen_method(&self, key_id_gen_method: KeyIdGenMethod) -> &Self {
708 self.inner.borrow_mut().key_id_gen_method = Some(key_id_gen_method);
709 self
710 }
711
712 /// Optional
713 #[inline]
key_usage(&self, key_usage: KeyUsage) -> &Self714 pub fn key_usage(&self, key_usage: KeyUsage) -> &Self {
715 self.inner.borrow_mut().key_usage = Some(key_usage);
716 self
717 }
718
719 /// Optional
720 #[inline]
extended_key_usage(&self, extended_key_usage: ExtendedKeyUsage) -> &Self721 pub fn extended_key_usage(&self, extended_key_usage: ExtendedKeyUsage) -> &Self {
722 self.inner.borrow_mut().extended_key_usage = Some(extended_key_usage);
723 self
724 }
725
726 /// Optional
727 #[inline]
subject_alt_name(&self, subject_alt_name: GeneralNames) -> &Self728 pub fn subject_alt_name(&self, subject_alt_name: GeneralNames) -> &Self {
729 self.inner.borrow_mut().subject_alt_name = Some(subject_alt_name);
730 self
731 }
732
733 /// Optional
734 #[inline]
issuer_alt_name(&self, issuer_alt_name: GeneralNames) -> &Self735 pub fn issuer_alt_name(&self, issuer_alt_name: GeneralNames) -> &Self {
736 self.inner.borrow_mut().issuer_alt_name = Some(issuer_alt_name);
737 self
738 }
739
740 /// Optional
741 ///
742 /// Bypass picky serial number generator by providing your own.
743 #[inline]
serial_number(&self, unsigned_integer_bytes: Vec<u8>) -> &Self744 pub fn serial_number(&self, unsigned_integer_bytes: Vec<u8>) -> &Self {
745 self.inner.borrow_mut().serial_number = Some(unsigned_integer_bytes);
746 self
747 }
748
749 /// Optional
750 ///
751 /// Inherit extensions from the "extension request" attribute of the provided CSR if applicable
752 /// Extensions already present will be ignored.
753 #[inline]
inherit_extensions_from_csr_attributes(&self, inherit: bool) -> &Self754 pub fn inherit_extensions_from_csr_attributes(&self, inherit: bool) -> &Self {
755 self.inner.borrow_mut().inherit_extensions_from_csr_attributes = inherit;
756 self
757 }
758
build(&self) -> Result<Cert, CertError>759 pub fn build(&self) -> Result<Cert, CertError> {
760 let mut inner = self.inner.borrow_mut();
761
762 let valid_from = inner.valid_from.take().ok_or(CertError::MissingBuilderArgument {
763 arg: field_str!(valid_from),
764 })?;
765 let valid_to = inner.valid_to.take().ok_or(CertError::MissingBuilderArgument {
766 arg: field_str!(valid_to),
767 })?;
768
769 let signature_hash_type = inner
770 .signature_hash_type
771 .take()
772 .unwrap_or(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_256));
773
774 let key_id_gen_method = inner
775 .key_id_gen_method
776 .take()
777 .unwrap_or(KeyIdGenMethod::SPKFullDER(HashAlgorithm::SHA2_256));
778
779 let issuer_infos = inner.issuer_infos.take().ok_or(CertError::MissingBuilderArgument {
780 arg: field_str!(issuer_infos),
781 })?;
782 let (issuer_name, issuer_key, aki, subject_infos) = {
783 let (aki, subject_infos) = if issuer_infos.self_signed {
784 let public_key = issuer_infos.key.to_public_key();
785 let aki = key_id_gen_method
786 .generate_from(&public_key)
787 .map_err(|e| CertError::KeyIdGen { source: e })
788 .map_err(|e| CertError::CertGeneration { source: Box::new(e) })?;
789 let subject_infos = SubjectInfos::NameAndPublicKey {
790 name: issuer_infos.name.clone(),
791 public_key,
792 };
793 (aki, subject_infos)
794 } else {
795 let aki = inner
796 .authority_key_identifier
797 .take()
798 .ok_or(CertError::MissingBuilderArgument {
799 arg: field_str!(authority_key_identifier),
800 })?;
801 let subject_infos = inner.subject_infos.take().ok_or(CertError::MissingBuilderArgument {
802 arg: field_str!(subject_infos),
803 })?;
804 (aki, subject_infos)
805 };
806
807 (issuer_infos.name, issuer_infos.key, aki, subject_infos)
808 };
809 let (subject_name, subject_public_key, ext_req) = match subject_infos {
810 SubjectInfos::Csr(csr) => {
811 csr.verify().map_err(|e| CertError::InvalidCsr { source: e })?;
812
813 let ext_req = csr
814 .0
815 .certification_request_info
816 .attributes
817 .0
818 .into_iter()
819 .find_map(|attr| match attr.value {
820 picky_asn1_x509::AttributeValue::Extensions(set_of_extensions) => {
821 set_of_extensions.0.into_iter().next()
822 }
823 _ => None,
824 });
825
826 let subject_name = csr.0.certification_request_info.subject.into();
827 let subject_public_key = csr.0.certification_request_info.subject_public_key_info.into();
828
829 (subject_name, subject_public_key, ext_req)
830 }
831 SubjectInfos::NameAndPublicKey { name, public_key } => (name, public_key, None),
832 };
833
834 let ca = inner.ca.take().unwrap_or(false);
835 let pathlen = inner.pathlen.take();
836 let key_usage_opt = inner.key_usage.take();
837 let extended_key_usage_opt = inner.extended_key_usage.take();
838 let subject_alt_name_opt = inner.subject_alt_name.take();
839 let issuer_alt_name_opt = inner.issuer_alt_name.take();
840
841 let serial_number = if let Some(unsigned_integer_bytes) = inner.serial_number.take() {
842 IntegerAsn1::from_bytes_be_unsigned(unsigned_integer_bytes)
843 } else {
844 generate_serial_number()
845 };
846
847 let inherit_extensions_from_csr_attributes = inner.inherit_extensions_from_csr_attributes;
848
849 drop(inner);
850
851 let validity = Validity {
852 not_before: valid_from.into(),
853 not_after: valid_to.into(),
854 };
855
856 let extensions = {
857 let mut extensions = Vec::new();
858
859 // key usage + basic constraints
860 if let Some(key_usage) = key_usage_opt {
861 if key_usage.digital_signature() {
862 extensions.push(Extension::new_basic_constraints(ca, pathlen).into_critical());
863 } else {
864 extensions.push(Extension::new_basic_constraints(ca, pathlen).into_non_critical());
865 }
866 extensions.push(Extension::new_key_usage(key_usage));
867 } else {
868 extensions.push(Extension::new_basic_constraints(ca, pathlen).into_non_critical());
869 }
870
871 // eku
872 if let Some(extended_key_usage) = extended_key_usage_opt {
873 extensions.push(Extension::new_extended_key_usage(extended_key_usage));
874 }
875
876 // san
877 if let Some(san) = subject_alt_name_opt {
878 extensions.push(Extension::new_subject_alt_name(san));
879 }
880
881 // ian
882 if let Some(ian) = issuer_alt_name_opt {
883 extensions.push(Extension::new_issuer_alt_name(ian));
884 }
885
886 // ski
887 let ski = key_id_gen_method
888 .generate_from(&subject_public_key)
889 .map_err(|e| CertError::KeyIdGen { source: e })
890 .map_err(|e| CertError::CertGeneration { source: Box::new(e) })?;
891 extensions.push(Extension::new_subject_key_identifier(ski));
892
893 // aki
894 extensions.push(Extension::new_authority_key_identifier(
895 KeyIdentifier::from(aki),
896 None,
897 None,
898 ));
899
900 // inherit extensions from csr "request extension" attribute if allowed to
901 match ext_req {
902 Some(requested_exts) if inherit_extensions_from_csr_attributes => {
903 for requested_ext in requested_exts.0 {
904 if !extensions.iter().any(|o| requested_ext.extn_id() == o.extn_id()) {
905 extensions.push(requested_ext);
906 }
907 }
908 }
909 _ => {}
910 }
911
912 Extensions(extensions)
913 };
914
915 let tbs_certificate = TBSCertificate {
916 version: ApplicationTag0(Version::V3),
917 serial_number,
918 signature: AlgorithmIdentifier::from(signature_hash_type),
919 issuer: Name::from(issuer_name),
920 validity,
921 subject: Name::from(subject_name),
922 subject_public_key_info: SubjectPublicKeyInfo::from(subject_public_key),
923 extensions: ApplicationTag3(extensions),
924 };
925
926 let tbs_der = picky_asn1_der::to_vec(&tbs_certificate)
927 .map_err(|e| CertError::Asn1Serialization {
928 source: e,
929 element: "tbs certificate",
930 })
931 .map_err(|e| CertError::CertGeneration { source: Box::new(e) })?;
932 let signature_value = BitString::with_bytes(
933 signature_hash_type
934 .sign(&tbs_der, issuer_key)
935 .map_err(|e| CertError::Signature { source: e })
936 .map_err(|e| CertError::CertGeneration { source: Box::new(e) })?,
937 );
938
939 Ok(Cert(Certificate {
940 tbs_certificate,
941 signature_algorithm: signature_hash_type.into(),
942 signature_value: signature_value.into(),
943 }))
944 }
945 }
946
generate_serial_number() -> IntegerAsn1947 fn generate_serial_number() -> IntegerAsn1 {
948 let x = rand::random::<u32>();
949 let b1 = ((x >> 24) & 0xff) as u8;
950 let b2 = ((x >> 16) & 0xff) as u8;
951 let b3 = ((x >> 8) & 0xff) as u8;
952 let b4 = (x & 0xff) as u8;
953 // serial number MUST be a positive integer
954 IntegerAsn1::from_bytes_be_unsigned(vec![b1, b2, b3, b4])
955 }
956
957 #[cfg(test)]
958 mod tests {
959 use super::*;
960 use crate::pem::{parse_pem, Pem};
961 use crate::x509::csr::Attribute;
962
963 #[test]
read_pem_and_parse_certificate()964 fn read_pem_and_parse_certificate() {
965 let pem = parse_pem(crate::test_files::INTERMEDIATE_CA.as_bytes()).unwrap();
966 let cert = Cert::from_der(pem.data()).unwrap();
967
968 assert_eq!(cert.serial_number(), &vec![1]);
969 assert_eq!(
970 Into::<String>::into(cert.signature_algorithm().oid()).as_str(),
971 oids::SHA1_WITH_RSA_ENCRYPTION
972 );
973 assert_eq!(cert.valid_not_before(), UTCDate::new(2011, 2, 12, 14, 44, 6).unwrap());
974 assert_eq!(cert.valid_not_after(), UTCDate::new(2021, 2, 12, 14, 44, 6).unwrap());
975
976 assert_eq!(cert.issuer_name().to_string(), "C=NL,O=PolarSSL,CN=PolarSSL Test CA");
977 }
978
979 #[test]
get_identifier()980 fn get_identifier() {
981 let pem = crate::test_files::RSA_2048_PK_1
982 .parse::<Pem>()
983 .expect("couldn't parse pem");
984 let private_key = PrivateKey::from_pkcs8(pem.data()).expect("couldn't extract private key from pkcs8");
985
986 // validity
987 let valid_from = UTCDate::ymd(2019, 10, 10).unwrap();
988 let valid_to = UTCDate::ymd(2019, 10, 11).unwrap();
989
990 let root = CertificateBuilder::new()
991 .validity(valid_from, valid_to)
992 .self_signed(DirectoryName::new_common_name("test"), &private_key)
993 .ca(true)
994 .build()
995 .expect("couldn't generate root ca");
996
997 root.subject_key_identifier()
998 .expect("couldn't get subject key identifier");
999 root.authority_key_identifier()
1000 .expect("couldn't get authority key identifier");
1001
1002 assert_eq!(root.ty(), CertType::Root);
1003 }
1004
1005 #[test]
key_id_and_cert()1006 fn key_id_and_cert() {
1007 let kid = "c4a7b1a47b2c71fadbe14b9075ffc41560858910";
1008 let pem = crate::test_files::ROOT_CA.parse::<Pem>().expect("couldn't parse PEM");
1009 let cert = Cert::from_der(pem.data()).expect("couldn't deserialize certificate");
1010 assert_eq!(cert.ty(), CertType::Root);
1011 let key_id = cert
1012 .subject_key_identifier()
1013 .expect("couldn't get subject key identifier");
1014 pretty_assertions::assert_eq!(hex::encode(&key_id), kid);
1015 }
1016
parse_key(pem_str: &str) -> PrivateKey1017 fn parse_key(pem_str: &str) -> PrivateKey {
1018 let pem = pem_str.parse::<Pem>().unwrap();
1019 PrivateKey::from_pkcs8(pem.data()).unwrap()
1020 }
1021
1022 #[test]
valid_ca_chain()1023 fn valid_ca_chain() {
1024 let root_key = parse_key(crate::test_files::RSA_2048_PK_1);
1025 let intermediate_key = parse_key(crate::test_files::RSA_2048_PK_2);
1026 let leaf_key = parse_key(crate::test_files::RSA_2048_PK_3);
1027
1028 let root = CertificateBuilder::new()
1029 .validity(UTCDate::ymd(2065, 6, 15).unwrap(), UTCDate::ymd(2070, 6, 15).unwrap())
1030 .self_signed(DirectoryName::new_common_name("TheFuture.usodakedo Root CA"), &root_key)
1031 .ca(true)
1032 .signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_512))
1033 .key_id_gen_method(KeyIdGenMethod::SPKFullDER(HashAlgorithm::SHA2_384))
1034 .build()
1035 .expect("couldn't build root ca");
1036 assert_eq!(root.ty(), CertType::Root);
1037
1038 let intermediate = CertificateBuilder::new()
1039 .validity(UTCDate::ymd(2068, 1, 1).unwrap(), UTCDate::ymd(2071, 1, 1).unwrap())
1040 .subject(
1041 DirectoryName::new_common_name("TheFuture.usodakedo Authority"),
1042 intermediate_key.to_public_key(),
1043 )
1044 .issuer_cert(&root, &root_key)
1045 .signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_224))
1046 .key_id_gen_method(KeyIdGenMethod::SPKValueHashedLeftmost160(HashAlgorithm::SHA1))
1047 .ca(true)
1048 .pathlen(0)
1049 .build()
1050 .expect("couldn't build intermediate ca");
1051 assert_eq!(intermediate.ty(), CertType::Intermediate);
1052
1053 let csr = Csr::generate(
1054 DirectoryName::new_common_name("ChillingInTheFuture.usobakkari"),
1055 &leaf_key,
1056 SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA1),
1057 )
1058 .unwrap();
1059
1060 let signed_leaf = CertificateBuilder::new()
1061 .validity(UTCDate::ymd(2069, 1, 1).unwrap(), UTCDate::ymd(2072, 1, 1).unwrap())
1062 .subject_from_csr(csr)
1063 .issuer_cert(&intermediate, &intermediate_key)
1064 .signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_384))
1065 .key_id_gen_method(KeyIdGenMethod::SPKFullDER(HashAlgorithm::SHA2_512))
1066 .pathlen(0) // not meaningful in non-CA certificates
1067 .build()
1068 .expect("couldn't build signed leaf");
1069 assert_eq!(signed_leaf.ty(), CertType::Leaf);
1070
1071 let chain = [intermediate, root];
1072
1073 // check with exact date
1074 signed_leaf
1075 .verifier()
1076 .chain(chain.iter())
1077 .exact_date(&UTCDate::ymd(2069, 10, 1).unwrap())
1078 .verify()
1079 .expect("couldn't verify chain");
1080
1081 // check with interval date
1082 signed_leaf
1083 .verifier()
1084 .chain(chain.iter())
1085 .interval_date(
1086 &UTCDate::new(2068, 12, 31, 23, 59, 59).unwrap(),
1087 &UTCDate::ymd(2069, 1, 1).unwrap(),
1088 )
1089 .verify()
1090 .expect("couldn't verify chain with interval date");
1091
1092 // check with ignore not before
1093 signed_leaf
1094 .verifier()
1095 .chain(chain.iter())
1096 .exact_date(&UTCDate::new(2068, 12, 31, 23, 59, 59).unwrap())
1097 .ignore_not_before_check()
1098 .verify()
1099 .expect("couldn't verify chain with interval date");
1100
1101 // check with no date validity check
1102 signed_leaf
1103 .verifier()
1104 .chain(chain.iter())
1105 .ignore_not_after_check()
1106 .ignore_not_before_check()
1107 .verify()
1108 .expect("couldn't verify chain with no date validity check");
1109
1110 let expired_err = signed_leaf
1111 .verifier()
1112 .chain(chain.iter())
1113 .exact_date(&UTCDate::ymd(2080, 10, 1).unwrap())
1114 .verify()
1115 .unwrap_err();
1116 assert_eq!(
1117 expired_err.to_string(),
1118 "invalid certificate \'CN=ChillingInTheFuture.usobakkari\': \
1119 certificate expired (not after: 2072-01-01 00:00:00, now: 2080-10-01 00:00:00)"
1120 );
1121
1122 let intermediate_expired_err = signed_leaf
1123 .verifier()
1124 .chain(chain.iter())
1125 .exact_date(&UTCDate::ymd(2071, 6, 1).unwrap())
1126 .verify()
1127 .unwrap_err();
1128 assert_eq!(
1129 intermediate_expired_err.to_string(),
1130 "invalid certificate \'CN=TheFuture.usodakedo Authority\': \
1131 certificate expired (not after: 2071-01-01 00:00:00, now: 2071-06-01 00:00:00)"
1132 );
1133
1134 let root_expired_err = signed_leaf
1135 .verifier()
1136 .chain(chain.iter())
1137 .exact_date(&UTCDate::ymd(2070, 6, 16).unwrap())
1138 .verify()
1139 .unwrap_err();
1140 assert_eq!(
1141 root_expired_err.to_string(),
1142 "invalid certificate \'CN=TheFuture.usodakedo Root CA\': \
1143 certificate expired (not after: 2070-06-15 00:00:00, now: 2070-06-16 00:00:00)"
1144 );
1145
1146 let still_in_2019_err = signed_leaf
1147 .verifier()
1148 .chain(chain.iter())
1149 .exact_date(&UTCDate::ymd(2019, 11, 14).unwrap())
1150 .verify()
1151 .unwrap_err();
1152 assert_eq!(
1153 still_in_2019_err.to_string(),
1154 "invalid certificate \'CN=ChillingInTheFuture.usobakkari\': \
1155 certificate is not yet valid (not before: 2069-01-01 00:00:00, now: 2019-11-14 00:00:00)"
1156 );
1157
1158 let not_yet_valid_with_interval_err = signed_leaf
1159 .verifier()
1160 .chain(chain.iter())
1161 .interval_date(
1162 &UTCDate::ymd(2068, 12, 30).unwrap(),
1163 &UTCDate::ymd(2068, 12, 31).unwrap(),
1164 )
1165 .verify()
1166 .unwrap_err();
1167 assert_eq!(
1168 not_yet_valid_with_interval_err.to_string(),
1169 "invalid certificate \'CN=ChillingInTheFuture.usobakkari\': \
1170 certificate is not yet valid (not before: 2069-01-01 00:00:00, now: 2068-12-31 00:00:00)"
1171 );
1172
1173 let date_is_missing_err = signed_leaf.verifier().chain(chain.iter()).verify().unwrap_err();
1174 assert_eq!(
1175 date_is_missing_err.to_string(),
1176 "missing required builder argument `now`"
1177 );
1178 }
1179
1180 #[test]
malicious_ca_chain()1181 fn malicious_ca_chain() {
1182 let root_key = parse_key(crate::test_files::RSA_2048_PK_1);
1183 let intermediate_key = parse_key(crate::test_files::RSA_2048_PK_2);
1184 let leaf_key = parse_key(crate::test_files::RSA_2048_PK_3);
1185 let malicious_root_key = parse_key(crate::test_files::RSA_2048_PK_4);
1186
1187 let root = CertificateBuilder::new()
1188 .validity(UTCDate::ymd(2065, 6, 15).unwrap(), UTCDate::ymd(2070, 6, 15).unwrap())
1189 .self_signed(DirectoryName::new_common_name("VerySafe Root CA"), &root_key)
1190 .ca(true)
1191 .pathlen(1)
1192 .signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA1))
1193 .key_id_gen_method(KeyIdGenMethod::SPKFullDER(HashAlgorithm::SHA2_224))
1194 .build()
1195 .expect("couldn't build root ca");
1196
1197 let intermediate = CertificateBuilder::new()
1198 .validity(UTCDate::ymd(2068, 1, 1).unwrap(), UTCDate::ymd(2071, 1, 1).unwrap())
1199 .subject(
1200 DirectoryName::new_common_name("V.E.R.Y Legitimate VerySafe Authority"),
1201 intermediate_key.to_public_key(),
1202 )
1203 .issuer_cert(&root, &malicious_root_key)
1204 .signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_512))
1205 .key_id_gen_method(KeyIdGenMethod::SPKValueHashedLeftmost160(HashAlgorithm::SHA2_384))
1206 .ca(true)
1207 .pathlen(0)
1208 .build()
1209 .expect("couldn't build intermediate ca");
1210
1211 let csr = Csr::generate(
1212 DirectoryName::new_common_name("I Trust This V.E.R.Y Legitimate Intermediate Certificate"),
1213 &leaf_key,
1214 SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA1),
1215 )
1216 .unwrap();
1217
1218 let signed_leaf = CertificateBuilder::new()
1219 .validity(UTCDate::ymd(2069, 1, 1).unwrap(), UTCDate::ymd(2072, 1, 1).unwrap())
1220 .subject_from_csr(csr)
1221 .issuer_cert(&intermediate, &intermediate_key)
1222 .signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_224))
1223 .key_id_gen_method(KeyIdGenMethod::SPKFullDER(HashAlgorithm::SHA2_384))
1224 .build()
1225 .expect("couldn't build signed leaf");
1226
1227 let chain = [intermediate, root];
1228
1229 let root_missing_err = signed_leaf
1230 .verifier()
1231 .chain(chain[..1].iter())
1232 .exact_date(&UTCDate::ymd(2069, 10, 1).unwrap())
1233 .verify()
1234 .unwrap_err();
1235 assert_eq!(
1236 root_missing_err.to_string(),
1237 "CA chain error: chain is missing a root certificate"
1238 );
1239
1240 let invalid_sig_err = signed_leaf
1241 .verifier()
1242 .chain(chain.iter())
1243 .exact_date(&UTCDate::ymd(2069, 10, 1).unwrap())
1244 .verify()
1245 .unwrap_err();
1246 assert_eq!(
1247 invalid_sig_err.to_string(),
1248 "invalid certificate \'CN=V.E.R.Y Legitimate VerySafe Authority\': signature error: invalid signature"
1249 );
1250 }
1251
1252 #[test]
invalid_basic_constraints_chain()1253 fn invalid_basic_constraints_chain() {
1254 let root_key = parse_key(crate::test_files::RSA_2048_PK_1);
1255 let intermediate_key = parse_key(crate::test_files::RSA_2048_PK_2);
1256 let leaf_key = parse_key(crate::test_files::RSA_2048_PK_3);
1257
1258 let root = CertificateBuilder::new()
1259 .validity(UTCDate::ymd(2065, 6, 15).unwrap(), UTCDate::ymd(2070, 6, 15).unwrap())
1260 .self_signed(DirectoryName::new_common_name("VerySafe Root CA"), &root_key)
1261 .ca(true)
1262 .pathlen(0)
1263 .build()
1264 .expect("couldn't build root ca");
1265
1266 let intermediate = CertificateBuilder::new()
1267 .validity(UTCDate::ymd(2068, 1, 1).unwrap(), UTCDate::ymd(2071, 1, 1).unwrap())
1268 .subject(
1269 DirectoryName::new_common_name("V.E.R.Y Legitimate VerySafe Authority"),
1270 intermediate_key.to_public_key(),
1271 )
1272 .issuer_cert(&root, &root_key)
1273 .ca(true)
1274 .pathlen(0)
1275 .build()
1276 .expect("couldn't build intermediate ca");
1277
1278 let csr = Csr::generate(
1279 DirectoryName::new_common_name("I Trust This V.E.R.Y Legitimate Intermediate Certificate"),
1280 &leaf_key,
1281 SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA1),
1282 )
1283 .unwrap();
1284
1285 let signed_leaf = CertificateBuilder::new()
1286 .validity(UTCDate::ymd(2069, 1, 1).unwrap(), UTCDate::ymd(2072, 1, 1).unwrap())
1287 .subject_from_csr(csr.clone())
1288 .issuer_cert(&intermediate, &intermediate_key)
1289 .build()
1290 .expect("couldn't build signed leaf");
1291
1292 let chain = [intermediate.clone(), root.clone()];
1293
1294 let invalid_pathlen_err = signed_leaf
1295 .verifier()
1296 .chain(chain.iter())
1297 .exact_date(&UTCDate::ymd(2069, 10, 1).unwrap())
1298 .verify()
1299 .unwrap_err();
1300 assert_eq!(
1301 invalid_pathlen_err.to_string(),
1302 "CA chain error: chain depth doesn\'t satisfy basic constraints extension: \
1303 certificate \'CN=VerySafe Root CA\' has pathlen of 0"
1304 );
1305
1306 let invalid_issuer_signed_leaf = CertificateBuilder::new()
1307 .validity(UTCDate::ymd(2069, 1, 1).unwrap(), UTCDate::ymd(2072, 1, 1).unwrap())
1308 .subject_from_csr(csr)
1309 .issuer_cert(&signed_leaf, &leaf_key)
1310 .build()
1311 .expect("couldn't build invalid issuer signed leaf");
1312
1313 let chain = [signed_leaf, intermediate.clone(), root.clone()];
1314
1315 let invalid_issuer_err = invalid_issuer_signed_leaf
1316 .verifier()
1317 .chain(chain.iter())
1318 .exact_date(&UTCDate::ymd(2069, 10, 1).unwrap())
1319 .verify()
1320 .unwrap_err();
1321 assert_eq!(
1322 invalid_issuer_err.to_string(),
1323 "CA chain error: issuer certificate \'CN=I Trust This V.E.R.Y Legitimate Intermediate Certificate\' is not a CA"
1324 );
1325 }
1326
1327 #[test]
bypass_serial_number_generator()1328 fn bypass_serial_number_generator() {
1329 let root_key = parse_key(crate::test_files::RSA_2048_PK_1);
1330
1331 let unsigned_integer_bytes = [21, 84, 58, 122];
1332
1333 let cert = CertificateBuilder::new()
1334 .validity(UTCDate::ymd(2065, 6, 15).unwrap(), UTCDate::ymd(2070, 6, 15).unwrap())
1335 .self_signed(DirectoryName::new_common_name("TheFuture.usodakedo Root CA"), &root_key)
1336 .ca(true)
1337 .signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_512))
1338 .key_id_gen_method(KeyIdGenMethod::SPKFullDER(HashAlgorithm::SHA2_384))
1339 .serial_number(unsigned_integer_bytes.to_vec())
1340 .build()
1341 .expect("couldn't build root ca");
1342
1343 assert_eq!(cert.serial_number().as_unsigned_bytes_be(), unsigned_integer_bytes);
1344 }
1345
1346 #[test]
validity_encoding()1347 fn validity_encoding() {
1348 use picky_asn1_x509::validity::Time;
1349
1350 let root_key = parse_key(crate::test_files::RSA_2048_PK_1);
1351
1352 let cert = CertificateBuilder::new()
1353 .validity(UTCDate::ymd(2045, 6, 15).unwrap(), UTCDate::ymd(2055, 6, 15).unwrap())
1354 .self_signed(DirectoryName::new_common_name("Am I valid"), &root_key)
1355 .ca(true)
1356 .signature_hash_type(SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA1))
1357 .key_id_gen_method(KeyIdGenMethod::SPKFullDER(HashAlgorithm::SHA2_224))
1358 .build()
1359 .expect("couldn't build root ca");
1360
1361 let validity = &cert.0.tbs_certificate.validity;
1362
1363 assert!(matches!(validity.not_before, Time::UTC(_)));
1364 assert!(matches!(validity.not_after, Time::Generalized(_)));
1365 }
1366
1367 #[test]
inherit_requested_extensions_by_csr()1368 fn inherit_requested_extensions_by_csr() {
1369 use crate::x509::name::GeneralName;
1370
1371 let root_key = parse_key(crate::test_files::RSA_2048_PK_1);
1372 let leaf_key = parse_key(crate::test_files::RSA_2048_PK_3);
1373
1374 let root = CertificateBuilder::new()
1375 .validity(UTCDate::ymd(2065, 6, 15).unwrap(), UTCDate::ymd(2070, 6, 15).unwrap())
1376 .self_signed(DirectoryName::new_common_name("VerySafe Root CA"), &root_key)
1377 .ca(true)
1378 .pathlen(0)
1379 .build()
1380 .expect("couldn't build root ca");
1381
1382 let extensions =
1383 vec![Extension::new_subject_alt_name(GeneralName::new_dns_name("localhost").unwrap()).into_non_critical()];
1384 let attr = Attribute::new_extension_request(extensions);
1385 let csr = Csr::generate_with_attributes(
1386 DirectoryName::new_common_name("I want more extensions"),
1387 &leaf_key,
1388 SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_256),
1389 vec![attr],
1390 )
1391 .unwrap();
1392
1393 let signed_leaf = CertificateBuilder::new()
1394 .validity(UTCDate::ymd(2069, 1, 1).unwrap(), UTCDate::ymd(2072, 1, 1).unwrap())
1395 .subject_from_csr(csr)
1396 .issuer_cert(&root, &root_key)
1397 .inherit_extensions_from_csr_attributes(true)
1398 .build()
1399 .expect("couldn't build signed leaf");
1400
1401 let subject_alt_name = signed_leaf
1402 .extensions()
1403 .iter()
1404 .find_map(|ext| match ext.extn_value() {
1405 ExtensionView::SubjectAltName(gn) => match gn.0.first().unwrap() {
1406 picky_asn1_x509::GeneralName::DNSName(name) => Some(name.to_string()),
1407 _ => None,
1408 },
1409 _ => None,
1410 })
1411 .unwrap();
1412
1413 assert_eq!(subject_alt_name, "localhost");
1414 }
1415 }
1416