1use std::net::IpAddr;
2use std::str::FromStr;
3
4#[cfg(feature = "pem")]
5use pem::Pem;
6use pki_types::{CertificateDer, CertificateSigningRequestDer};
7use time::{Date, Month, OffsetDateTime, PrimitiveDateTime, Time};
8use yasna::models::ObjectIdentifier;
9use yasna::{DERWriter, Tag};
10
11use crate::crl::CrlDistributionPoint;
12use crate::csr::CertificateSigningRequest;
13use crate::key_pair::{serialize_public_key_der, PublicKeyData};
14#[cfg(feature = "crypto")]
15use crate::ring_like::digest;
16#[cfg(feature = "pem")]
17use crate::ENCODE_CONFIG;
18use crate::{
19 oid, write_distinguished_name, write_dt_utc_or_generalized,
20 write_x509_authority_key_identifier, write_x509_extension, DistinguishedName, Error, Issuer,
21 KeyIdMethod, KeyPair, KeyUsagePurpose, SanType, SerialNumber,
22};
23
24pub struct Certificate {
26 pub(crate) params: CertificateParams,
27 pub(crate) subject_public_key_info: Vec<u8>,
28 pub(crate) der: CertificateDer<'static>,
29}
30
31impl Certificate {
32 pub fn params(&self) -> &CertificateParams {
34 &self.params
35 }
36 pub fn key_identifier(&self) -> Vec<u8> {
39 self.params
40 .key_identifier_method
41 .derive(&self.subject_public_key_info)
42 }
43 pub fn der(&self) -> &CertificateDer<'static> {
48 &self.der
49 }
50 #[cfg(feature = "pem")]
52 pub fn pem(&self) -> String {
53 pem::encode_config(&Pem::new("CERTIFICATE", self.der().to_vec()), ENCODE_CONFIG)
54 }
55}
56
57impl From<Certificate> for CertificateDer<'static> {
58 fn from(cert: Certificate) -> Self {
59 cert.der
60 }
61}
62
63#[allow(missing_docs)]
65#[non_exhaustive]
66#[derive(Debug, PartialEq, Eq, Clone)]
67pub struct CertificateParams {
68 pub not_before: OffsetDateTime,
69 pub not_after: OffsetDateTime,
70 pub serial_number: Option<SerialNumber>,
71 pub subject_alt_names: Vec<SanType>,
72 pub distinguished_name: DistinguishedName,
73 pub is_ca: IsCa,
74 pub key_usages: Vec<KeyUsagePurpose>,
75 pub extended_key_usages: Vec<ExtendedKeyUsagePurpose>,
76 pub name_constraints: Option<NameConstraints>,
77 pub crl_distribution_points: Vec<CrlDistributionPoint>,
83 pub custom_extensions: Vec<CustomExtension>,
84 pub use_authority_key_identifier_extension: bool,
86 pub key_identifier_method: KeyIdMethod,
90}
91
92impl Default for CertificateParams {
93 fn default() -> Self {
94 let not_before = date_time_ymd(1975, 01, 01);
96 let not_after = date_time_ymd(4096, 01, 01);
97 let mut distinguished_name = DistinguishedName::new();
98 distinguished_name.push(DnType::CommonName, "rcgen self signed cert");
99 CertificateParams {
100 not_before,
101 not_after,
102 serial_number: None,
103 subject_alt_names: Vec::new(),
104 distinguished_name,
105 is_ca: IsCa::NoCa,
106 key_usages: Vec::new(),
107 extended_key_usages: Vec::new(),
108 name_constraints: None,
109 crl_distribution_points: Vec::new(),
110 custom_extensions: Vec::new(),
111 use_authority_key_identifier_extension: false,
112 #[cfg(feature = "crypto")]
113 key_identifier_method: KeyIdMethod::Sha256,
114 #[cfg(not(feature = "crypto"))]
115 key_identifier_method: KeyIdMethod::PreSpecified(Vec::new()),
116 }
117 }
118}
119
120impl CertificateParams {
121 pub fn new(subject_alt_names: impl Into<Vec<String>>) -> Result<Self, Error> {
123 let subject_alt_names = subject_alt_names
124 .into()
125 .into_iter()
126 .map(|s| {
127 Ok(match IpAddr::from_str(&s) {
128 Ok(ip) => SanType::IpAddress(ip),
129 Err(_) => SanType::DnsName(s.try_into()?),
130 })
131 })
132 .collect::<Result<Vec<_>, _>>()?;
133 Ok(CertificateParams {
134 subject_alt_names,
135 ..Default::default()
136 })
137 }
138
139 pub fn signed_by(
151 self,
152 public_key: &impl PublicKeyData,
153 issuer: &Certificate,
154 issuer_key: &KeyPair,
155 ) -> Result<Certificate, Error> {
156 let issuer = Issuer {
157 distinguished_name: &issuer.params.distinguished_name,
158 key_identifier_method: &issuer.params.key_identifier_method,
159 key_usages: &issuer.params.key_usages,
160 key_pair: issuer_key,
161 };
162
163 let subject_public_key_info =
164 yasna::construct_der(|writer| serialize_public_key_der(public_key, writer));
165 let der = self.serialize_der_with_signer(public_key, issuer)?;
166 Ok(Certificate {
167 params: self,
168 subject_public_key_info,
169 der,
170 })
171 }
172
173 pub fn self_signed(self, key_pair: &KeyPair) -> Result<Certificate, Error> {
178 let issuer = Issuer {
179 distinguished_name: &self.distinguished_name,
180 key_identifier_method: &self.key_identifier_method,
181 key_usages: &self.key_usages,
182 key_pair,
183 };
184
185 let subject_public_key_info = key_pair.public_key_der();
186 let der = self.serialize_der_with_signer(key_pair, issuer)?;
187 Ok(Certificate {
188 params: self,
189 subject_public_key_info,
190 der,
191 })
192 }
193
194 #[cfg(all(feature = "pem", feature = "x509-parser"))]
198 pub fn from_ca_cert_pem(pem_str: &str) -> Result<Self, Error> {
199 let certificate = pem::parse(pem_str).or(Err(Error::CouldNotParseCertificate))?;
200 Self::from_ca_cert_der(&certificate.contents().into())
201 }
202
203 #[cfg(feature = "x509-parser")]
225 pub fn from_ca_cert_der(ca_cert: &CertificateDer<'_>) -> Result<Self, Error> {
226 let (_remainder, x509) = x509_parser::parse_x509_certificate(ca_cert)
227 .or(Err(Error::CouldNotParseCertificate))?;
228
229 let dn = DistinguishedName::from_name(&x509.tbs_certificate.subject)?;
230 let is_ca = Self::convert_x509_is_ca(&x509)?;
231 let validity = x509.validity();
232 let subject_alt_names = Self::convert_x509_subject_alternative_name(&x509)?;
233 let key_usages = Self::convert_x509_key_usages(&x509)?;
234 let extended_key_usages = Self::convert_x509_extended_key_usages(&x509)?;
235 let name_constraints = Self::convert_x509_name_constraints(&x509)?;
236 let serial_number = Some(x509.serial.to_bytes_be().into());
237
238 let key_identifier_method =
239 x509.iter_extensions()
240 .find_map(|ext| match ext.parsed_extension() {
241 x509_parser::extensions::ParsedExtension::SubjectKeyIdentifier(key_id) => {
242 Some(KeyIdMethod::PreSpecified(key_id.0.into()))
243 },
244 _ => None,
245 });
246
247 let key_identifier_method = match key_identifier_method {
248 Some(method) => method,
249 None => {
250 #[cfg(not(feature = "crypto"))]
251 return Err(Error::UnsupportedSignatureAlgorithm);
252 #[cfg(feature = "crypto")]
253 KeyIdMethod::Sha256
254 },
255 };
256
257 Ok(CertificateParams {
258 is_ca,
259 subject_alt_names,
260 key_usages,
261 extended_key_usages,
262 name_constraints,
263 serial_number,
264 key_identifier_method,
265 distinguished_name: dn,
266 not_before: validity.not_before.to_datetime(),
267 not_after: validity.not_after.to_datetime(),
268 ..Default::default()
269 })
270 }
271 #[cfg(feature = "x509-parser")]
272 fn convert_x509_is_ca(
273 x509: &x509_parser::certificate::X509Certificate<'_>,
274 ) -> Result<IsCa, Error> {
275 use x509_parser::extensions::BasicConstraints as B;
276
277 let basic_constraints = x509
278 .basic_constraints()
279 .or(Err(Error::CouldNotParseCertificate))?
280 .map(|ext| ext.value);
281
282 let is_ca = match basic_constraints {
283 Some(B {
284 ca: true,
285 path_len_constraint: Some(n),
286 }) if *n <= u8::MAX as u32 => IsCa::Ca(BasicConstraints::Constrained(*n as u8)),
287 Some(B {
288 ca: true,
289 path_len_constraint: Some(_),
290 }) => return Err(Error::CouldNotParseCertificate),
291 Some(B {
292 ca: true,
293 path_len_constraint: None,
294 }) => IsCa::Ca(BasicConstraints::Unconstrained),
295 Some(B { ca: false, .. }) => IsCa::ExplicitNoCa,
296 None => IsCa::NoCa,
297 };
298
299 Ok(is_ca)
300 }
301 #[cfg(feature = "x509-parser")]
302 fn convert_x509_subject_alternative_name(
303 x509: &x509_parser::certificate::X509Certificate<'_>,
304 ) -> Result<Vec<SanType>, Error> {
305 let sans = x509
306 .subject_alternative_name()
307 .or(Err(Error::CouldNotParseCertificate))?
308 .map(|ext| &ext.value.general_names);
309
310 if let Some(sans) = sans {
311 let mut subject_alt_names = Vec::with_capacity(sans.len());
312 for san in sans {
313 subject_alt_names.push(SanType::try_from_general(san)?);
314 }
315 Ok(subject_alt_names)
316 } else {
317 Ok(Vec::new())
318 }
319 }
320 #[cfg(feature = "x509-parser")]
321 fn convert_x509_key_usages(
322 x509: &x509_parser::certificate::X509Certificate<'_>,
323 ) -> Result<Vec<KeyUsagePurpose>, Error> {
324 let key_usage = x509
325 .key_usage()
326 .or(Err(Error::CouldNotParseCertificate))?
327 .map(|ext| ext.value);
328 let flags = key_usage.map_or(0u16, |k| k.flags).reverse_bits();
330 Ok(KeyUsagePurpose::from_u16(flags))
331 }
332 #[cfg(feature = "x509-parser")]
333 fn convert_x509_extended_key_usages(
334 x509: &x509_parser::certificate::X509Certificate<'_>,
335 ) -> Result<Vec<ExtendedKeyUsagePurpose>, Error> {
336 let extended_key_usage = x509
337 .extended_key_usage()
338 .or(Err(Error::CouldNotParseCertificate))?
339 .map(|ext| ext.value);
340
341 let mut extended_key_usages = Vec::new();
342 if let Some(extended_key_usage) = extended_key_usage {
343 if extended_key_usage.any {
344 extended_key_usages.push(ExtendedKeyUsagePurpose::Any);
345 }
346 if extended_key_usage.server_auth {
347 extended_key_usages.push(ExtendedKeyUsagePurpose::ServerAuth);
348 }
349 if extended_key_usage.client_auth {
350 extended_key_usages.push(ExtendedKeyUsagePurpose::ClientAuth);
351 }
352 if extended_key_usage.code_signing {
353 extended_key_usages.push(ExtendedKeyUsagePurpose::CodeSigning);
354 }
355 if extended_key_usage.email_protection {
356 extended_key_usages.push(ExtendedKeyUsagePurpose::EmailProtection);
357 }
358 if extended_key_usage.time_stamping {
359 extended_key_usages.push(ExtendedKeyUsagePurpose::TimeStamping);
360 }
361 if extended_key_usage.ocsp_signing {
362 extended_key_usages.push(ExtendedKeyUsagePurpose::OcspSigning);
363 }
364 }
365 Ok(extended_key_usages)
366 }
367 #[cfg(feature = "x509-parser")]
368 fn convert_x509_name_constraints(
369 x509: &x509_parser::certificate::X509Certificate<'_>,
370 ) -> Result<Option<NameConstraints>, Error> {
371 let constraints = x509
372 .name_constraints()
373 .or(Err(Error::CouldNotParseCertificate))?
374 .map(|ext| ext.value);
375
376 if let Some(constraints) = constraints {
377 let permitted_subtrees = if let Some(permitted) = &constraints.permitted_subtrees {
378 Self::convert_x509_general_subtrees(permitted)?
379 } else {
380 Vec::new()
381 };
382
383 let excluded_subtrees = if let Some(excluded) = &constraints.excluded_subtrees {
384 Self::convert_x509_general_subtrees(excluded)?
385 } else {
386 Vec::new()
387 };
388
389 let name_constraints = NameConstraints {
390 permitted_subtrees,
391 excluded_subtrees,
392 };
393
394 Ok(Some(name_constraints))
395 } else {
396 Ok(None)
397 }
398 }
399 #[cfg(feature = "x509-parser")]
400 fn convert_x509_general_subtrees(
401 subtrees: &[x509_parser::extensions::GeneralSubtree<'_>],
402 ) -> Result<Vec<GeneralSubtree>, Error> {
403 use x509_parser::extensions::GeneralName;
404
405 let mut result = Vec::new();
406 for subtree in subtrees {
407 let subtree = match &subtree.base {
408 GeneralName::RFC822Name(s) => GeneralSubtree::Rfc822Name(s.to_string()),
409 GeneralName::DNSName(s) => GeneralSubtree::DnsName(s.to_string()),
410 GeneralName::DirectoryName(n) => {
411 GeneralSubtree::DirectoryName(DistinguishedName::from_name(n)?)
412 },
413 GeneralName::IPAddress(bytes) if bytes.len() == 8 => {
414 let addr: [u8; 4] = bytes[..4].try_into().unwrap();
415 let mask: [u8; 4] = bytes[4..].try_into().unwrap();
416 GeneralSubtree::IpAddress(CidrSubnet::V4(addr, mask))
417 },
418 GeneralName::IPAddress(bytes) if bytes.len() == 32 => {
419 let addr: [u8; 16] = bytes[..16].try_into().unwrap();
420 let mask: [u8; 16] = bytes[16..].try_into().unwrap();
421 GeneralSubtree::IpAddress(CidrSubnet::V6(addr, mask))
422 },
423 _ => continue,
424 };
425 result.push(subtree);
426 }
427 Ok(result)
428 }
429
430 fn write_extension_request_attribute(&self, writer: DERWriter) {
434 writer.write_sequence(|writer| {
435 writer.next().write_oid(&ObjectIdentifier::from_slice(
436 oid::PKCS_9_AT_EXTENSION_REQUEST,
437 ));
438 writer.next().write_set(|writer| {
439 writer.next().write_sequence(|writer| {
440 self.write_key_usage(writer.next());
442 self.write_subject_alt_names(writer.next());
444 self.write_extended_key_usage(writer.next());
445
446 for ext in &self.custom_extensions {
448 write_x509_extension(writer.next(), &ext.oid, ext.critical, |writer| {
449 writer.write_der(ext.content())
450 });
451 }
452 });
453 });
454 });
455 }
456
457 fn write_key_usage(&self, writer: DERWriter) {
459 const KEY_USAGE_BITS: usize = 9;
462 if self.key_usages.is_empty() {
463 return;
464 }
465
466 write_x509_extension(writer, oid::KEY_USAGE, true, |writer| {
468 let bit_string = self.key_usages.iter().fold(0u16, |bit_string, key_usage| {
470 bit_string | key_usage.to_u16()
471 });
472 writer.write_bitvec_bytes(&bit_string.to_be_bytes(), KEY_USAGE_BITS);
473 });
474 }
475
476 fn write_extended_key_usage(&self, writer: DERWriter) {
477 if !self.extended_key_usages.is_empty() {
478 write_x509_extension(writer, oid::EXT_KEY_USAGE, false, |writer| {
479 writer.write_sequence(|writer| {
480 for usage in &self.extended_key_usages {
481 writer
482 .next()
483 .write_oid(&ObjectIdentifier::from_slice(usage.oid()));
484 }
485 });
486 });
487 }
488 }
489
490 fn write_subject_alt_names(&self, writer: DERWriter) {
491 if self.subject_alt_names.is_empty() {
492 return;
493 }
494
495 write_x509_extension(writer, oid::SUBJECT_ALT_NAME, false, |writer| {
496 writer.write_sequence(|writer| {
497 for san in self.subject_alt_names.iter() {
498 writer.next().write_tagged_implicit(
499 Tag::context(san.tag()),
500 |writer| match san {
501 SanType::Rfc822Name(name)
502 | SanType::DnsName(name)
503 | SanType::URI(name) => writer.write_ia5_string(name.as_str()),
504 SanType::IpAddress(IpAddr::V4(addr)) => {
505 writer.write_bytes(&addr.octets())
506 },
507 SanType::IpAddress(IpAddr::V6(addr)) => {
508 writer.write_bytes(&addr.octets())
509 },
510 SanType::OtherName((oid, value)) => {
511 writer.write_sequence(|writer| {
514 writer.next().write_oid(&ObjectIdentifier::from_slice(oid));
515 value.write_der(writer.next());
516 });
517 },
518 },
519 );
520 }
521 });
522 });
523 }
524
525 pub fn serialize_request(
534 &self,
535 subject_key: &KeyPair,
536 ) -> Result<CertificateSigningRequest, Error> {
537 self.serialize_request_with_attributes(subject_key, Vec::new())
538 }
539
540 pub fn serialize_request_with_attributes(
552 &self,
553 subject_key: &KeyPair,
554 attrs: Vec<Attribute>,
555 ) -> Result<CertificateSigningRequest, Error> {
556 #[deny(unused)]
558 let Self {
559 not_before,
560 not_after,
561 serial_number,
562 subject_alt_names,
563 distinguished_name,
564 is_ca,
565 key_usages,
566 extended_key_usages,
567 name_constraints,
568 crl_distribution_points,
569 custom_extensions,
570 use_authority_key_identifier_extension,
571 key_identifier_method,
572 } = self;
573 let _ = (
581 not_before,
582 not_after,
583 key_identifier_method,
584 extended_key_usages,
585 );
586 if serial_number.is_some()
587 || *is_ca != IsCa::NoCa
588 || name_constraints.is_some()
589 || !crl_distribution_points.is_empty()
590 || *use_authority_key_identifier_extension
591 {
592 return Err(Error::UnsupportedInCsr);
593 }
594
595 let write_extension_request = !key_usages.is_empty()
597 || !subject_alt_names.is_empty()
598 || !extended_key_usages.is_empty()
599 || !custom_extensions.is_empty();
600
601 let der = subject_key.sign_der(|writer| {
602 writer.next().write_u8(0);
604 write_distinguished_name(writer.next(), distinguished_name);
605 serialize_public_key_der(subject_key, writer.next());
606
607 writer
609 .next()
610 .write_tagged_implicit(Tag::context(0), |writer| {
611 writer.write_set_of(|writer| {
613 if write_extension_request {
614 self.write_extension_request_attribute(writer.next());
615 }
616
617 for Attribute { oid, values } in attrs {
618 writer.next().write_sequence(|writer| {
619 writer.next().write_oid(&ObjectIdentifier::from_slice(&oid));
620 writer.next().write_der(&values);
621 });
622 }
623 });
624 });
625
626 Ok(())
627 })?;
628
629 Ok(CertificateSigningRequest {
630 der: CertificateSigningRequestDer::from(der),
631 })
632 }
633
634 pub(crate) fn serialize_der_with_signer<K: PublicKeyData>(
635 &self,
636 pub_key: &K,
637 issuer: Issuer<'_>,
638 ) -> Result<CertificateDer<'static>, Error> {
639 let der = issuer.key_pair.sign_der(|writer| {
640 let pub_key_spki =
641 yasna::construct_der(|writer| serialize_public_key_der(pub_key, writer));
642 writer.next().write_tagged(Tag::context(0), |writer| {
644 writer.write_u8(2);
645 });
646 if let Some(ref serial) = self.serial_number {
648 writer.next().write_bigint_bytes(serial.as_ref(), true);
649 } else {
650 #[cfg(feature = "crypto")]
651 {
652 let hash = digest::digest(&digest::SHA256, pub_key.der_bytes());
653 let mut sl = hash.as_ref()[0..20].to_vec();
655 sl[0] &= 0x7f; writer.next().write_bigint_bytes(&sl, true);
657 }
658 #[cfg(not(feature = "crypto"))]
659 if self.serial_number.is_none() {
660 return Err(Error::MissingSerialNumber);
661 }
662 };
663 issuer.key_pair.alg.write_alg_ident(writer.next());
665 write_distinguished_name(writer.next(), &issuer.distinguished_name);
667 writer.next().write_sequence(|writer| {
669 write_dt_utc_or_generalized(writer.next(), self.not_before);
671 write_dt_utc_or_generalized(writer.next(), self.not_after);
673 Ok::<(), Error>(())
674 })?;
675 write_distinguished_name(writer.next(), &self.distinguished_name);
677 serialize_public_key_der(pub_key, writer.next());
679 let should_write_exts = self.use_authority_key_identifier_extension
681 || !self.subject_alt_names.is_empty()
682 || !self.extended_key_usages.is_empty()
683 || self.name_constraints.iter().any(|c| !c.is_empty())
684 || matches!(self.is_ca, IsCa::ExplicitNoCa)
685 || matches!(self.is_ca, IsCa::Ca(_))
686 || !self.custom_extensions.is_empty();
687 if !should_write_exts {
688 return Ok(());
689 }
690
691 writer.next().write_tagged(Tag::context(3), |writer| {
692 writer.write_sequence(|writer| {
693 if self.use_authority_key_identifier_extension {
694 write_x509_authority_key_identifier(
695 writer.next(),
696 match issuer.key_identifier_method {
697 KeyIdMethod::PreSpecified(aki) => aki.clone(),
698 #[cfg(feature = "crypto")]
699 _ => issuer
700 .key_identifier_method
701 .derive(issuer.key_pair.public_key_der()),
702 },
703 );
704 }
705 if !self.subject_alt_names.is_empty() {
707 self.write_subject_alt_names(writer.next());
708 }
709
710 self.write_key_usage(writer.next());
712
713 if !self.extended_key_usages.is_empty() {
715 write_x509_extension(writer.next(), oid::EXT_KEY_USAGE, false, |writer| {
716 writer.write_sequence(|writer| {
717 for usage in self.extended_key_usages.iter() {
718 let oid = ObjectIdentifier::from_slice(usage.oid());
719 writer.next().write_oid(&oid);
720 }
721 });
722 });
723 }
724 if let Some(name_constraints) = &self.name_constraints {
725 if !name_constraints.is_empty() {
727 write_x509_extension(
728 writer.next(),
729 oid::NAME_CONSTRAINTS,
730 true,
731 |writer| {
732 writer.write_sequence(|writer| {
733 if !name_constraints.permitted_subtrees.is_empty() {
734 write_general_subtrees(
735 writer.next(),
736 0,
737 &name_constraints.permitted_subtrees,
738 );
739 }
740 if !name_constraints.excluded_subtrees.is_empty() {
741 write_general_subtrees(
742 writer.next(),
743 1,
744 &name_constraints.excluded_subtrees,
745 );
746 }
747 });
748 },
749 );
750 }
751 }
752 if !self.crl_distribution_points.is_empty() {
753 write_x509_extension(
754 writer.next(),
755 oid::CRL_DISTRIBUTION_POINTS,
756 false,
757 |writer| {
758 writer.write_sequence(|writer| {
759 for distribution_point in &self.crl_distribution_points {
760 distribution_point.write_der(writer.next());
761 }
762 })
763 },
764 );
765 }
766 match self.is_ca {
767 IsCa::Ca(ref constraint) => {
768 write_x509_extension(
770 writer.next(),
771 oid::SUBJECT_KEY_IDENTIFIER,
772 false,
773 |writer| {
774 writer.write_bytes(
775 &self.key_identifier_method.derive(pub_key_spki),
776 );
777 },
778 );
779 write_x509_extension(
781 writer.next(),
782 oid::BASIC_CONSTRAINTS,
783 true,
784 |writer| {
785 writer.write_sequence(|writer| {
786 writer.next().write_bool(true); if let BasicConstraints::Constrained(path_len_constraint) =
788 constraint
789 {
790 writer.next().write_u8(*path_len_constraint);
791 }
792 });
793 },
794 );
795 },
796 IsCa::ExplicitNoCa => {
797 write_x509_extension(
799 writer.next(),
800 oid::SUBJECT_KEY_IDENTIFIER,
801 false,
802 |writer| {
803 writer.write_bytes(
804 &self.key_identifier_method.derive(pub_key_spki),
805 );
806 },
807 );
808 write_x509_extension(
810 writer.next(),
811 oid::BASIC_CONSTRAINTS,
812 true,
813 |writer| {
814 writer.write_sequence(|writer| {
815 writer.next().write_bool(false); });
817 },
818 );
819 },
820 IsCa::NoCa => {},
821 }
822
823 for ext in &self.custom_extensions {
825 write_x509_extension(writer.next(), &ext.oid, ext.critical, |writer| {
826 writer.write_der(ext.content())
827 });
828 }
829 });
830 });
831
832 Ok(())
833 })?;
834
835 Ok(der.into())
836 }
837
838 pub fn insert_extended_key_usage(&mut self, eku: ExtendedKeyUsagePurpose) {
840 if !self.extended_key_usages.contains(&eku) {
841 self.extended_key_usages.push(eku);
842 }
843 }
844}
845
846fn write_general_subtrees(writer: DERWriter, tag: u64, general_subtrees: &[GeneralSubtree]) {
847 writer.write_tagged_implicit(Tag::context(tag), |writer| {
848 writer.write_sequence(|writer| {
849 for subtree in general_subtrees.iter() {
850 writer.next().write_sequence(|writer| {
851 writer
852 .next()
853 .write_tagged_implicit(
854 Tag::context(subtree.tag()),
855 |writer| match subtree {
856 GeneralSubtree::Rfc822Name(name)
857 | GeneralSubtree::DnsName(name) => writer.write_ia5_string(name),
858 GeneralSubtree::DirectoryName(name) => {
859 write_distinguished_name(writer, name)
860 },
861 GeneralSubtree::IpAddress(subnet) => {
862 writer.write_bytes(&subnet.to_bytes())
863 },
864 },
865 );
866 });
868 }
869 });
870 });
871}
872
873#[derive(Debug, PartialEq, Eq, Hash, Clone)]
879pub struct Attribute {
880 pub oid: &'static [u64],
882 pub values: Vec<u8>,
890}
891
892#[derive(Debug, PartialEq, Eq, Hash, Clone)]
895pub struct CustomExtension {
896 oid: Vec<u64>,
897 critical: bool,
898
899 content: Vec<u8>,
901}
902
903impl CustomExtension {
904 pub fn new_acme_identifier(sha_digest: &[u8]) -> Self {
909 assert_eq!(sha_digest.len(), 32, "wrong size of sha_digest");
910 let content = yasna::construct_der(|writer| {
911 writer.write_bytes(sha_digest);
912 });
913 Self {
914 oid: oid::PE_ACME.to_owned(),
915 critical: true,
916 content,
917 }
918 }
919 pub fn from_oid_content(oid: &[u64], content: Vec<u8>) -> Self {
921 Self {
922 oid: oid.to_owned(),
923 critical: false,
924 content,
925 }
926 }
927 pub fn set_criticality(&mut self, criticality: bool) {
929 self.critical = criticality;
930 }
931 pub fn criticality(&self) -> bool {
933 self.critical
934 }
935 pub fn content(&self) -> &[u8] {
937 &self.content
938 }
939 pub fn oid_components(&self) -> impl Iterator<Item = u64> + '_ {
941 self.oid.iter().copied()
942 }
943}
944
945#[derive(Debug, PartialEq, Eq, Hash, Clone)]
946#[non_exhaustive]
947pub enum DnType {
949 CountryName,
951 LocalityName,
953 StateOrProvinceName,
955 OrganizationName,
957 OrganizationalUnitName,
959 CommonName,
961 CustomDnType(Vec<u64>),
963}
964
965impl DnType {
966 pub(crate) fn to_oid(&self) -> ObjectIdentifier {
967 let sl = match self {
968 DnType::CountryName => oid::COUNTRY_NAME,
969 DnType::LocalityName => oid::LOCALITY_NAME,
970 DnType::StateOrProvinceName => oid::STATE_OR_PROVINCE_NAME,
971 DnType::OrganizationName => oid::ORG_NAME,
972 DnType::OrganizationalUnitName => oid::ORG_UNIT_NAME,
973 DnType::CommonName => oid::COMMON_NAME,
974 DnType::CustomDnType(ref oid) => oid.as_slice(),
975 };
976 ObjectIdentifier::from_slice(sl)
977 }
978
979 pub fn from_oid(slice: &[u64]) -> Self {
981 match slice {
982 oid::COUNTRY_NAME => DnType::CountryName,
983 oid::LOCALITY_NAME => DnType::LocalityName,
984 oid::STATE_OR_PROVINCE_NAME => DnType::StateOrProvinceName,
985 oid::ORG_NAME => DnType::OrganizationName,
986 oid::ORG_UNIT_NAME => DnType::OrganizationalUnitName,
987 oid::COMMON_NAME => DnType::CommonName,
988 oid => DnType::CustomDnType(oid.into()),
989 }
990 }
991}
992
993#[derive(Debug, PartialEq, Eq, Hash, Clone)]
994pub enum ExtendedKeyUsagePurpose {
996 Any,
998 ServerAuth,
1000 ClientAuth,
1002 CodeSigning,
1004 EmailProtection,
1006 TimeStamping,
1008 OcspSigning,
1010 Other(Vec<u64>),
1012}
1013
1014impl ExtendedKeyUsagePurpose {
1015 fn oid(&self) -> &[u64] {
1016 use ExtendedKeyUsagePurpose::*;
1017 match self {
1018 Any => &[2, 5, 29, 37, 0],
1020 ServerAuth => &[1, 3, 6, 1, 5, 5, 7, 3, 1],
1022 ClientAuth => &[1, 3, 6, 1, 5, 5, 7, 3, 2],
1023 CodeSigning => &[1, 3, 6, 1, 5, 5, 7, 3, 3],
1024 EmailProtection => &[1, 3, 6, 1, 5, 5, 7, 3, 4],
1025 TimeStamping => &[1, 3, 6, 1, 5, 5, 7, 3, 8],
1026 OcspSigning => &[1, 3, 6, 1, 5, 5, 7, 3, 9],
1027 Other(oid) => oid,
1028 }
1029 }
1030}
1031
1032#[derive(Debug, PartialEq, Eq, Clone)]
1035pub struct NameConstraints {
1036 pub permitted_subtrees: Vec<GeneralSubtree>,
1038 pub excluded_subtrees: Vec<GeneralSubtree>,
1042}
1043
1044impl NameConstraints {
1045 fn is_empty(&self) -> bool {
1046 self.permitted_subtrees.is_empty() && self.excluded_subtrees.is_empty()
1047 }
1048}
1049
1050#[derive(Debug, PartialEq, Eq, Clone)]
1051#[allow(missing_docs)]
1052#[non_exhaustive]
1053pub enum GeneralSubtree {
1059 Rfc822Name(String),
1061 DnsName(String),
1062 DirectoryName(DistinguishedName),
1063 IpAddress(CidrSubnet),
1064}
1065
1066impl GeneralSubtree {
1067 fn tag(&self) -> u64 {
1068 const TAG_RFC822_NAME: u64 = 1;
1071 const TAG_DNS_NAME: u64 = 2;
1072 const TAG_DIRECTORY_NAME: u64 = 4;
1073 const TAG_IP_ADDRESS: u64 = 7;
1074
1075 match self {
1076 GeneralSubtree::Rfc822Name(_name) => TAG_RFC822_NAME,
1077 GeneralSubtree::DnsName(_name) => TAG_DNS_NAME,
1078 GeneralSubtree::DirectoryName(_name) => TAG_DIRECTORY_NAME,
1079 GeneralSubtree::IpAddress(_addr) => TAG_IP_ADDRESS,
1080 }
1081 }
1082}
1083
1084#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1085#[allow(missing_docs)]
1086pub enum CidrSubnet {
1095 V4([u8; 4], [u8; 4]),
1096 V6([u8; 16], [u8; 16]),
1097}
1098
1099macro_rules! mask {
1100 ($t:ty, $d:expr) => {{
1101 let v = <$t>::max_value();
1102 let v = v.checked_shr($d as u32).unwrap_or(0);
1103 (!v).to_be_bytes()
1104 }};
1105}
1106
1107impl CidrSubnet {
1108 pub fn from_addr_prefix(addr: IpAddr, prefix: u8) -> Self {
1122 match addr {
1123 IpAddr::V4(addr) => Self::from_v4_prefix(addr.octets(), prefix),
1124 IpAddr::V6(addr) => Self::from_v6_prefix(addr.octets(), prefix),
1125 }
1126 }
1127 pub fn from_v4_prefix(addr: [u8; 4], prefix: u8) -> Self {
1130 CidrSubnet::V4(addr, mask!(u32, prefix))
1131 }
1132 pub fn from_v6_prefix(addr: [u8; 16], prefix: u8) -> Self {
1135 CidrSubnet::V6(addr, mask!(u128, prefix))
1136 }
1137 fn to_bytes(&self) -> Vec<u8> {
1138 let mut res = Vec::new();
1139 match self {
1140 CidrSubnet::V4(addr, mask) => {
1141 res.extend_from_slice(addr);
1142 res.extend_from_slice(mask);
1143 },
1144 CidrSubnet::V6(addr, mask) => {
1145 res.extend_from_slice(addr);
1146 res.extend_from_slice(mask);
1147 },
1148 }
1149 res
1150 }
1151}
1152
1153impl FromStr for CidrSubnet {
1164 type Err = ();
1165
1166 fn from_str(s: &str) -> Result<Self, Self::Err> {
1167 let mut iter = s.split('/');
1168 if let (Some(addr_s), Some(prefix_s)) = (iter.next(), iter.next()) {
1169 let addr = IpAddr::from_str(addr_s).map_err(|_| ())?;
1170 let prefix = u8::from_str(prefix_s).map_err(|_| ())?;
1171 Ok(Self::from_addr_prefix(addr, prefix))
1172 } else {
1173 Err(())
1174 }
1175 }
1176}
1177
1178pub fn date_time_ymd(year: i32, month: u8, day: u8) -> OffsetDateTime {
1187 let month = Month::try_from(month).expect("out-of-range month");
1188 let primitive_dt = PrimitiveDateTime::new(
1189 Date::from_calendar_date(year, month, day).expect("invalid or out-of-range date"),
1190 Time::MIDNIGHT,
1191 );
1192 primitive_dt.assume_utc()
1193}
1194
1195#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1197pub enum IsCa {
1198 NoCa,
1200 ExplicitNoCa,
1202 Ca(BasicConstraints),
1204}
1205
1206#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1211pub enum BasicConstraints {
1212 Unconstrained,
1214 Constrained(u8),
1216}
1217
1218#[cfg(test)]
1219mod tests {
1220 #[cfg(feature = "pem")]
1221 use super::*;
1222
1223 #[cfg(feature = "crypto")]
1224 #[test]
1225 fn test_with_key_usages() {
1226 let mut params: CertificateParams = Default::default();
1227
1228 params.key_usages = vec![
1230 KeyUsagePurpose::DigitalSignature,
1231 KeyUsagePurpose::KeyEncipherment,
1232 KeyUsagePurpose::ContentCommitment,
1233 ];
1234
1235 params.is_ca = IsCa::Ca(BasicConstraints::Constrained(0));
1237
1238 let key_pair = KeyPair::generate().unwrap();
1240 let cert = params.self_signed(&key_pair).unwrap();
1241
1242 let (_rem, cert) = x509_parser::parse_x509_certificate(cert.der()).unwrap();
1244
1245 let key_usage_oid_str = "2.5.29.15";
1247
1248 let mut found = false;
1250
1251 for ext in cert.extensions() {
1252 if key_usage_oid_str == ext.oid.to_id_string() {
1253 match ext.parsed_extension() {
1254 x509_parser::extensions::ParsedExtension::KeyUsage(usage) => {
1255 assert!(usage.flags == 7);
1256 found = true;
1257 },
1258 _ => {},
1259 }
1260 }
1261 }
1262
1263 assert!(found);
1264 }
1265
1266 #[cfg(feature = "crypto")]
1267 #[test]
1268 fn test_with_key_usages_decipheronly_only() {
1269 let mut params: CertificateParams = Default::default();
1270
1271 params.key_usages = vec![KeyUsagePurpose::DecipherOnly];
1273
1274 params.is_ca = IsCa::Ca(BasicConstraints::Constrained(0));
1276
1277 let key_pair = KeyPair::generate().unwrap();
1279 let cert = params.self_signed(&key_pair).unwrap();
1280
1281 let (_rem, cert) = x509_parser::parse_x509_certificate(cert.der()).unwrap();
1283
1284 let key_usage_oid_str = "2.5.29.15";
1286
1287 let mut found = false;
1289
1290 for ext in cert.extensions() {
1291 if key_usage_oid_str == ext.oid.to_id_string() {
1292 match ext.parsed_extension() {
1293 x509_parser::extensions::ParsedExtension::KeyUsage(usage) => {
1294 assert!(usage.flags == 256);
1295 found = true;
1296 },
1297 _ => {},
1298 }
1299 }
1300 }
1301
1302 assert!(found);
1303 }
1304
1305 #[cfg(feature = "crypto")]
1306 #[test]
1307 fn test_with_extended_key_usages_any() {
1308 let mut params: CertificateParams = Default::default();
1309
1310 params.extended_key_usages = vec![ExtendedKeyUsagePurpose::Any];
1312
1313 let key_pair = KeyPair::generate().unwrap();
1315 let cert = params.self_signed(&key_pair).unwrap();
1316
1317 let (_rem, cert) = x509_parser::parse_x509_certificate(cert.der()).unwrap();
1319
1320 let maybe_extension = cert.extended_key_usage().unwrap();
1322 let extension = maybe_extension.unwrap();
1323 assert!(extension.value.any);
1324 }
1325
1326 #[cfg(feature = "crypto")]
1327 #[test]
1328 fn test_with_extended_key_usages_other() {
1329 use x509_parser::der_parser::asn1_rs::Oid;
1330 let mut params: CertificateParams = Default::default();
1331 const OID_1: &[u64] = &[1, 2, 3, 4];
1332 const OID_2: &[u64] = &[1, 2, 3, 4, 5, 6];
1333
1334 params.extended_key_usages = vec![
1336 ExtendedKeyUsagePurpose::Other(Vec::from(OID_1)),
1337 ExtendedKeyUsagePurpose::Other(Vec::from(OID_2)),
1338 ];
1339
1340 let key_pair = KeyPair::generate().unwrap();
1342 let cert = params.self_signed(&key_pair).unwrap();
1343
1344 let (_rem, cert) = x509_parser::parse_x509_certificate(cert.der()).unwrap();
1346
1347 let maybe_extension = cert.extended_key_usage().unwrap();
1349 let extension = maybe_extension.unwrap();
1350
1351 let expected_oids = vec![Oid::from(OID_1).unwrap(), Oid::from(OID_2).unwrap()];
1352 assert_eq!(extension.value.other, expected_oids);
1353 }
1354
1355 #[cfg(feature = "pem")]
1356 mod test_pem_serialization {
1357 use super::*;
1358
1359 #[test]
1360 #[cfg(windows)]
1361 fn test_windows_line_endings() {
1362 let key_pair = KeyPair::generate().unwrap();
1363 let cert = CertificateParams::default().self_signed(&key_pair).unwrap();
1364 assert!(cert.pem().contains("\r\n"));
1365 }
1366
1367 #[test]
1368 #[cfg(not(windows))]
1369 fn test_not_windows_line_endings() {
1370 let key_pair = KeyPair::generate().unwrap();
1371 let cert = CertificateParams::default().self_signed(&key_pair).unwrap();
1372 assert!(!cert.pem().contains('\r'));
1373 }
1374 }
1375
1376 #[cfg(all(feature = "pem", feature = "x509-parser"))]
1377 mod test_key_identifier_from_ca {
1378 use super::*;
1379
1380 #[test]
1381 fn load_ca_and_sign_cert() {
1382 let ca_cert = r#"-----BEGIN CERTIFICATE-----
1383MIIFDTCCAvWgAwIBAgIUVuDfDt/BUVfObGOHsM+L5/qPZfIwDQYJKoZIhvcNAQEL
1384BQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMjMxMjA4MTAwOTI2WhcNMjQx
1385MTI4MTAwOTI2WjAWMRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcN
1386AQEBBQADggIPADCCAgoCggIBAKXyZsv7Zwek9yc54IXWjCkMwU4eDMz9Uw06WETF
1387hZtauwDo4usCeYJa/7x8RZbGcI99s/vOMHjIdVzY6g9p5c6qS+7EUBhXARYVB74z
1388XUGwgVGss7lgw+0dNxhQ8F0M2smBXUP9FlJJjJpbWeU+93iynGy+PTXFtYMnOoVI
13894G7YKsG5lX0zBJUNYZslEz6Kp8eRYu7FAdccU0u5bmg02a1WiXOYJeN1+AifUbRN
1390zNInZCqMCFgoHczb0DvKU3QX/xrcBxfr/SNJPqxlecUvsozteUoAFAUF1uTxH31q
1391cVmCHf9I0r6JJoGxs+XMVbH2SJLdsq/+zpjeHz6gy0z4aRMBpaUWUQ9pEENeSq15
1392PXCuX3yPT2BII30mL86OWO6qgms70iALak6xZ/xAT7RT22E1bOF+XJsiUM3OgGF0
1393TPmDcpafEMH4kwzdaC7U5hqhYk9I2lfTMEghV86kUXClExuHEQD4GZLcd1HMD/Wg
1394qOZO4y/t/yzBPNq01FpeilFph/tW6pxr1X7Jloz1/yIuNFK0oXTB24J/TUi+/S1B
1395kavOBg3eNHHDXDjESKtnV+iwo1cFt6LVCrnKhKJ6m95+c+YKQGIrcwkR91OxZ9ZT
1396DEzySsPDpWrteZf3K1VA0Ut41aTKu8pYwxsnVdOiBGaJkOh/lrevI6U9Eg4vVq94
1397hyAZAgMBAAGjUzBRMB0GA1UdDgQWBBSX1HahmxpxNSrH9KGEElYGul1hhDAfBgNV
1398HSMEGDAWgBSX1HahmxpxNSrH9KGEElYGul1hhDAPBgNVHRMBAf8EBTADAQH/MA0G
1399CSqGSIb3DQEBCwUAA4ICAQAhtwt0OrHVITVOzoH3c+7SS/rGd9KGpHG4Z/N7ASs3
14007A2PXFC5XbUuylky0+/nbkN6hhecj+Zwt5x5R8k4saXUZ8xkMfP8RaRxyZ3rUOIC
1401BZhZm1XbQzaWIQjpjyPUWDDa9P0lGsUyrEIQaLjg1J5jYPOD132bmdIuhZtzldTV
1402zeE/4sKdrkj6HZxe1jxAhx2IWm6W+pEAcq1Ld9SmJGOxBVRRKyGsMMw6hCdWfQHv
1403Z8qRIhn3FU6ZKW2jvTGJBIXoK4u454qi6DVxkFZ0OK9VwWVuDLvs2Es95TiZPTq+
1404KJmRHWHF/Ic78XFgxVq0tVaJAs7qoOMjDkehPG1V8eewanlpcaE6rPx0eiPq+nHE
1405gCf0KmKGVM8lQe63obzprkdLKL3T4UDN19K2wqscJcPKK++27OYx2hJaJKmYzF23
14064WhIRzdALTs/2fbB68nVSz7kBtHvsHHS33Q57zEdQq5YeyUaTtCvJJobt70dy9vN
1407YolzLWoY/itEPFtbBAdnJxXlctI3bw4Mzw1d66Wt+//R45+cIe6cJdUIqMHDhsGf
1408U8EuffvDcTJuUzIkyzbyOI15r1TMbRt8vFR0jzagZBCG73lVacH/bYEb2j4Z1ORi
1409L2Fl4tgIQ5tyaTpu9gpJZvPU0VZ/j+1Jdk1c9PJ6xhCjof4nzI9YsLbI8lPtu8K/
1410Ng==
1411-----END CERTIFICATE-----"#;
1412
1413 let ca_key = r#"-----BEGIN PRIVATE KEY-----
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
1463PITGdT9dgN88nHPCle0B1+OY+OZ5
1464-----END PRIVATE KEY-----"#;
1465
1466 let params = CertificateParams::from_ca_cert_pem(ca_cert).unwrap();
1467 let ca_ski = vec![
1468 0x97, 0xD4, 0x76, 0xA1, 0x9B, 0x1A, 0x71, 0x35, 0x2A, 0xC7, 0xF4, 0xA1, 0x84, 0x12,
1469 0x56, 0x06, 0xBA, 0x5D, 0x61, 0x84,
1470 ];
1471
1472 assert_eq!(
1473 KeyIdMethod::PreSpecified(ca_ski.clone()),
1474 params.key_identifier_method
1475 );
1476
1477 let ca_kp = KeyPair::from_pem(ca_key).unwrap();
1478 let ca_cert = params.self_signed(&ca_kp).unwrap();
1479 assert_eq!(&ca_ski, &ca_cert.key_identifier());
1480
1481 let (_, x509_ca) = x509_parser::parse_x509_certificate(ca_cert.der()).unwrap();
1482 assert_eq!(
1483 &ca_ski,
1484 &x509_ca
1485 .iter_extensions()
1486 .find_map(|ext| match ext.parsed_extension() {
1487 x509_parser::extensions::ParsedExtension::SubjectKeyIdentifier(key_id) => {
1488 Some(key_id.0.to_vec())
1489 },
1490 _ => None,
1491 })
1492 .unwrap()
1493 );
1494
1495 let ee_key = KeyPair::generate().unwrap();
1496 let mut ee_params = CertificateParams::default();
1497 ee_params.use_authority_key_identifier_extension = true;
1498 let ee_cert = ee_params.signed_by(&ee_key, &ca_cert, &ee_key).unwrap();
1499
1500 let (_, x509_ee) = x509_parser::parse_x509_certificate(ee_cert.der()).unwrap();
1501 assert_eq!(
1502 &ca_ski,
1503 &x509_ee
1504 .iter_extensions()
1505 .find_map(|ext| match ext.parsed_extension() {
1506 x509_parser::extensions::ParsedExtension::AuthorityKeyIdentifier(aki) => {
1507 aki.key_identifier.as_ref().map(|ki| ki.0.to_vec())
1508 },
1509 _ => None,
1510 })
1511 .unwrap()
1512 );
1513 }
1514 }
1515}