diff --git a/Cargo.lock b/Cargo.lock index ca9217521..f796ef753 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -819,6 +819,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "rstest" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d912f35156a3f99a66ee3e11ac2e0b3f34ac85a07e05263d05a7e2c8810d616f" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -1245,6 +1258,7 @@ dependencies = [ "der", "flagset", "hex-literal", + "rstest", "spki", "x501", ] diff --git a/pkcs10/tests/certreq.rs b/pkcs10/tests/certreq.rs index d3ab85d8e..c3f2a63b3 100644 --- a/pkcs10/tests/certreq.rs +++ b/pkcs10/tests/certreq.rs @@ -71,7 +71,7 @@ fn decode_rsa_2048_der() { assert_eq!(attribute.values.len(), 1); // Check the extensions. - let extensions: x509::Extensions = attribute.values.get(0).unwrap().decode_into().unwrap(); + let extensions: x509::ext::Extensions = attribute.values.get(0).unwrap().decode_into().unwrap(); for (ext, (oid, val)) in extensions.iter().zip(EXTENSIONS) { assert_eq!(ext.extn_id, oid.parse().unwrap()); assert_eq!(ext.extn_value, *val); diff --git a/x509/Cargo.toml b/x509/Cargo.toml index f3997083f..f8d5b1a1c 100644 --- a/x509/Cargo.toml +++ b/x509/Cargo.toml @@ -22,6 +22,7 @@ x501 = { version = "=0.1.0-pre.0", path = "../x501" } [dev-dependencies] hex-literal = "0.3" +rstest = "0.12.0" [features] std = ["der/std"] diff --git a/x509/src/trust_anchor_format.rs b/x509/src/anchor.rs similarity index 96% rename from x509/src/trust_anchor_format.rs rename to x509/src/anchor.rs index eda8d1888..71942ff57 100644 --- a/x509/src/trust_anchor_format.rs +++ b/x509/src/anchor.rs @@ -1,6 +1,9 @@ //! Trust anchor-related structures as defined in RFC 5914 -use crate::{Certificate, CertificatePolicies, Extensions, NameConstraints, TbsCertificate}; +use crate::ext::pkix::certpolicy::CertificatePolicies; +use crate::ext::pkix::NameConstraints; +use crate::{ext::Extensions, Certificate, TbsCertificate}; + use der::asn1::{OctetString, Utf8String}; use der::{Choice, Enumerated, Sequence}; use flagset::{flags, FlagSet}; diff --git a/x509/src/certificate.rs b/x509/src/certificate.rs index 1f44a53c9..fe81780d3 100644 --- a/x509/src/certificate.rs +++ b/x509/src/certificate.rs @@ -1,10 +1,7 @@ -//! Certificate [`Certificate`] and TBSCertificate [`TBSCertificate`] as defined in RFC 5280 - -use der::asn1::{BitString, ObjectIdentifier, UIntBytes}; +use der::asn1::{BitString, UIntBytes}; use der::{Enumerated, Sequence}; use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo}; -use x501::name::Name; -use x501::time::Validity; +use x501::{name::Name, time::Validity}; /// Certificate `Version` as defined in [RFC 5280 Section 4.1]. /// @@ -33,7 +30,7 @@ impl Default for Version { } } -/// X.509 `TBSCertificate` as defined in [RFC 5280 Section 4.1] +/// X.509 `TbsCertificate` as defined in [RFC 5280 Section 4.1] /// /// ASN.1 structure containing the names of the subject and issuer, a public /// key associated with the subject, a validity period, and other associated @@ -57,7 +54,7 @@ impl Default for Version { /// } /// ``` /// -/// [RFC 5280 Section 4.1.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 +/// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 #[derive(Clone, Debug, Eq, PartialEq, Sequence)] #[allow(missing_docs)] pub struct TbsCertificate<'a> { @@ -77,74 +74,31 @@ pub struct TbsCertificate<'a> { pub subject: Name<'a>, pub subject_public_key_info: SubjectPublicKeyInfo<'a>, - #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] + #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] pub issuer_unique_id: Option>, - #[asn1(context_specific = "2", optional = "true", tag_mode = "IMPLICIT")] + #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] pub subject_unique_id: Option>, - #[asn1(context_specific = "3", optional = "true", tag_mode = "EXPLICIT")] - pub extensions: Option>, + #[asn1(context_specific = "3", tag_mode = "EXPLICIT", optional = "true")] + pub extensions: Option>, } /// X.509 certificates are defined in [RFC 5280 Section 4.1]. /// -/// ASN.1 structure for an X.509 certificate: -/// /// ```text /// Certificate ::= SEQUENCE { -/// tbsCertificate TBSCertificate, -/// signatureAlgorithm AlgorithmIdentifier, -/// signature BIT STRING } +/// tbsCertificate TBSCertificate, +/// signatureAlgorithm AlgorithmIdentifier, +/// signature BIT STRING +/// } /// ``` /// /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 #[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] pub struct Certificate<'a> { - /// tbsCertificate TBSCertificate, pub tbs_certificate: TbsCertificate<'a>, - /// signatureAlgorithm AlgorithmIdentifier, pub signature_algorithm: AlgorithmIdentifier<'a>, - /// signature BIT STRING pub signature: BitString<'a>, } - -/// Extension as defined in [RFC 5280 Section 4.1.2.9]. -/// -/// The ASN.1 definition for Extension objects is below. The extnValue type may be further parsed using a decoder corresponding to the extnID value. -/// -/// ```text -/// Extension ::= SEQUENCE { -/// extnID OBJECT IDENTIFIER, -/// critical BOOLEAN DEFAULT FALSE, -/// extnValue OCTET STRING -/// -- contains the DER encoding of an ASN.1 value -/// -- corresponding to the extension type identified -/// -- by extnID -/// } -/// ``` -/// -/// [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -pub struct Extension<'a> { - /// extnID OBJECT IDENTIFIER, - pub extn_id: ObjectIdentifier, - - /// critical BOOLEAN DEFAULT FALSE, - #[asn1(default = "Default::default")] - pub critical: bool, - - /// extnValue OCTET STRING - #[asn1(type = "OCTET STRING")] - pub extn_value: &'a [u8], -} - -/// Extensions as defined in [RFC 5280 Section 4.1.2.9]. -/// -/// ```text -/// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension -/// ``` -/// -/// [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9 -//pub type Extensions<'a> = SequenceOf, 10>; -pub type Extensions<'a> = alloc::vec::Vec>; diff --git a/x509/src/ext.rs b/x509/src/ext.rs new file mode 100644 index 000000000..0d3b5d0e9 --- /dev/null +++ b/x509/src/ext.rs @@ -0,0 +1,45 @@ +//! Standardized X.509 Certificate Extensions + +use der::Sequence; +use spki::ObjectIdentifier; + +pub mod other; +pub mod pkix; + +/// Extension as defined in [RFC 5280 Section 4.1.2.9]. +/// +/// The ASN.1 definition for Extension objects is below. The extnValue type +/// may be further parsed using a decoder corresponding to the extnID value. +/// +/// ```text +/// Extension ::= SEQUENCE { +/// extnID OBJECT IDENTIFIER, +/// critical BOOLEAN DEFAULT FALSE, +/// extnValue OCTET STRING +/// -- contains the DER encoding of an ASN.1 value +/// -- corresponding to the extension type identified +/// -- by extnID +/// } +/// ``` +/// +/// [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct Extension<'a> { + pub extn_id: ObjectIdentifier, + + #[asn1(default = "Default::default")] + pub critical: bool, + + #[asn1(type = "OCTET STRING")] + pub extn_value: &'a [u8], +} + +/// Extensions as defined in [RFC 5280 Section 4.1.2.9]. +/// +/// ```text +/// Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension +/// ``` +/// +/// [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9 +pub type Extensions<'a> = alloc::vec::Vec>; diff --git a/x509/src/ext/other.rs b/x509/src/ext/other.rs new file mode 100644 index 000000000..c78e582a4 --- /dev/null +++ b/x509/src/ext/other.rs @@ -0,0 +1,25 @@ +//! Miscelaneous Extensions + +use der::asn1::Null; + +/// OcspNoCheck as defined in [RFC 6960 Section 4.2.2.2.1]. +/// +/// This extension is idenfied by the [`PKIX_OCSP_NOCHECK`](constant.PKIX_OCSP_NOCHECK.html) OID. +/// +/// ```text +/// OcspNoCheck ::= NULL +/// ``` +/// +/// [RFC 6960 Section 4.2.2.2.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.2.2.1 +pub type OcspNoCheck = Null; + +/// NACI-indicator as defined in [FIPS 201-2 Appendix B]. +/// +/// This extension is identified by the [`PIV_NACI_INDICATOR`](constant.PIV_NACI_INDICATOR.html) OID. +/// +/// ```text +/// NACI-indicator ::= BOOLEAN +/// ``` +/// +/// [FIPS 201-2 Appendix B]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.201-2.pdf +pub type PivNaciIndicator = bool; diff --git a/x509/src/ext/pkix.rs b/x509/src/ext/pkix.rs new file mode 100644 index 000000000..2a24f3aed --- /dev/null +++ b/x509/src/ext/pkix.rs @@ -0,0 +1,83 @@ +//! PKIX X.509 Certificate Extensions (RFC 5280) + +pub mod certpolicy; +pub mod constraints; +pub mod crl; +pub mod name; +pub mod oids; + +mod access; +mod authkeyid; +mod keyusage; +mod policymap; + +pub use access::{AccessDescription, AuthorityInfoAccessSyntax, SubjectInfoAccessSyntax}; +pub use authkeyid::AuthorityKeyIdentifier; +pub use certpolicy::CertificatePolicies; +pub use constraints::{BasicConstraints, NameConstraints, PolicyConstraints}; +pub use crl::{ + BaseCrlNumber, CrlDistributionPoints, CrlNumber, CrlReason, FreshestCrl, + IssuingDistributionPoint, +}; +pub use keyusage::{ExtendedKeyUsage, KeyUsage, KeyUsages, PrivateKeyUsagePeriod}; +pub use policymap::{PolicyMapping, PolicyMappings}; + +use alloc::vec::Vec; + +use der::asn1::OctetString; +use x501::attr::AttributeTypeAndValue; + +/// SubjectKeyIdentifier as defined in [RFC 5280 Section 4.2.1.2]. +/// +/// This extension is identified by the [`PKIX_CE_SUBJECT_KEY_IDENTIFIER`](constant.PKIX_CE_SUBJECT_KEY_IDENTIFIER.html) OID. +/// +/// ```text +/// SubjectKeyIdentifier ::= KeyIdentifier +/// ``` +/// +/// [RFC 5280 Section 4.2.1.2]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.2 +pub type SubjectKeyIdentifier<'a> = OctetString<'a>; + +/// SubjectAltName as defined in [RFC 5280 Section 4.2.1.6]. +/// +/// This extension is identified by the [`PKIX_CE_SUBJECT_ALT_NAME`](constant.PKIX_CE_SUBJECT_ALT_NAME.html) OID. +/// +/// ```text +/// SubjectAltName ::= GeneralNames +/// ``` +/// +/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 +pub type SubjectAltName<'a> = name::GeneralNames<'a>; + +/// IssuerAltName as defined in [RFC 5280 Section 4.2.1.7]. +/// +/// This extension is identified by the [`PKIX_CE_ISSUER_ALT_NAME`](constant.PKIX_CE_ISSUER_ALT_NAME.html) OID. +/// +/// ```text +/// IssuerAltName ::= GeneralNames +/// ``` +/// +/// [RFC 5280 Section 4.2.1.7]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.7 +pub type IssuerAltName<'a> = name::GeneralNames<'a>; + +/// SubjectDirectoryAttributes as defined in [RFC 5280 Section 4.2.1.8]. +/// +/// This extension is identified by the [`PKIX_CE_SUBJECT_DIRECTORY_ATTRIBUTES`](constant.PKIX_CE_SUBJECT_DIRECTORY_ATTRIBUTES.html) OID. +/// +/// ```text +/// SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF AttributeSet +/// ``` +/// +/// [RFC 5280 Section 4.2.1.8]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.8 +pub type SubjectDirectoryAttributes<'a> = Vec>; + +/// InhibitAnyPolicy as defined in [RFC 5280 Section 4.2.1.14]. +/// +/// This extension is identified by the [`PKIX_CE_INHIBIT_ANY_POLICY`](constant.PKIX_CE_INHIBIT_ANY_POLICY.html) OID. +/// +/// ```text +/// InhibitAnyPolicy ::= SkipCerts +/// ``` +/// +/// [RFC 5280 Section 4.2.1.14]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.14 +pub type InhibitAnyPolicy = u32; diff --git a/x509/src/ext/pkix/access.rs b/x509/src/ext/pkix/access.rs new file mode 100644 index 000000000..0740c87ea --- /dev/null +++ b/x509/src/ext/pkix/access.rs @@ -0,0 +1,46 @@ +use super::name::GeneralName; + +use alloc::vec::Vec; + +use der::{asn1::ObjectIdentifier, Sequence}; + +/// AuthorityInfoAccessSyntax as defined in [RFC 5280 Section 4.2.2.1]. +/// +/// This extension is identified by the [`PKIX_PE_AUTHORITYINFOACCESS`](constant.PKIX_PE_AUTHORITYINFOACCESS.html) OID. +/// +/// ```text +/// AuthorityInfoAccessSyntax ::= SEQUENCE SIZE (1..MAX) OF AccessDescription +/// ``` +/// +/// [RFC 5280 Section 4.2.2.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1 +pub type AuthorityInfoAccessSyntax<'a> = Vec>; + +/// SubjectInfoAccessSyntax as defined in [RFC 5280 Section 4.2.2.2]. +/// +/// This extension is identified by the [`PKIX_PE_SUBJECTINFOACCESS`](constant.PKIX_PE_SUBJECTINFOACCESS.html) OID. +/// +/// ```text +/// SubjectInfoAccessSyntax ::= SEQUENCE SIZE (1..MAX) OF AccessDescription +/// ``` +/// +/// [RFC 5280 Section 4.2.2.2]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.2 +pub type SubjectInfoAccessSyntax<'a> = Vec>; + +/// AccessDescription as defined in [RFC 5280 Section 4.2.2.1]. +/// +/// ```text +/// AccessDescription ::= SEQUENCE { +/// accessMethod OBJECT IDENTIFIER, +/// accessLocation GeneralName +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.2.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +pub struct AccessDescription<'a> { + /// accessMethod OBJECT IDENTIFIER, + pub access_method: ObjectIdentifier, + + /// accessLocation GeneralName + pub access_location: GeneralName<'a>, +} diff --git a/x509/src/ext/pkix/authkeyid.rs b/x509/src/ext/pkix/authkeyid.rs new file mode 100644 index 000000000..d0061401c --- /dev/null +++ b/x509/src/ext/pkix/authkeyid.rs @@ -0,0 +1,32 @@ +use super::name::GeneralNames; + +use der::asn1::{OctetString, UIntBytes}; +use der::Sequence; + +/// AuthorityKeyIdentifier as defined in [RFC 5280 Section 4.2.1.1]. +/// +/// This extension is identified by the [`PKIX_CE_AUTHORITY_KEY_IDENTIFIER`](constant.PKIX_CE_AUTHORITY_KEY_IDENTIFIER.html) OID. +/// +/// ```text +/// AuthorityKeyIdentifier ::= SEQUENCE { +/// keyIdentifier [0] KeyIdentifier OPTIONAL, +/// authorityCertIssuer [1] GeneralNames OPTIONAL, +/// authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL +/// } +/// +/// KeyIdentifier ::= OCTET STRING +/// ``` +/// +/// [RFC 5280 Section 4.2.1.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.1 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct AuthorityKeyIdentifier<'a> { + #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")] + pub key_identifier: Option>, + + #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] + pub authority_cert_issuer: Option>, + + #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] + pub authority_cert_serial_number: Option>, +} diff --git a/x509/src/ext/pkix/certpolicy.rs b/x509/src/ext/pkix/certpolicy.rs new file mode 100644 index 000000000..7ed917d58 --- /dev/null +++ b/x509/src/ext/pkix/certpolicy.rs @@ -0,0 +1,119 @@ +//! PKIX Certificate Policies extension + +use alloc::vec::Vec; + +use der::asn1::{GeneralizedTime, Ia5String, ObjectIdentifier, UIntBytes, Utf8String}; +use der::{Any, Choice, Sequence}; + +/// CertificatePolicies as defined in [RFC 5280 Section 4.2.1.4]. +/// +/// This extension is identified by the [`PKIX_CE_CERTIFICATE_POLICIES`](constant.PKIX_CE_CERTIFICATE_POLICIES.html) OID. +/// +/// ```text +/// CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation +/// ``` +/// +/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 +pub type CertificatePolicies<'a> = Vec>; + +/// PolicyInformation as defined in [RFC 5280 Section 4.2.1.4]. +/// +/// ```text +/// PolicyInformation ::= SEQUENCE { +/// policyIdentifier CertPolicyId, +/// policyQualifiers SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo OPTIONAL +/// } +/// +/// CertPolicyId ::= OBJECT IDENTIFIER +/// ``` +/// +/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct PolicyInformation<'a> { + pub policy_identifier: ObjectIdentifier, + pub policy_qualifiers: Option>>, +} + +/// PolicyQualifierInfo as defined in [RFC 5280 Section 4.2.1.4]. +/// +/// ```text +/// PolicyQualifierInfo ::= SEQUENCE { +/// policyQualifierId PolicyQualifierId, +/// qualifier ANY DEFINED BY policyQualifierId +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct PolicyQualifierInfo<'a> { + pub policy_qualifier_id: ObjectIdentifier, + pub qualifier: Option>, +} + +/// CpsUri as defined in [RFC 5280 Section 4.2.1.4]. +/// +/// ```text +/// CPSuri ::= IA5String +/// ``` +/// +/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 +pub type CpsUri<'a> = Ia5String<'a>; + +/// UserNotice as defined in [RFC 5280 Section 4.2.1.4]. +/// +/// ```text +/// UserNotice ::= SEQUENCE { +/// noticeRef NoticeReference OPTIONAL, +/// explicitText DisplayText OPTIONAL +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct UserNotice<'a> { + pub notice_ref: Option, + pub explicit_text: Option>, +} + +/// NoticeReference as defined in [RFC 5280 Section 4.2.1.4]. +/// +/// ```text +/// NoticeReference ::= SEQUENCE { +/// organization DisplayText, +/// noticeNumbers SEQUENCE OF INTEGER } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct NoticeReference<'a> { + pub organization: DisplayText<'a>, + pub notice_numbers: Option>>, +} + +/// DisplayText as defined in [RFC 5280 Section 4.2.1.4]. +/// +/// ```text +/// DisplayText ::= CHOICE { +/// ia5String IA5String (SIZE (1..200)), +/// visibleString VisibleString (SIZE (1..200)), +/// bmpString BMPString (SIZE (1..200)), +/// utf8String UTF8String (SIZE (1..200)) +/// } +/// ``` +/// +/// Only the ia5String and utf8String options are currently supported. +/// +/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 +#[derive(Choice, Clone, Debug, Eq, PartialEq)] +#[allow(missing_docs)] +pub enum DisplayText<'a> { + #[asn1(type = "IA5String")] + Ia5String(Ia5String<'a>), + + #[asn1(type = "UTF8String")] + Utf8String(Utf8String<'a>), +} diff --git a/x509/src/ext/pkix/constraints.rs b/x509/src/ext/pkix/constraints.rs new file mode 100644 index 000000000..abe4c3f46 --- /dev/null +++ b/x509/src/ext/pkix/constraints.rs @@ -0,0 +1,10 @@ +//! PKIX Constraint Extensions + +mod basic; +mod policy; + +pub mod name; + +pub use basic::BasicConstraints; +pub use name::NameConstraints; +pub use policy::PolicyConstraints; diff --git a/x509/src/ext/pkix/constraints/basic.rs b/x509/src/ext/pkix/constraints/basic.rs new file mode 100644 index 000000000..b2146e13a --- /dev/null +++ b/x509/src/ext/pkix/constraints/basic.rs @@ -0,0 +1,21 @@ +use der::Sequence; + +/// BasicConstraints as defined in [RFC 5280 Section 4.2.1.9]. +/// +/// This extension is identified by the [`PKIX_CE_BASIC_CONSTRAINTS`](constant.PKIX_CE_BASIC_CONSTRAINTS.html) OID. +/// +/// ```text +/// BasicConstraints ::= SEQUENCE { +/// cA BOOLEAN DEFAULT FALSE, +/// pathLenConstraint INTEGER (0..MAX) OPTIONAL +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.9 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct BasicConstraints { + #[asn1(default = "Default::default")] + pub ca: bool, + pub path_len_constraint: Option, +} diff --git a/x509/src/ext/pkix/constraints/name.rs b/x509/src/ext/pkix/constraints/name.rs new file mode 100644 index 000000000..4627e4033 --- /dev/null +++ b/x509/src/ext/pkix/constraints/name.rs @@ -0,0 +1,65 @@ +//! PKIX Name Constraint extension + +use alloc::vec::Vec; + +use der::Sequence; + +use super::super::name::GeneralName; + +/// NameConstraints extension as defined in [RFC 5280 Section 4.2.1.10]. +/// +/// This extension is identified by the [`PKIX_CE_NAME_CONSTRAINTS`](constant.PKIX_CE_NAME_CONSTRAINTS.html) OID. +/// +/// ```text +/// NameConstraints ::= SEQUENCE { +/// permittedSubtrees [0] GeneralSubtrees OPTIONAL, +/// excludedSubtrees [1] GeneralSubtrees OPTIONAL +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct NameConstraints<'a> { + #[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")] + pub permitted_subtrees: Option>, + + #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] + pub excluded_subtrees: Option>, +} + +/// GeneralSubtrees as defined in [RFC 5280 Section 4.2.1.10]. +/// +/// ```text +/// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree +/// ``` +/// +/// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 +pub type GeneralSubtrees<'a> = Vec>; + +/// GeneralSubtree as defined in [RFC 5280 Section 4.2.1.10]. +/// +/// ```text +/// GeneralSubtree ::= SEQUENCE { +/// base GeneralName, +/// minimum [0] BaseDistance DEFAULT 0, +/// maximum [1] BaseDistance OPTIONAL +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct GeneralSubtree<'a> { + pub base: GeneralName<'a>, + + #[asn1( + context_specific = "0", + tag_mode = "IMPLICIT", + default = "Default::default" + )] + pub minimum: u32, + + #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] + pub maximum: Option, +} diff --git a/x509/src/ext/pkix/constraints/policy.rs b/x509/src/ext/pkix/constraints/policy.rs new file mode 100644 index 000000000..337685628 --- /dev/null +++ b/x509/src/ext/pkix/constraints/policy.rs @@ -0,0 +1,23 @@ +use der::Sequence; + +/// Policy constraints extension as defined in [RFC 5280 Section 4.2.1.11]. +/// +/// This extension is identified by the [`PKIX_CE_POLICY_CONSTRAINTS`](constant.PKIX_CE_POLICY_CONSTRAINTS.html) OID. +/// +/// ```text +/// PolicyConstraints ::= SEQUENCE { +/// requireExplicitPolicy [0] SkipCerts OPTIONAL, +/// inhibitPolicyMapping [1] SkipCerts OPTIONAL +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.11]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.11 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct PolicyConstraints { + #[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")] + pub require_explicit_policy: Option, + + #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] + pub inhibit_policy_mapping: Option, +} diff --git a/x509/src/ext/pkix/crl.rs b/x509/src/ext/pkix/crl.rs new file mode 100644 index 000000000..2864302fa --- /dev/null +++ b/x509/src/ext/pkix/crl.rs @@ -0,0 +1,89 @@ +//! PKIX Certificate Revocation List extensions + +pub mod dp; + +pub use dp::IssuingDistributionPoint; + +use alloc::vec::Vec; + +use der::{asn1::UIntBytes, Enumerated}; + +/// CrlNumber as defined in [RFC 5280 Section 5.2.3]. +/// +/// This extension is identified by the [`PKIX_CE_CRLNUMBER`](constant.PKIX_CE_CRLNUMBER.html) OID. +/// +/// ```text +/// CRLNumber ::= INTEGER (0..MAX) +/// ``` +/// +/// [RFC 5280 Section 5.2.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.3 +pub type CrlNumber<'a> = UIntBytes<'a>; + +/// BaseCRLNumber as defined in [RFC 5280 Section 5.2.4]. +/// +/// This extension is identified by the [`PKIX_CE_DELTACRLINDICATOR`](constant.PKIX_CE_DELTACRLINDICATOR.html) OID. +/// +/// ```text +/// BaseCRLNumber ::= CRLNumber +/// ``` +/// +/// [RFC 5280 Section 5.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.4 +pub type BaseCrlNumber<'a> = CrlNumber<'a>; + +/// CrlDistributionPoints as defined in [RFC 5280 Section 4.2.1.13]. +/// +/// This extension is identified by the [`PKIX_CE_CRL_DISTRIBUTION_POINTS`](constant.PKIX_CE_CRL_DISTRIBUTION_POINTS.html) OID. +/// +/// ```text +/// CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint +/// ``` +/// +/// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 +pub type CrlDistributionPoints<'a> = Vec>; + +/// FreshestCrl as defined in [RFC 5280 Section 5.2.6]. +/// +/// This extension is identified by the [`PKIX_CE_FRESHEST_CRL`](constant.PKIX_CE_FRESHEST_CRL.html) OID. +/// +/// ```text +/// FreshestCRL ::= CRLDistributionPoints +/// ``` +/// +/// [RFC 5280 Section 5.2.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.6 +pub type FreshestCrl<'a> = CrlDistributionPoints<'a>; + +/// CRLReason as defined in [RFC 5280 Section 5.3.1]. +/// +/// This extension is identified by the [`PKIX_CE_CRLREASONS`](constant.PKIX_CE_CRLREASONS.html) OID. +/// +/// ```text +/// CRLReason ::= ENUMERATED { +/// unspecified (0), +/// keyCompromise (1), +/// cACompromise (2), +/// affiliationChanged (3), +/// superseded (4), +/// cessationOfOperation (5), +/// certificateHold (6), +/// removeFromCRL (8), +/// privilegeWithdrawn (9), +/// aACompromise (10) +/// } +/// ``` +/// +/// [RFC 5280 Section 5.3.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.3.1 +#[derive(Copy, Clone, Debug, Eq, PartialEq, Enumerated)] +#[allow(missing_docs)] +#[repr(u32)] +pub enum CrlReason { + Unspecified = 0, + KeyCompromise = 1, + CaCompromise = 2, + AffiliationChanged = 3, + Superseded = 4, + CessationOfOperation = 5, + CertificateHold = 6, + RemoveFromCRL = 8, + PrivilegeWithdrawn = 9, + AaCompromise = 10, +} diff --git a/x509/src/ext/pkix/crl/dp.rs b/x509/src/ext/pkix/crl/dp.rs new file mode 100644 index 000000000..8c28195e4 --- /dev/null +++ b/x509/src/ext/pkix/crl/dp.rs @@ -0,0 +1,122 @@ +//! PKIX distribution point types + +use der::Sequence; +use flagset::{flags, FlagSet}; + +use crate::ext::pkix::name::{DistributionPointName, GeneralNames}; + +/// IssuingDistributionPoint as defined in [RFC 5280 Section 5.2.5]. +/// +/// This extension is identified by the [`PKIX_PE_SUBJECTINFOACCESS`](constant.PKIX_PE_SUBJECTINFOACCESS.html) OID. +/// +/// ```text +/// IssuingDistributionPoint ::= SEQUENCE { +/// distributionPoint [0] DistributionPointName OPTIONAL, +/// onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, +/// onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, +/// onlySomeReasons [3] ReasonFlags OPTIONAL, +/// indirectCRL [4] BOOLEAN DEFAULT FALSE, +/// onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE +/// -- at most one of onlyContainsUserCerts, onlyContainsCACerts, +/// -- and onlyContainsAttributeCerts may be set to TRUE. +/// } +/// ``` +/// +/// [RFC 5280 Section 5.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct IssuingDistributionPoint<'a> { + #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")] + pub distribution_point: Option>, + + #[asn1( + context_specific = "1", + tag_mode = "IMPLICIT", + default = "Default::default" + )] + pub only_contains_user_certs: bool, + + #[asn1( + context_specific = "2", + tag_mode = "IMPLICIT", + default = "Default::default" + )] + pub only_contains_ca_certs: bool, + + #[asn1(context_specific = "3", tag_mode = "IMPLICIT", optional = "true")] + pub only_some_reasons: Option, + + #[asn1( + context_specific = "4", + tag_mode = "IMPLICIT", + default = "Default::default" + )] + pub indirect_crl: bool, + + #[asn1( + context_specific = "5", + tag_mode = "IMPLICIT", + default = "Default::default" + )] + pub only_contains_attribute_certs: bool, +} + +/// DistributionPoint as defined in [RFC 5280 Section 4.2.1.13]. +/// +/// ```text +/// DistributionPoint ::= SEQUENCE { +/// distributionPoint [0] DistributionPointName OPTIONAL, +/// reasons [1] ReasonFlags OPTIONAL, +/// cRLIssuer [2] GeneralNames OPTIONAL } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 +#[derive(Clone, Debug, PartialEq, Eq, Sequence)] +#[allow(missing_docs)] +pub struct DistributionPoint<'a> { + #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")] + pub distribution_point: Option>, + + #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] + pub reasons: Option, + + #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] + pub crl_issuer: Option>, +} + +/// ReasonFlags as defined in [RFC 5280 Section 4.2.1.13]. +/// +/// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 +pub type ReasonFlags = FlagSet; + +flags! { + /// ReasonFlags values as defined in [RFC 5280 Section 4.2.1.13]. + /// + /// ```text + /// ReasonFlags ::= BIT STRING { + /// unused (0), + /// keyCompromise (1), + /// cACompromise (2), + /// affiliationChanged (3), + /// superseded (4), + /// cessationOfOperation (5), + /// certificateHold (6), + /// privilegeWithdrawn (7), + /// aACompromise (8) + /// } + /// ``` + /// + /// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 + #[allow(missing_docs)] + pub enum Reasons: u16 { + Unused = 1 << 0, + KeyCompromise = 1 << 1, + CaCompromise = 1 << 2, + AffiliationChanged = 1 << 3, + Superseded = 1 << 4, + CessationOfOperation = 1 << 5, + CertificateHold = 1 << 6, + PrivilegeWithdrawn = 1 << 7, + AaCompromise = 1 << 8, + } +} diff --git a/x509/src/ext/pkix/keyusage.rs b/x509/src/ext/pkix/keyusage.rs new file mode 100644 index 000000000..f0b076ea8 --- /dev/null +++ b/x509/src/ext/pkix/keyusage.rs @@ -0,0 +1,90 @@ +use alloc::vec::Vec; + +use der::asn1::{GeneralizedTime, ObjectIdentifier}; +use der::Sequence; +use flagset::{flags, FlagSet}; + +flags! { + /// Key usage flags as defined in [RFC 5280 Section 4.2.1.3]. + /// + /// ```text + /// KeyUsage ::= BIT STRING { + /// digitalSignature (0), + /// nonRepudiation (1), -- recent editions of X.509 have + /// -- renamed this bit to contentCommitment + /// keyEncipherment (2), + /// dataEncipherment (3), + /// keyAgreement (4), + /// keyCertSign (5), + /// cRLSign (6), + /// encipherOnly (7), + /// decipherOnly (8) + /// } + /// ``` + /// + /// [RFC 5280 Section 4.2.1.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 + #[allow(missing_docs)] + pub enum KeyUsages: u16 { + DigitalSignature = 1 << 0, + NonRepudiation = 1 << 1, + KeyEncipherment = 1 << 2, + DataEncipherment = 1 << 3, + KeyAgreement = 1 << 4, + KeyCertSign = 1 << 5, + CRLSign = 1 << 6, + EncipherOnly = 1 << 7, + DecipherOnly = 1 << 8, + } +} + +/// KeyUsage as defined in [RFC 5280 Section 4.2.1.3]. +/// +/// This extension is identified by the [`PKIX_CE_KEY_USAGE`](constant.PKIX_CE_KEY_USAGE.html) OID. +/// +/// [RFC 5280 Section 4.2.1.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 +pub type KeyUsage<'a> = FlagSet; + +/// ExtKeyUsageSyntax as defined in [RFC 5280 Section 4.2.1.12]. +/// +/// This extension is identified by the [`PKIX_CE_EXTKEYUSAGE`](constant.PKIX_CE_EXTKEYUSAGE.html) OID. +/// +/// Many extended key usage values include: +/// - [`PKIX_CE_ANYEXTENDEDKEYUSAGE`](constant.PKIX_CE_ANYEXTENDEDKEYUSAGE.html), +/// - [`PKIX_KP_SERVERAUTH`](constant.PKIX_KP_SERVERAUTH.html), +/// - [`PKIX_KP_CLIENTAUTH`](constant.PKIX_KP_CLIENTAUTH.html), +/// - [`PKIX_KP_CODESIGNING`](constant.PKIX_KP_CODESIGNING.html), +/// - [`PKIX_KP_EMAILPROTECTION`](constant.PKIX_KP_EMAILPROTECTION.html), +/// - [`PKIX_KP_TIMESTAMPING`](constant.PKIX_KP_TIMESTAMPING.html), +/// +/// ```text +/// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId +/// KeyPurposeId ::= OBJECT IDENTIFIER +/// ``` +/// +/// [RFC 5280 Section 4.2.1.12]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12 +pub type ExtendedKeyUsage<'a> = Vec; + +/// PrivateKeyUsagePeriod as defined in [RFC 3280 Section 4.2.1.4]. +/// +/// This extension is identified by the [`PKIX_CE_PRIVATE_KEY_USAGE_PERIOD`](constant.PKIX_CE_PRIVATE_KEY_USAGE_PERIOD.html) OID. +/// +/// RFC 5280 states "use of this ISO standard extension is neither deprecated nor recommended for use in the Internet PKI." +/// +/// ```text +/// PrivateKeyUsagePeriod ::= SEQUENCE { +/// notBefore [0] GeneralizedTime OPTIONAL, +/// notAfter [1] GeneralizedTime OPTIONAL } +/// -- either notBefore or notAfter MUST be present +/// ``` +/// +/// [RFC 3280 Section 4.2.1.12]: https://datatracker.ietf.org/doc/html/rfc3280#section-4.2.1.4 +#[derive(Clone, Debug, PartialEq, Eq, Sequence)] +pub struct PrivateKeyUsagePeriod { + /// notBefore [0] GeneralizedTime OPTIONAL, + #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")] + pub not_before: Option, + + /// notAfter [1] GeneralizedTime OPTIONAL + #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] + pub not_after: Option, +} diff --git a/x509/src/ext/pkix/name.rs b/x509/src/ext/pkix/name.rs new file mode 100644 index 000000000..4e0112be4 --- /dev/null +++ b/x509/src/ext/pkix/name.rs @@ -0,0 +1,13 @@ +//! PKIX Name types + +mod dirstr; +mod dp; +mod ediparty; +mod general; +mod other; + +pub use dirstr::DirectoryString; +pub use dp::DistributionPointName; +pub use ediparty::EdiPartyName; +pub use general::{GeneralName, GeneralNames}; +pub use other::OtherName; diff --git a/x509/src/ext/pkix/name/dirstr.rs b/x509/src/ext/pkix/name/dirstr.rs new file mode 100644 index 000000000..6ac90e7ae --- /dev/null +++ b/x509/src/ext/pkix/name/dirstr.rs @@ -0,0 +1,50 @@ +use der::asn1::{PrintableString, Utf8String}; +use der::Choice; + +/// DirectoryString as defined in [RFC 5280 Section 4.2.1.4]. +/// +/// ASN.1 structure for DirectoryString is below. +/// +/// ```text +/// DirectoryString ::= CHOICE { +/// teletexString TeletexString (SIZE (1..MAX)), +/// printableString PrintableString (SIZE (1..MAX)), +/// universalString UniversalString (SIZE (1..MAX)), +/// utf8String UTF8String (SIZE (1..MAX)), +/// bmpString BMPString (SIZE (1..MAX)) +/// } +/// ``` +/// +/// Further, [RFC 5280 Section 4.2.1.4] states: +/// +/// ```text +/// The DirectoryString type is defined as a choice of PrintableString, +/// TeletexString, BMPString, UTF8String, and UniversalString. CAs +/// conforming to this profile MUST use either the PrintableString or +/// UTF8String encoding of DirectoryString, with two exceptions. When +/// CAs have previously issued certificates with issuer fields with +/// attributes encoded using TeletexString, BMPString, or +/// UniversalString, then the CA MAY continue to use these encodings of +/// the DirectoryString to preserve backward compatibility. Also, new +/// CAs that are added to a domain where existing CAs issue certificates +/// with issuer fields with attributes encoded using TeletexString, +/// BMPString, or UniversalString MAY encode attributes that they share +/// with the existing CAs using the same encodings as the existing CAs +/// use. +/// ``` +/// +/// The implication of the above paragraph is that `PrintableString` and +/// `UTF8String` are the new types and the other types are legacy. Until +/// the need arises, we only support `PrintableString` and `UTF8String`. +/// +/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 +#[derive(Clone, Debug, Eq, PartialEq, Choice)] +pub enum DirectoryString<'a> { + /// ia5String IA5String (SIZE (1..200)) + #[asn1(type = "PrintableString")] + PrintableString(PrintableString<'a>), + + /// utf8String UTF8String (SIZE (1..200)) + #[asn1(type = "UTF8String")] + Utf8String(Utf8String<'a>), +} diff --git a/x509/src/ext/pkix/name/dp.rs b/x509/src/ext/pkix/name/dp.rs new file mode 100644 index 000000000..adc1980e0 --- /dev/null +++ b/x509/src/ext/pkix/name/dp.rs @@ -0,0 +1,24 @@ +use super::GeneralNames; + +use der::Choice; +use x501::name::RelativeDistinguishedName; + +/// DistributionPointName as defined in [RFC 5280 Section 4.2.1.13]. +/// +/// ```text +/// DistributionPointName ::= CHOICE { +/// fullName [0] GeneralNames, +/// nameRelativeToCRLIssuer [1] RelativeDistinguishedName +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 +#[derive(Clone, Debug, Eq, PartialEq, Choice)] +#[allow(missing_docs)] +pub enum DistributionPointName<'a> { + #[asn1(context_specific = "0", tag_mode = "IMPLICIT", constructed = "true")] + FullName(GeneralNames<'a>), + + #[asn1(context_specific = "1", tag_mode = "IMPLICIT", constructed = "true")] + NameRelativeToCRLIssuer(RelativeDistinguishedName<'a>), +} diff --git a/x509/src/ext/pkix/name/ediparty.rs b/x509/src/ext/pkix/name/ediparty.rs new file mode 100644 index 000000000..4c90477d8 --- /dev/null +++ b/x509/src/ext/pkix/name/ediparty.rs @@ -0,0 +1,37 @@ +use der::{Decodable, Sequence}; + +use super::DirectoryString; + +/// EDIPartyName as defined in [RFC 5280 Section 4.2.1.6]. +/// +/// ```text +/// EDIPartyName ::= SEQUENCE { +/// nameAssigner [0] DirectoryString OPTIONAL, +/// partyName [1] DirectoryString +/// } +/// ``` +/// +/// Note that although the module uses `IMPLICIT` tagging, these tags are +/// `EXPLICIT` because of `X.680-2015 31.2.7 (c)`: +/// +/// ```text +/// c) the "Tag Type" alternative is used and the value of "TagDefault" for +/// the module is IMPLICIT TAGS or AUTOMATIC TAGS, but the type defined by +/// "Type" is an untagged choice type, an untagged open type, or an untagged +/// "DummyReference" (see Rec. ITU-T X.683 | ISO/IEC 8824-4, 8.3). +/// ``` +/// +/// See [this OpenSSL bug] for more details. +/// +/// [this OpenSSL bug]: https://github.com/openssl/openssl/issues/6859 +/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +pub struct EdiPartyName<'a> { + /// nameAssigner + #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")] + pub name_assigner: Option>, + + /// partyName + #[asn1(context_specific = "1", tag_mode = "EXPLICIT")] + pub party_name: DirectoryString<'a>, +} diff --git a/x509/src/ext/pkix/name/general.rs b/x509/src/ext/pkix/name/general.rs new file mode 100644 index 000000000..cc377331f --- /dev/null +++ b/x509/src/ext/pkix/name/general.rs @@ -0,0 +1,147 @@ +//! GeneralNames as defined in [RFC 5280 Section 4.2.1.6]. + +use super::{EdiPartyName, OtherName}; + +use der::asn1::{Ia5String, ObjectIdentifier, OctetString}; +use der::Choice; +use x501::name::Name; + +/// GeneralNames as defined in [RFC 5280 Section 4.2.1.6]. +/// +/// ```text +/// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName +/// ``` +/// +/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 +pub type GeneralNames<'a> = alloc::vec::Vec>; + +/// GeneralName as defined in [RFC 5280 Section 4.2.1.6]. +/// +/// ```text +/// GeneralName ::= CHOICE { +/// otherName [0] OtherName, +/// rfc822Name [1] IA5String, +/// dNSName [2] IA5String, +/// x400Address [3] ORAddress, +/// directoryName [4] Name, +/// ediPartyName [5] EDIPartyName, +/// uniformResourceIdentifier [6] IA5String, +/// iPAddress [7] OCTET STRING, +/// registeredID [8] OBJECT IDENTIFIER +/// } +/// ``` +/// +/// This implementation does not currently support the `x400Address` choice. +/// +/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 +#[derive(Clone, Debug, Eq, PartialEq, Choice)] +#[allow(missing_docs)] +pub enum GeneralName<'a> { + #[asn1(context_specific = "0", tag_mode = "IMPLICIT", constructed = "true")] + OtherName(OtherName<'a>), + + #[asn1(context_specific = "1", tag_mode = "IMPLICIT")] + Rfc822Name(Ia5String<'a>), + + #[asn1(context_specific = "2", tag_mode = "IMPLICIT")] + DnsName(Ia5String<'a>), + + #[asn1(context_specific = "4", tag_mode = "EXPLICIT", constructed = "true")] + DirectoryName(Name<'a>), + + #[asn1(context_specific = "5", tag_mode = "IMPLICIT", constructed = "true")] + EdiPartyName(EdiPartyName<'a>), + + #[asn1(context_specific = "6", tag_mode = "IMPLICIT")] + UniformResourceIdentifier(Ia5String<'a>), + + #[asn1(context_specific = "7", tag_mode = "IMPLICIT")] + IpAddress(OctetString<'a>), + + #[asn1(context_specific = "8", tag_mode = "IMPLICIT")] + RegisteredId(ObjectIdentifier), +} + +#[cfg(test)] +mod test { + use super::{GeneralName, GeneralNames}; + + use der::{Decodable, Encodable}; + use hex_literal::hex; + use rstest::rstest; + + const OTHER_NAME: &[u8] = &hex!("A01B060560865E0202A0120C105249462D472D32303030343033362D30"); + const RFC822_NAME: &[u8] = &hex!("8117456D61696C5F353238343037373733406468732E676F76"); + const DNS_NAME: &[u8] = + &hex!("8222756E7465726E65686D656E736E616368666F6C67652D696E2D62617965726E2E6465"); + const DIRECTORY_NAME: &[u8] = + &hex!("A43B3039310B3009060355040613024445310F300D06035504080C0642617965726E31193017060355040A0C104672656973746161742042617965726E"); + // TODO: EdiPartyName + const URI: &[u8] = &hex!( + "862A687474703A2F2F63726C2E71756F7661646973676C6F62616C2E636F6D2F71767263613267332E63726C" + ); + const IPADDR: &[u8] = + &hex!("87202A02102C000000000000000000000000FFFFFFFF000000000000000000000000"); + // TODO: RegisteredId + + const OTHER_NAMES: &[u8] = + &hex!("301da01b060560865e0202a0120c105249462d472d32303030343033362d30"); + const RFC822_NAMES: &[u8] = &hex!("30198117456D61696C5F353238343037373733406468732E676F76"); + const DNS_NAMES: &[u8] = + &hex!("30248222756E7465726E65686D656E736E616368666F6C67652D696E2D62617965726E2E6465"); + const DIRECTORY_NAMES: &[u8] = &hex!("303DA43B3039310B3009060355040613024445310F300D06035504080C0642617965726E31193017060355040A0C104672656973746161742042617965726E"); + // TODO: EdiPartyName + const URIS: &[u8] = &hex!("302C862A687474703A2F2F63726C2E71756F7661646973676C6F62616C2E636F6D2F71767263613267332E63726C"); + const IPADDRS: &[u8] = + &hex!("302287202A02102C000000000000000000000000FFFFFFFF000000000000000000000000"); + // TODO: RegisteredId + + #[rstest] + #[case(1, OTHER_NAME)] + #[case(2, RFC822_NAME)] + #[case(3, DNS_NAME)] + #[case(4, DIRECTORY_NAME)] + #[case(5, URI)] + #[case(6, IPADDR)] + fn singular(#[case] idx: usize, #[case] value: &[u8]) { + let decoded = GeneralName::from_der(value).unwrap(); + + match (idx, &decoded) { + (1, GeneralName::OtherName(..)) => (), + (2, GeneralName::Rfc822Name(..)) => (), + (3, GeneralName::DnsName(..)) => (), + (4, GeneralName::DirectoryName(..)) => (), + (5, GeneralName::UniformResourceIdentifier(..)) => (), + (6, GeneralName::IpAddress(..)) => (), + _ => panic!("unexpected decoded value"), + } + + let encoded = decoded.to_vec().unwrap(); + assert_eq!(value, encoded); + } + + #[rstest] + #[case(1, OTHER_NAMES)] + #[case(2, RFC822_NAMES)] + #[case(3, DNS_NAMES)] + #[case(4, DIRECTORY_NAMES)] + #[case(5, URIS)] + #[case(6, IPADDRS)] + fn plural(#[case] idx: usize, #[case] value: &[u8]) { + let decoded = GeneralNames::from_der(value).unwrap(); + + assert_eq!(1, decoded.len()); + match (idx, &decoded[0]) { + (1, GeneralName::OtherName(..)) => (), + (2, GeneralName::Rfc822Name(..)) => (), + (3, GeneralName::DnsName(..)) => (), + (4, GeneralName::DirectoryName(..)) => (), + (5, GeneralName::UniformResourceIdentifier(..)) => (), + (6, GeneralName::IpAddress(..)) => (), + _ => panic!("unexpected decoded value"), + } + + let encoded = decoded.to_vec().unwrap(); + assert_eq!(value, encoded); + } +} diff --git a/x509/src/ext/pkix/name/other.rs b/x509/src/ext/pkix/name/other.rs new file mode 100644 index 000000000..31b0d1280 --- /dev/null +++ b/x509/src/ext/pkix/name/other.rs @@ -0,0 +1,37 @@ +use der::{asn1::ObjectIdentifier, Any, Decodable, Sequence}; + +/// OtherName as defined in [RFC 5280 Section 4.2.1.6]. +/// +/// ```text +/// OtherName ::= SEQUENCE { +/// type-id OBJECT IDENTIFIER, +/// value [0] EXPLICIT ANY DEFINED BY type-id +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct OtherName<'a> { + pub type_id: ObjectIdentifier, + + #[asn1(context_specific = "0", tag_mode = "EXPLICIT")] + pub value: Any<'a>, +} + +#[test] +#[cfg(test)] +fn test() { + use der::{Decodable, Encodable}; + use hex_literal::hex; + + let input = hex!("3021060A2B060104018237140203A0130C1155706E5F323134393530313330406D696C"); + let decoded = OtherName::from_der(&input).unwrap(); + eprintln!("{:?}", decoded.value); + + let onval = decoded.value.utf8_string().unwrap(); + assert_eq!(onval.to_string(), "Upn_214950130@mil"); + + let encoded = decoded.to_vec().unwrap(); + assert_eq!(&input[..], &encoded); +} diff --git a/x509/src/ext/pkix/oids.rs b/x509/src/ext/pkix/oids.rs new file mode 100644 index 000000000..14012321d --- /dev/null +++ b/x509/src/ext/pkix/oids.rs @@ -0,0 +1,187 @@ +//! Object identifier values from PKIX1Implicit and PKIX1Explicit ASN.1 modules + +use der::asn1::ObjectIdentifier; + +/// OID for CPS qualifier: 1.3.6.1.5.5.7.2.1 +pub const QT_CPS: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.2.1"); + +/// OID for user notice qualifier: 1.3.6.1.5.5.7.2.2 +pub const QT_UNOTICE: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.2.2"); + +/// OID for OCSP access descriptor: 1.3.6.1.5.5.7.48.1: 1.3.6.1.5.5.7.48.1 +pub const AD_OCSP: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.1"); + +/// OID for caIssuers access descriptor: 1.3.6.1.5.5.7.48.2 +pub const AD_CA_ISSUERS: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.2"); + +/// OID for timeStamping access descriptor: 1.3.6.1.5.5.7.48.3 +pub const AD_TIME_STAMPING: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.3"); + +/// OID for caRepository access descriptor: 1.3.6.1.5.5.7.48.5 +pub const AD_CA_REPOSITORY: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.5"); + +/// OID for Name attribute: 2.5.4.41 +pub const AT_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.41"); + +/// OID for Surname attribute: 2.5.4.4 +pub const AT_SURNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.4"); + +/// OID for givenName attribute: 2.5.4.42 +pub const AT_GIVENNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.42"); + +/// OID for Initials attribute: 2.5.4.43 +pub const AT_INITIALS: ObjectIdentifier = ObjectIdentifier::new("2.5.4.43"); + +/// OID for generationQualifier attribute: 2.5.4.44 +pub const AT_GENERATION_QUALIFIER: ObjectIdentifier = ObjectIdentifier::new("2.5.4.44"); + +/// OID for commonName attribute: 2.5.4.3 +pub const AT_COMMON_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.3"); + +/// OID for localityName attribute: 2.5.4.7 +pub const AT_LOCALITY_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.7"); + +/// OID for stateOrProvinceName attribute: 2.5.4.8 +pub const AT_STATEORPROVINCENAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.8"); + +/// OID for street attribute: 2.5.4.9 +pub const AT_STREET: ObjectIdentifier = ObjectIdentifier::new("2.5.4.9"); + +/// OID for organizationName attribute: 2.5.4.10 +pub const AT_ORGANIZATIONNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.10"); + +/// OID for organizationalUnitName attribute: 2.5.4.11 +pub const AT_ORGANIZATIONALUNITNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.11"); + +/// OID for title attribute: 2.5.4.12 +pub const AT_TITLE: ObjectIdentifier = ObjectIdentifier::new("2.5.4.12"); + +/// OID for dnQualifier attribute: 2.5.4.46 +pub const AT_DNQUALIFIER: ObjectIdentifier = ObjectIdentifier::new("2.5.4.46"); + +/// OID for countryName attribute: 2.5.4.6 +pub const AT_COUNTRYNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.6"); + +/// OID for serialNumber attribute: 2.5.4.5 +pub const AT_SERIALNUMBER: ObjectIdentifier = ObjectIdentifier::new("2.5.4.5"); + +/// OID for pseudonym attribute: 2.5.4.65 +pub const AT_PSEUDONYM: ObjectIdentifier = ObjectIdentifier::new("2.5.4.65"); + +/// OID for domainComponent attribute: 0.9.2342.19200300.100.1.25 +pub const DOMAINCOMPONENT: ObjectIdentifier = ObjectIdentifier::new("0.9.2342.19200300.100.1.25"); + +/// OID for emailAddress attribute: 1.2.840.113549.1.9.1 +pub const EMAILADDRESS: ObjectIdentifier = ObjectIdentifier::new("1.2.840.113549.1.9.1"); + +/// OID for anyPolicy extension: 2.5.29.32.0 +pub const CE_ANYPOLICY: ObjectIdentifier = ObjectIdentifier::new("2.5.29.32.0"); + +/// OID for extKeyUsage extension: 2.5.29.37. See [`ExtendedKeyUsage`](type.ExtendedKeyUsage.html). +pub const CE_EXTKEYUSAGE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.37"); + +/// OID for anyExtendedKeyUsage EKU value: 2.5.29.37.0 +pub const CE_ANYEXTENDEDKEYUSAGE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.37.0"); + +/// OID for serverAuth key purpose: 1.3.6.1.5.5.7.3.31 +pub const KP_SERVERAUTH: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.31"); + +/// OID for clientAuth key purpose: 1.3.6.1.5.5.7.3.32 +pub const KP_CLIENTAUTH: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.32"); + +/// OID for codeSigning key purpose: 1.3.6.1.5.5.7.3.33 +pub const KP_CODESIGNING: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.33"); + +/// OID for emailProtection key purpose: 1.3.6.1.5.5.7.3.34 +pub const KP_EMAILPROTECTION: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.34"); + +/// OID for timeStamping key purpose: 1.3.6.1.5.5.7.3.38 +pub const KP_TIMESTAMPING: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.38"); + +/// OID for OCSPSigning key purpose: 1.3.6.1.5.5.7.3.39 +pub const KP_OCSPSIGNING: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.39"); + +/// OID for authorityInfoAccess extension: 1.3.6.1.5.5.7.1.1 +pub const PE_AUTHORITYINFOACCESS: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.1.1"); + +/// OID for subjectInfoAccess extension: 1.3.6.1.5.5.7.1.11 +pub const PE_SUBJECTINFOACCESS: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.1.11"); + +/// OID for subjectDirectoryAttributes extension: 2.5.29.9. See [`SubjectDirectoryAttributes`](type.SubjectDirectoryAttributes.html). +pub const CE_SUBJECT_DIRECTORY_ATTRIBUTES: ObjectIdentifier = ObjectIdentifier::new("2.5.29.9"); + +/// OID for subjectKeyIdentifier extension: 2.5.29.14. See [`SubjectKeyIdentifier`](type.SubjectKeyIdentifier.html). +pub const CE_SUBJECT_KEY_IDENTIFIER: ObjectIdentifier = ObjectIdentifier::new("2.5.29.14"); + +/// OID for keyUsage extension: 2.5.29.15. See [`KeyUsage`](type.KeyUsage.html). +pub const CE_KEY_USAGE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.15"); + +/// OID for privateKeyUsagePeriod extension: 2.5.29.16. See [`PrivateKeyUsagePeriod`](struct.PrivateKeyUsagePeriod.html). +pub const CE_PRIVATE_KEY_USAGE_PERIOD: ObjectIdentifier = ObjectIdentifier::new("2.5.29.16"); + +/// OID for subjectAltName extension: 2.5.29.17. See [`SubjectAltName`](type.SubjectAltName.html). +pub const CE_SUBJECT_ALT_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.29.17"); + +/// OID for issuerAltName extension: 2.5.29.18. See [`IssuerAltName`](type.IssuerAltName.html). +pub const CE_ISSUER_ALT_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.29.18"); + +/// OID for basicConstraints extension: 2.5.29.19. See [`BasicConstraints`](struct.BasicConstraints.html). +pub const CE_BASIC_CONSTRAINTS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.19"); + +/// OID for cRLNumber extension: 2.5.29.20 +pub const CE_CRLNUMBER: ObjectIdentifier = ObjectIdentifier::new("2.5.29.20"); + +/// OID for cRLReasons extension: 2.5.29.21 +pub const CE_CRLREASONS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.21"); + +/// OID for issuingDistributionPoint extension: 2.5.29.28 +pub const CE_ISSUINGDISTRIBUTIONPOINT: ObjectIdentifier = ObjectIdentifier::new("2.5.29.28"); + +/// OID for deltaCRLIndicator extension: 2.5.29.27 +pub const CE_DELTACRLINDICATOR: ObjectIdentifier = ObjectIdentifier::new("2.5.29.27"); + +/// OID for certificateIssuer extension: 2.5.29.29 +pub const CE_CERTIFICATEISSUER: ObjectIdentifier = ObjectIdentifier::new("2.5.29.29"); + +/// OID for holdInstructionCode extension: 2.5.29.23 +pub const CE_HOLDINSTRUCTIONCODE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.23"); + +/// OID forholdinstruction-callissuer attribute: 2.2.840.10040.2.2 +pub const HI_HOLDINSTRUCTION_CALLISSUER: ObjectIdentifier = + ObjectIdentifier::new("2.2.840.10040.2.2"); + +/// OID for holdinstruction-reject attribute: 2.2.840.10040.23 +pub const HI_HOLDINSTRUCTION_REJECT: ObjectIdentifier = ObjectIdentifier::new("2.2.840.10040.23"); + +/// OID for invalidityDate extension: 2.5.29.24 +pub const CE_INVALIDITYDATE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.24"); + +/// OID for nameConstraints extension: 2.5.29.30. See [`CertificatePolicies`](type.CertificatePolicies.html). +pub const CE_NAME_CONSTRAINTS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.30"); + +/// OID for cRLDistributionPoints extension: 2.5.29.31. See [`CertificatePolicies`](type.CertificatePolicies.html). +pub const CE_CRL_DISTRIBUTION_POINTS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.31"); + +/// OID for certificatePolicies extension: 2.5.29.32. See [`CertificatePolicies`](type.CertificatePolicies.html). +pub const CE_CERTIFICATE_POLICIES: ObjectIdentifier = ObjectIdentifier::new("2.5.29.32"); + +/// OID for policyMappings extension: 2.5.29.33. See [`PolicyMappings`](type.PolicyMappings.html). +pub const CE_POLICY_MAPPINGS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.33"); + +/// OID for authorityKeyIdentifier extension: 2.5.29.35. See [`AuthorityKeyIdentifier`](type.AuthorityKeyIdentifier.html). +pub const CE_AUTHORITY_KEY_IDENTIFIER: ObjectIdentifier = ObjectIdentifier::new("2.5.29.35"); + +/// OID for policyConstraints extension: 2.5.29.36. See [`PolicyConstraints`](struct.PolicyConstraints.html). +pub const CE_POLICY_CONSTRAINTS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.36"); + +/// OID for policyConstraints extension: 2.5.29.46. See [`PolicyConstraints`](type.FreshestCRL.html). +pub const CE_FRESHEST_CRL: ObjectIdentifier = ObjectIdentifier::new("2.5.29.46"); + +/// OID for inhibitAnyPolicy extension: 2.5.29.54. See [`InhibitAnyPolicy`](type.InhibitAnyPolicy.html). +pub const CE_INHIBIT_ANY_POLICY: ObjectIdentifier = ObjectIdentifier::new("2.5.29.54"); + +/// OID for ocspNoCheck extension: 1.3.6.1.5.5.7.48.1.5. See [`OcspNoCheck`](type.OcspNoCheck.html). +pub const OCSP_NOCHECK: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.1.5"); + +/// OID for PIV NACI extension: 2.16.840.1.101.3.6.9.1. See [`PivNaciIndicator`](type.PivNaciIndicator.html). +pub const PIV_NACI_INDICATOR: ObjectIdentifier = ObjectIdentifier::new("2.16.840.1.101.3.6.9.1"); diff --git a/x509/src/ext/pkix/policymap.rs b/x509/src/ext/pkix/policymap.rs new file mode 100644 index 000000000..54feee04a --- /dev/null +++ b/x509/src/ext/pkix/policymap.rs @@ -0,0 +1,34 @@ +use alloc::vec::Vec; + +use der::asn1::ObjectIdentifier; +use der::Sequence; + +/// PolicyMappings as defined in [RFC 5280 Section 4.2.1.5]. +/// +/// This extension is identified by the [`PKIX_CE_POLICY_MAPPINGS`](constant.PKIX_CE_POLICY_MAPPINGS.html) OID. +/// +/// ```text +/// PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { +/// ``` +/// +/// [RFC 5280 Section 4.2.1.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.5 +pub type PolicyMappings<'a> = Vec; + +/// PolicyMapping as defined in [RFC 5280 Section 4.2.1.5]. +/// +/// ```text +/// PolicyMapping ::= SEQUENCE { +/// issuerDomainPolicy CertPolicyId, +/// subjectDomainPolicy CertPolicyId +/// } +/// ``` +/// +/// [RFC 5280 Section 4.2.1.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.5 +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +pub struct PolicyMapping { + /// issuerDomainPolicy CertPolicyId, + pub issuer_domain_policy: ObjectIdentifier, + + /// subjectDomainPolicy CertPolicyId } + pub subject_domain_policy: ObjectIdentifier, +} diff --git a/x509/src/general_name.rs b/x509/src/general_name.rs deleted file mode 100644 index 939672680..000000000 --- a/x509/src/general_name.rs +++ /dev/null @@ -1,403 +0,0 @@ -//! GeneralNames as defined in [RFC 5280 Section 4.2.1.6]. - -use alloc::string::ToString; -use alloc::vec::Vec; -use der::asn1::{Any, ContextSpecific, Ia5String, ObjectIdentifier, OctetString}; -use der::{Decodable, Decoder, ErrorKind, Sequence, TagMode, TagNumber}; -use x501::name::Name; - -/// OtherName as defined in [RFC 5280 Section 4.2.1.6]. -/// -/// ```text -/// OtherName ::= SEQUENCE { -/// type-id OBJECT IDENTIFIER, -/// value [0] EXPLICIT ANY DEFINED BY type-id -/// } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -#[allow(missing_docs)] -pub struct OtherName<'a> { - pub type_id: ObjectIdentifier, - - #[asn1(context_specific = "0", tag_mode = "EXPLICIT")] - pub value: Any<'a>, -} - -/// GeneralNames as defined in [RFC 5280 Section 4.2.1.6] in support of the Subject Alternative Name extension. -/// -/// ```text -/// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName -/// ``` -/// -/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 -pub type GeneralNames<'a> = Vec>; - -/// GeneralName as defined in [RFC 5280 Section 4.2.1.6] in support of the Subject Alternative Name extension. -/// -/// ```text -/// GeneralName ::= CHOICE { -/// otherName [0] OtherName, -/// rfc822Name [1] IA5String, -/// dNSName [2] IA5String, -/// x400Address [3] ORAddress, -/// directoryName [4] Name, -/// ediPartyName [5] EDIPartyName, -/// uniformResourceIdentifier [6] IA5String, -/// iPAddress [7] OCTET STRING, -/// registeredID [8] OBJECT IDENTIFIER } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum GeneralName<'a> { - /// otherName [0] OtherName, - OtherName(OtherName<'a>), - - /// rfc822Name [1] IA5String, - Rfc822Name(Ia5String<'a>), - - /// dNSName [2] IA5String, - DnsName(Ia5String<'a>), - - // x400Address [3] ORAddress, - // Not supporting x400Address - /// directoryName [4] Name, - DirectoryName(Name<'a>), - - // ediPartyName [5] EDIPartyName, - // Not supporting ediPartyName - /// uniformResourceIdentifier [6] IA5String, - UniformResourceIdentifier(Ia5String<'a>), - - /// iPAddress [7] OCTET STRING, - IpAddress(OctetString<'a>), - - /// registeredID [8] OBJECT IDENTIFIER - RegisteredId(ObjectIdentifier), -} - -const OTHER_NAME_TAG: TagNumber = TagNumber::new(0); -const RFC822_NAME_TAG: TagNumber = TagNumber::new(1); -const DNS_NAME_TAG: TagNumber = TagNumber::new(2); -//const X400_ADDRESS_TAG: TagNumber = TagNumber::new(3); -const DIRECTORY_NAME_TAG: TagNumber = TagNumber::new(4); -//const EDIPI_PARTY_NAME_TAG: TagNumber = TagNumber::new(5); -const URI_TAG: TagNumber = TagNumber::new(6); -const IP_ADDRESS_TAG: TagNumber = TagNumber::new(7); -const REGISTERED_ID_TAG: TagNumber = TagNumber::new(8); - -// Custom Decodable to handle implicit context specific fields (this may move to derived later). -impl<'a> Decodable<'a> for GeneralName<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - let t = decoder.peek_tag()?; - match t.octet() { - 0xA0 => { - let on = - decoder.context_specific::>(OTHER_NAME_TAG, TagMode::Implicit)?; - Ok(GeneralName::OtherName(on.unwrap())) - } - 0x81 => { - let ia5 = decoder - .context_specific::>(RFC822_NAME_TAG, TagMode::Implicit)?; - Ok(GeneralName::Rfc822Name(ia5.unwrap())) - } - 0x82 => { - let ia5 = - decoder.context_specific::>(DNS_NAME_TAG, TagMode::Implicit)?; - Ok(GeneralName::DnsName(ia5.unwrap())) - } - //0xA3 => Not supporting x400Address, - 0xA4 => { - // Explicit is used because Name is also a CHOICE. Nested CHOICEs are essentially - // EXPLICIT tags. See section 31.2.7 in X.680. - let ia5 = - decoder.context_specific::>(DIRECTORY_NAME_TAG, TagMode::Explicit)?; - Ok(GeneralName::DirectoryName(ia5.unwrap())) - } - //0xA5 => Not supporting ediPartyName, - 0x86 => { - let ia5 = decoder.context_specific::>(URI_TAG, TagMode::Implicit)?; - Ok(GeneralName::UniformResourceIdentifier(ia5.unwrap())) - } - 0x87 => { - let os = decoder - .context_specific::>(IP_ADDRESS_TAG, TagMode::Implicit)?; - Ok(GeneralName::IpAddress(os.unwrap())) - } - 0x88 => { - let os = decoder - .context_specific::(REGISTERED_ID_TAG, TagMode::Implicit)?; - Ok(GeneralName::RegisteredId(os.unwrap())) - } - _ => Err(ErrorKind::TagUnknown { byte: t.octet() }.into()), - } - } -} - -impl<'a> ::der::Encodable for GeneralName<'a> { - fn encode(&self, encoder: &mut ::der::Encoder<'_>) -> ::der::Result<()> { - match self { - Self::OtherName(variant) => ContextSpecific { - tag_number: OTHER_NAME_TAG, - tag_mode: TagMode::Implicit, - value: variant.clone(), - } - .encode(encoder), - Self::Rfc822Name(variant) => ContextSpecific { - tag_number: RFC822_NAME_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::Ia5String::new(variant)?, - } - .encode(encoder), - Self::DnsName(variant) => ContextSpecific { - tag_number: DNS_NAME_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::Ia5String::new(variant)?, - } - .encode(encoder), - // Explicit is used because Name is also a CHOICE. Nested CHOICEs are essentially - // EXPLICIT tags. See section 31.2.7 in X.680. - Self::DirectoryName(variant) => ContextSpecific { - tag_number: DIRECTORY_NAME_TAG, - tag_mode: TagMode::Explicit, - value: variant.clone(), - } - .encode(encoder), - Self::UniformResourceIdentifier(variant) => ContextSpecific { - tag_number: URI_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::Ia5String::new(variant)?, - } - .encode(encoder), - Self::IpAddress(variant) => ContextSpecific { - tag_number: IP_ADDRESS_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::OctetString::new(variant.as_bytes())?, - } - .encode(encoder), - Self::RegisteredId(variant) => ContextSpecific { - tag_number: REGISTERED_ID_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::ObjectIdentifier::new(variant.to_string().as_str()), - } - .encode(encoder), - } - } - fn encoded_len(&self) -> ::der::Result<::der::Length> { - // Could just do variant.encode for the implicitly tagged fields - match self { - Self::OtherName(variant) => ContextSpecific { - tag_number: OTHER_NAME_TAG, - tag_mode: TagMode::Implicit, - value: variant.clone(), - } - .encoded_len(), - Self::Rfc822Name(variant) => ContextSpecific { - tag_number: RFC822_NAME_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::Ia5String::new(variant)?, - } - .encoded_len(), - Self::DnsName(variant) => ContextSpecific { - tag_number: DNS_NAME_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::Ia5String::new(variant)?, - } - .encoded_len(), - // Explicit is used because Name is also a CHOICE. Nested CHOICEs are essentially - // EXPLICIT tags. See section 31.2.7 in X.680. - Self::DirectoryName(variant) => ContextSpecific { - tag_number: DIRECTORY_NAME_TAG, - tag_mode: TagMode::Explicit, - value: variant.clone(), - } - .encoded_len(), - Self::UniformResourceIdentifier(variant) => ContextSpecific { - tag_number: URI_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::Ia5String::new(variant)?, - } - .encoded_len(), - Self::IpAddress(variant) => ContextSpecific { - tag_number: IP_ADDRESS_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::OctetString::new(variant.as_bytes())?, - } - .encoded_len(), - Self::RegisteredId(variant) => ContextSpecific { - tag_number: REGISTERED_ID_TAG, - tag_mode: TagMode::Implicit, - value: ::der::asn1::ObjectIdentifier::new(variant.to_string().as_str()), - } - .encoded_len(), - } - } -} - -#[test] -fn reencode_gn() { - use der::Encodable; - use hex_literal::hex; - - // OtherName - // 0 27: [0] { - // 2 5: OBJECT IDENTIFIER '2 16 862 2 2' - // 9 18: [0] { - // 11 16: UTF8String 'RIF-G-20004036-0' - // : } - // : } - let decoded_other_name = GeneralName::from_der(&hex!( - "A01B060560865E0202A0120C105249462D472D32303030343033362D30" - )) - .unwrap(); - let reencoded_other_name = decoded_other_name.to_vec().unwrap(); - assert_eq!( - &hex!("A01B060560865E0202A0120C105249462D472D32303030343033362D30"), - reencoded_other_name.as_slice() - ); - - let gns_other_name = GeneralNames::from_der(&hex!( - "30198117456D61696C5F353238343037373733406468732E676F76" - )) - .unwrap(); - let reencoded_gns_other_name = gns_other_name.to_vec().unwrap(); - assert_eq!( - &hex!("30198117456D61696C5F353238343037373733406468732E676F76"), - reencoded_gns_other_name.as_slice() - ); - - // Rfc822Name - // 0 23: [1] 'Email_528407773@dhs.gov' - let decoded_rfc822_name = - GeneralName::from_der(&hex!("8117456D61696C5F353238343037373733406468732E676F76")).unwrap(); - let reencoded_rfc822_name = decoded_rfc822_name.to_vec().unwrap(); - assert_eq!( - &hex!("8117456D61696C5F353238343037373733406468732E676F76"), - reencoded_rfc822_name.as_slice() - ); - - let gns_rfc822_name = GeneralNames::from_der(&hex!( - "30198117456D61696C5F353238343037373733406468732E676F76" - )) - .unwrap(); - let reencoded_gns_rfc822_name = gns_rfc822_name.to_vec().unwrap(); - assert_eq!( - &hex!("30198117456D61696C5F353238343037373733406468732E676F76"), - reencoded_gns_rfc822_name.as_slice() - ); - - // DnsName - // 0 34: [2] 'unternehmensnachfolge-in-bayern.de' - let decoded_dns_name = GeneralName::from_der(&hex!( - "8222756E7465726E65686D656E736E616368666F6C67652D696E2D62617965726E2E6465" - )) - .unwrap(); - let reencoded_dns_name = decoded_dns_name.to_vec().unwrap(); - assert_eq!( - &hex!("8222756E7465726E65686D656E736E616368666F6C67652D696E2D62617965726E2E6465"), - reencoded_dns_name.as_slice() - ); - - let gns_dns_name = GeneralNames::from_der(&hex!( - "30248222756E7465726E65686D656E736E616368666F6C67652D696E2D62617965726E2E6465" - )) - .unwrap(); - let reencoded_gns_dns_name = gns_dns_name.to_vec().unwrap(); - assert_eq!( - &hex!("30248222756E7465726E65686D656E736E616368666F6C67652D696E2D62617965726E2E6465"), - reencoded_gns_dns_name.as_slice() - ); - - // DirectoryName - // 0 59: [4] { - // 2 57: SEQUENCE { - // 4 11: SET { - // 6 9: SEQUENCE { - // 8 3: OBJECT IDENTIFIER countryName (2 5 4 6) - // 13 2: PrintableString 'DE' - // : } - // : } - // 17 15: SET { - // 19 13: SEQUENCE { - // 21 3: OBJECT IDENTIFIER stateOrProvinceName (2 5 4 8) - // 26 6: UTF8String 'Bayern' - // : } - // : } - // 34 25: SET { - // 36 23: SEQUENCE { - // 38 3: OBJECT IDENTIFIER organizationName (2 5 4 10) - // 43 16: UTF8String 'Freistaat Bayern' - // : } - // : } - // : } - // : } - let decoded_dn = - GeneralName::from_der(&hex!("A43B3039310B3009060355040613024445310F300D06035504080C0642617965726E31193017060355040A0C104672656973746161742042617965726E")).unwrap(); - let reencoded_dn = decoded_dn.to_vec().unwrap(); - assert_eq!( - &hex!("A43B3039310B3009060355040613024445310F300D06035504080C0642617965726E31193017060355040A0C104672656973746161742042617965726E"), - reencoded_dn.as_slice() - ); - - let gns_dn = GeneralNames::from_der(&hex!( - "303DA43B3039310B3009060355040613024445310F300D06035504080C0642617965726E31193017060355040A0C104672656973746161742042617965726E" - )) - .unwrap(); - let reencoded_gns_dn = gns_dn.to_vec().unwrap(); - assert_eq!( - &hex!("303DA43B3039310B3009060355040613024445310F300D06035504080C0642617965726E31193017060355040A0C104672656973746161742042617965726E"), - reencoded_gns_dn.as_slice() - ); - - // UniformResourceIdentifier - // 0 42: [6] - // : 'http://crl.quovadisglobal.com/qvrca2g3.crl' - let decoded_uri = GeneralName::from_der(&hex!( - "862A687474703A2F2F63726C2E71756F7661646973676C6F62616C2E636F6D2F71767263613267332E63726C" - )) - .unwrap(); - let reencoded_uri = decoded_uri.to_vec().unwrap(); - assert_eq!( - &hex!("862A687474703A2F2F63726C2E71756F7661646973676C6F62616C2E636F6D2F71767263613267332E63726C"), - reencoded_uri.as_slice() - ); - - let gns_uri = GeneralNames::from_der(&hex!( - "302C862A687474703A2F2F63726C2E71756F7661646973676C6F62616C2E636F6D2F71767263613267332E63726C" - )) - .unwrap(); - let reencoded_gns_uri = gns_uri.to_vec().unwrap(); - assert_eq!( - &hex!("302C862A687474703A2F2F63726C2E71756F7661646973676C6F62616C2E636F6D2F71767263613267332E63726C"), - reencoded_gns_uri.as_slice() - ); - - // IP Address - // 0 32: [7] - // : 2A 02 10 2C 00 00 00 00 00 00 00 00 00 00 00 00 - // : FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 - let decoded_ip = GeneralName::from_der(&hex!( - "87202A02102C000000000000000000000000FFFFFFFF000000000000000000000000" - )) - .unwrap(); - let reencoded_ip = decoded_ip.to_vec().unwrap(); - assert_eq!( - &hex!("87202A02102C000000000000000000000000FFFFFFFF000000000000000000000000"), - reencoded_ip.as_slice() - ); - - let gns_ip = GeneralNames::from_der(&hex!( - "302287202A02102C000000000000000000000000FFFFFFFF000000000000000000000000" - )) - .unwrap(); - let reencoded_gns_ip = gns_ip.to_vec().unwrap(); - assert_eq!( - &hex!("302287202A02102C000000000000000000000000FFFFFFFF000000000000000000000000"), - reencoded_gns_ip.as_slice() - ); - - // RegisteredId - // TODO -} diff --git a/x509/src/lib.rs b/x509/src/lib.rs index be312a3c7..36cf50076 100644 --- a/x509/src/lib.rs +++ b/x509/src/lib.rs @@ -1,4 +1,4 @@ -#![no_std] +#![cfg_attr(not(test), no_std)] #![cfg_attr(docsrs, feature(doc_cfg))] #![doc = include_str!("../README.md")] #![doc( @@ -14,12 +14,9 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; +pub mod anchor; +pub mod ext; + mod certificate; -mod general_name; -pub mod pkix_extensions; -pub mod pkix_oids; -pub mod trust_anchor_format; -pub use crate::{certificate::*, general_name::*, pkix_extensions::*, pkix_oids::*}; -pub use der::{self, asn1::ObjectIdentifier}; -pub use spki::{self, AlgorithmIdentifier, SubjectPublicKeyInfo}; +pub use certificate::{Certificate, TbsCertificate, Version}; diff --git a/x509/src/pkix_extensions.rs b/x509/src/pkix_extensions.rs deleted file mode 100644 index 4725cf63a..000000000 --- a/x509/src/pkix_extensions.rs +++ /dev/null @@ -1,672 +0,0 @@ -//! Extensions [`Extensions`] as defined in RFC 5280 - -use crate::general_name::GeneralName; -use crate::general_name::GeneralNames; - -use alloc::vec::Vec; - -use der::asn1::*; -use der::{Choice, Enumerated, Sequence}; -use flagset::{flags, FlagSet}; -use x501::attr::AttributeTypeAndValue; -use x501::name::RelativeDistinguishedName; - -/// DisplayText as defined in [RFC 5280 Section 4.2.1.4] in support of the Certificate Policies extension. -/// -/// ASN.1 structure for DisplayText is below. At present, only the ia5String and utf8String options are supported. -/// -/// ```text -/// DisplayText ::= CHOICE { -/// ia5String IA5String (SIZE (1..200)), -/// visibleString VisibleString (SIZE (1..200)), -/// bmpString BMPString (SIZE (1..200)), -/// utf8String UTF8String (SIZE (1..200)) } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 -#[derive(Choice, Clone, Debug, Eq, PartialEq)] -pub enum DisplayText<'a> { - /// ia5String IA5String (SIZE (1..200)) - #[asn1(type = "IA5String")] - Ia5String(Ia5String<'a>), - - /// visibleString VisibleString (SIZE (1..200)), - // TODO: support VisibleString if desired - - /// bmpString BMPString (SIZE (1..200)), - // TODO: support BMPString if desired - - /// utf8String UTF8String (SIZE (1..200)) - #[asn1(type = "UTF8String")] - Utf8String(Utf8String<'a>), -} - -/// Extended key usage extension as defined in [RFC 5280 Section 4.2.1.12] and as identified by the [`PKIX_CE_EXTKEYUSAGE`](constant.PKIX_CE_EXTKEYUSAGE.html) OID. -/// -/// Many extended key usage values include: -/// - [`PKIX_CE_ANYEXTENDEDKEYUSAGE`](constant.PKIX_CE_ANYEXTENDEDKEYUSAGE.html), -/// - [`PKIX_KP_SERVERAUTH`](constant.PKIX_KP_SERVERAUTH.html), -/// - [`PKIX_KP_CLIENTAUTH`](constant.PKIX_KP_CLIENTAUTH.html), -/// - [`PKIX_KP_CODESIGNING`](constant.PKIX_KP_CODESIGNING.html), -/// - [`PKIX_KP_EMAILPROTECTION`](constant.PKIX_KP_EMAILPROTECTION.html), -/// - [`PKIX_KP_TIMESTAMPING`](constant.PKIX_KP_TIMESTAMPING.html), -/// -/// ```text -/// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId -/// ``` -/// -/// [RFC 5280 Section 4.2.1.12]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12 -pub type ExtendedKeyUsage<'a> = Vec; - -/// Subject alternative name extension as defined in [RFC 5280 Section 4.2.1.6] and as identified by the [`PKIX_CE_SUBJECT_ALT_NAME`](constant.PKIX_CE_SUBJECT_ALT_NAME.html) OID. -/// -/// ```text -/// SubjectAltName ::= GeneralNames -/// ``` -/// -/// [RFC 5280 Section 4.2.1.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 -pub type SubjectAltName<'a> = GeneralNames<'a>; - -/// Issuer alternative name extension as defined in [RFC 5280 Section 4.2.1.7] and as identified by the [`PKIX_CE_ISSUER_ALT_NAME`](constant.PKIX_CE_ISSUER_ALT_NAME.html) OID. -/// -/// ```text -/// IssuerAltName ::= GeneralNames -/// ``` -/// -/// [RFC 5280 Section 4.2.1.7]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.7 -pub type IssuerAltName<'a> = GeneralNames<'a>; - -/// OCSP noCheck extension as defined in [RFC 6960 Section 4.2.2.2.1] and as idenfied by the [`PKIX_OCSP_NOCHECK`](constant.PKIX_OCSP_NOCHECK.html) OID. -/// -/// ```text -/// OcspNoCheck ::= NULL -/// ``` -/// -/// [RFC 6960 Section 4.2.2.2.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.2.2.1 -pub type OcspNoCheck = Null; - -/// Subject directory attributes extension as defined in [RFC 5280 Section 4.2.1.8] and as identified by the [`PKIX_CE_SUBJECT_DIRECTORY_ATTRIBUTES`](constant.PKIX_CE_SUBJECT_DIRECTORY_ATTRIBUTES.html) OID. -/// -/// ```text -/// SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF AttributeSet -/// ``` -/// -/// [RFC 5280 Section 4.2.1.8]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.8 -pub type SubjectDirectoryAttributes<'a> = Vec>; - -/// Basic constraints extension as defined in [RFC 5280 Section 4.2.1.9] and as identified by the [`PKIX_CE_BASIC_CONSTRAINTS`](constant.PKIX_CE_BASIC_CONSTRAINTS.html) OID. -/// -/// ```text -/// BasicConstraints ::= SEQUENCE { -/// cA BOOLEAN DEFAULT FALSE, -/// pathLenConstraint INTEGER (0..MAX) OPTIONAL } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.9 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -pub struct BasicConstraints { - /// cA BOOLEAN DEFAULT FALSE, - #[asn1(default = "Default::default")] - pub ca: bool, - - /// pathLenConstraint INTEGER (0..MAX) OPTIONAL - pub path_len_constraint: Option, -} - -/// Subject key identifier extension as defined in [RFC 5280 Section 4.2.1.2] and as identified by the [`PKIX_CE_SUBJECT_KEY_IDENTIFIER`](constant.PKIX_CE_SUBJECT_KEY_IDENTIFIER.html) OID. -/// -/// ```text -/// SubjectKeyIdentifier ::= KeyIdentifier -/// ``` -/// -/// [RFC 5280 Section 4.2.1.2]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.2 -pub type SubjectKeyIdentifier<'a> = OctetString<'a>; - -flags! { - /// Key usage flags as defined in [RFC 5280 Section 4.2.1.3]. - /// - /// ```text - /// KeyUsage ::= BIT STRING { - /// digitalSignature (0), - /// nonRepudiation (1), -- recent editions of X.509 have - /// -- renamed this bit to contentCommitment - /// keyEncipherment (2), - /// dataEncipherment (3), - /// keyAgreement (4), - /// keyCertSign (5), - /// cRLSign (6), - /// encipherOnly (7), - /// decipherOnly (8) - /// } - /// ``` - /// - /// [RFC 5280 Section 4.2.1.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 - #[allow(missing_docs)] - pub enum KeyUsages: u16 { - DigitalSignature = 1 << 0, - NonRepudiation = 1 << 1, - KeyEncipherment = 1 << 2, - DataEncipherment = 1 << 3, - KeyAgreement = 1 << 4, - KeyCertSign = 1 << 5, - CRLSign = 1 << 6, - EncipherOnly = 1 << 7, - DecipherOnly = 1 << 8, - } -} - -/// KeyUsage as defined in [RFC 5280 Section 4.2.1.3] and as identified by the [`PKIX_CE_KEY_USAGE`](constant.PKIX_CE_KEY_USAGE.html) OID. -/// -/// [RFC 5280 Section 4.2.1.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 -pub type KeyUsage<'a> = FlagSet; - -/// Certificate policies extension as defined in [RFC 5280 Section 4.2.1.4] and as identified by the [`PKIX_CE_CERTIFICATE_POLICIES`](constant.PKIX_CE_CERTIFICATE_POLICIES.html) OID. -/// -/// ```text -///CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation -/// ``` -/// -/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 -pub type CertificatePolicies<'a> = Vec>; - -/// PolicyInformation as defined in [RFC 5280 Section 4.2.1.4] in support of the Certificate Policies extension. -/// -/// ```text -/// PolicyInformation ::= SEQUENCE { -/// policyIdentifier CertPolicyId, -/// policyQualifiers SEQUENCE SIZE (1..MAX) OF -/// PolicyQualifierInfo OPTIONAL } -/// -/// CertPolicyId ::= OBJECT IDENTIFIER -/// -/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -pub struct PolicyInformation<'a> { - /// policyIdentifier CertPolicyId, - pub policy_identifier: ObjectIdentifier, - - /// policyQualifiers SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo OPTIONAL - pub policy_qualifiers: Option>>, -} - -/// PolicyQualifierInfo as defined in [RFC 5280 Section 4.2.1.4] in support of the Certificate Policies extension. -/// -/// ```text -/// PolicyQualifierInfo ::= SEQUENCE { -/// policyQualifierId PolicyQualifierId, -/// qualifier ANY DEFINED BY policyQualifierId } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -pub struct PolicyQualifierInfo<'a> { - /// policyQualifierId PolicyQualifierId, - pub policy_qualifier_id: ObjectIdentifier, - - /// qualifier ANY DEFINED BY policyQualifierId - pub qualifier: Option>, -} - -/// PrivateKeyUsagePeriod as defined in [RFC 3280 Section 4.2.1.4]. -/// -/// This extension is by the [`PKIX_CE_PRIVATE_KEY_USAGE_PERIOD`](constant.PKIX_CE_PRIVATE_KEY_USAGE_PERIOD.html) OID. -/// -/// RFC 5280 states "use of this ISO standard extension is neither deprecated nor recommended for use in the Internet PKI." -/// -/// ```text -/// PrivateKeyUsagePeriod ::= SEQUENCE { -/// notBefore [0] GeneralizedTime OPTIONAL, -/// notAfter [1] GeneralizedTime OPTIONAL -/// -- either notBefore or notAfter MUST be present -/// } -/// ``` -/// -/// [RFC 3280 Section 4.2.1.12]: https://datatracker.ietf.org/doc/html/rfc3280#section-4.2.1.4 -#[derive(Clone, Debug, PartialEq, Eq, Sequence)] -#[allow(missing_docs)] -pub struct PrivateKeyUsagePeriod { - #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")] - pub not_before: Option, - - #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] - pub not_after: Option, -} - -/// NoticeReference as defined in [RFC 5280 Section 4.2.1.4] in support of the Certificate Policies extension. -/// -/// ```text -/// NoticeReference ::= SEQUENCE { -/// organization DisplayText, -/// noticeNumbers SEQUENCE OF INTEGER } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -pub struct NoticeReference<'a> { - /// organization DisplayText, - pub organization: DisplayText<'a>, - - /// noticeNumbers SEQUENCE OF INTEGER - pub notice_numbers: Option>>, -} - -/// UserNotice as defined in [RFC 5280 Section 4.2.1.4] in support of the Certificate Policies extension. -/// -/// ```text -/// UserNotice ::= SEQUENCE { -/// noticeRef NoticeReference OPTIONAL, -/// explicitText DisplayText OPTIONAL } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -pub struct UserNotice<'a> { - /// noticeRef NoticeReference OPTIONAL, - pub notice_ref: Option, - - /// explicitText DisplayText OPTIONAL } - pub explicit_text: Option>, -} - -/// Policy mappings extension as defined in [RFC 5280 Section 4.2.1.5] and as identified by the [`PKIX_CE_POLICY_MAPPINGS`](constant.PKIX_CE_POLICY_MAPPINGS.html) OID. -/// -/// ```text -/// PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { -/// ``` -/// -/// [RFC 5280 Section 4.2.1.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.5 -pub type PolicyMappings<'a> = Vec; - -/// PolicyMapping represents the inner portion of the PolicyMapping definition in [RFC 5280 Section 4.2.1.5]. -/// -/// ```text -/// PolicyMapping ::= SEQUENCE { -/// issuerDomainPolicy CertPolicyId, -/// subjectDomainPolicy CertPolicyId } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.5 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -pub struct PolicyMapping { - /// issuerDomainPolicy CertPolicyId, - pub issuer_domain_policy: ObjectIdentifier, - - /// subjectDomainPolicy CertPolicyId } - pub subject_domain_policy: ObjectIdentifier, -} - -/// Name constraints extension as defined in [RFC 5280 Section 4.2.1.10] and as identified by the [`PKIX_CE_NAME_CONSTRAINTS`](constant.PKIX_CE_NAME_CONSTRAINTS.html) OID. -/// -/// ```text -/// NameConstraints ::= SEQUENCE { -/// permittedSubtrees [0] GeneralSubtrees OPTIONAL, -/// excludedSubtrees [1] GeneralSubtrees OPTIONAL } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -pub struct NameConstraints<'a> { - /// permittedSubtrees [0] GeneralSubtrees OPTIONAL, - #[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")] - pub permitted_subtrees: Option>, - - /// excludedSubtrees [1] GeneralSubtrees OPTIONAL } - #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] - pub excluded_subtrees: Option>, -} - -/// GeneralSubtrees as defined in [RFC 5280 Section 4.2.1.10] in support of the Name Constraints extension. -/// -/// ```text -/// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree -/// ``` -/// -/// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 -pub type GeneralSubtrees<'a> = Vec>; - -/// GeneralSubtree as defined in [RFC 5280 Section 4.2.1.10]. -/// -/// ```text -/// GeneralSubtree ::= SEQUENCE { -/// base GeneralName, -/// minimum [0] BaseDistance DEFAULT 0, -/// maximum [1] BaseDistance OPTIONAL -/// } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -#[allow(missing_docs)] -pub struct GeneralSubtree<'a> { - pub base: GeneralName<'a>, - - #[asn1( - context_specific = "0", - tag_mode = "IMPLICIT", - default = "Default::default" - )] - pub minimum: u32, - - #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] - pub maximum: Option, -} - -/// Policy constraints extension as defined in [RFC 5280 Section 4.2.1.11]. -/// -/// This extension is identified by the [`PKIX_CE_POLICY_CONSTRAINTS`](constant.PKIX_CE_POLICY_CONSTRAINTS.html) OID. -/// -/// ```text -/// PolicyConstraints ::= SEQUENCE { -/// requireExplicitPolicy [0] SkipCerts OPTIONAL, -/// inhibitPolicyMapping [1] SkipCerts OPTIONAL -/// } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.11]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.11 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -#[allow(missing_docs)] -pub struct PolicyConstraints { - #[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")] - pub require_explicit_policy: Option, - - #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] - pub inhibit_policy_mapping: Option, -} - -/// Inhibit any policy extension as defined in [RFC 5280 Section 4.2.1.14] and as identified by the [`PKIX_CE_INHIBIT_ANY_POLICY`](constant.PKIX_CE_INHIBIT_ANY_POLICY.html) OID. -/// -/// ```text -/// InhibitAnyPolicy ::= SkipCerts -/// ``` -/// -/// [RFC 5280 Section 4.2.1.14]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.14 -pub type InhibitAnyPolicy = u32; - -/// Authority information access extension as defined in [RFC 5280 Section 4.2.2.1] and as identified by the [`PKIX_PE_AUTHORITYINFOACCESS`](constant.PKIX_PE_AUTHORITYINFOACCESS.html) OID. -/// -/// ```text -/// AuthorityInfoAccessSyntax ::= -/// SEQUENCE SIZE (1..MAX) OF AccessDescription -/// ``` -/// -/// [RFC 5280 Section 4.2.2.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1 -pub type AuthorityInfoAccessSyntax<'a> = Vec>; - -/// AccessDescription as defined in [RFC 5280 Section 4.2.2.1]. -/// -/// ```text -/// AccessDescription ::= SEQUENCE { -/// accessMethod OBJECT IDENTIFIER, -/// accessLocation GeneralName -/// } -/// ``` -/// -/// [RFC 5280 Section 4.2.2.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -#[allow(missing_docs)] -pub struct AccessDescription<'a> { - pub access_method: ObjectIdentifier, - - pub access_location: GeneralName<'a>, -} - -/// Subject information access extension as defined in [RFC 5280 Section 4.2.2.2] and as identified by the [`PKIX_PE_SUBJECTINFOACCESS`](constant.PKIX_PE_SUBJECTINFOACCESS.html) OID. -/// -/// ```text -/// SubjectInfoAccessSyntax ::= -/// SEQUENCE SIZE (1..MAX) OF AccessDescription -/// ``` -/// -/// [RFC 5280 Section 4.2.2.2]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.2 -pub type SubjectInfoAccessSyntax<'a> = Vec>; - -/// CRL number extension as defined in [RFC 5280 Section 5.2.3] and as identified by the [`PKIX_CE_CRLNUMBER`](constant.PKIX_CE_CRLNUMBER.html) OID. -/// -/// ```text -/// CRLNumber ::= INTEGER (0..MAX) -/// ``` -/// -/// [RFC 5280 Section 5.2.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.3 -pub type CRLNumber<'a> = UIntBytes<'a>; - -/// Delta CRL indicator extension as defined in [RFC 5280 Section 5.2.4] and as identified by the [`PKIX_CE_DELTACRLINDICATOR`](constant.PKIX_CE_DELTACRLINDICATOR.html) OID. -/// -/// ```text -/// BaseCRLNumber ::= CRLNumber -/// ``` -/// -/// [RFC 5280 Section 5.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.4 -pub type BaseCRLNumber<'a> = CRLNumber<'a>; - -/// Reason code extension as defined in [RFC 5280 Section 5.3.1] and as identified by the [`PKIX_CE_CRLREASONS`](constant.PKIX_CE_CRLREASONS.html) OID. -/// -/// ```text -/// CRLReason ::= ENUMERATED { -/// unspecified (0), -/// keyCompromise (1), -/// cACompromise (2), -/// affiliationChanged (3), -/// superseded (4), -/// cessationOfOperation (5), -/// certificateHold (6), -/// removeFromCRL (8), -/// privilegeWithdrawn (9), -/// aACompromise (10) } -/// ``` -/// -/// [RFC 5280 Section 5.3.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.3.1 -#[derive(Enumerated, Copy, Clone, Debug, Eq, PartialEq)] -#[repr(u32)] -pub enum CRLReason { - /// unspecified (0), - Unspecified = 0, - /// keyCompromise (1), - KeyCompromise = 1, - /// cACompromise (2), - CaCompromise = 2, - /// affiliationChanged (3), - AffiliationChanged = 3, - /// superseded (4), - Superseded = 4, - /// cessationOfOperation (5), - CessationOfOperation = 5, - /// certificateHold (6), - CertificateHold = 6, - /// removeFromCRL (8), - RemoveFromCRL = 8, - /// privilegeWithdrawn (9), - PrivilegeWithdrawn = 9, - /// aACompromise (10) - AaCompromise = 10, -} - -/// AuthorityKeyIdentifier as defined in [RFC 5280 Section 4.2.1.1]. -/// -/// This extension is identified by the [`PKIX_CE_AUTHORITY_KEY_IDENTIFIER`](constant.PKIX_CE_AUTHORITY_KEY_IDENTIFIER.html) OID. -/// -/// ```text -/// AuthorityKeyIdentifier ::= SEQUENCE { -/// keyIdentifier [0] KeyIdentifier OPTIONAL, -/// authorityCertIssuer [1] GeneralNames OPTIONAL, -/// authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL -/// } -/// -/// KeyIdentifier ::= OCTET STRING -/// ``` -/// -/// [RFC 5280 Section 4.2.1.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.1 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -#[allow(missing_docs)] -pub struct AuthorityKeyIdentifier<'a> { - #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")] - pub key_identifier: Option>, - - #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] - pub authority_cert_issuer: Option>, - - #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] - pub authority_cert_serial_number: Option>, -} - -flags! { - /// Reason flags as defined in [RFC 5280 Section 4.2.1.13]. - /// - /// ```text - /// ReasonFlags ::= BIT STRING { - /// unused (0), - /// keyCompromise (1), - /// cACompromise (2), - /// affiliationChanged (3), - /// superseded (4), - /// cessationOfOperation (5), - /// certificateHold (6), - /// privilegeWithdrawn (7), - /// aACompromise (8) } - /// ``` - /// - /// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 - #[allow(missing_docs)] - pub enum Reasons: u16 { - Unused = 1 << 0, - KeyCompromise = 1 << 1, - CaCompromise = 1 << 2, - AffiliationChanged = 1 << 3, - Superseded = 1 << 4, - CessationOfOperation = 1 << 5, - CertificateHold = 1 << 6, - PrivilegeWithdrawn = 1 << 7, - AaCompromise = 1 << 8, - } -} - -/// `ReasonFlags` as defined in [RFC 5280 Section 4.2.1.13] in support of the CRL distribution points extension. -/// -/// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 -pub type ReasonFlags = FlagSet; - -/// CRL distribution points extension as defined in [RFC 5280 Section 4.2.1.13] and as identified by the [`PKIX_CE_CRL_DISTRIBUTION_POINTS`](constant.PKIX_CE_CRL_DISTRIBUTION_POINTS.html) OID. -/// -/// ```text -/// CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint -/// ``` -/// -/// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 -pub type CRLDistributionPoints<'a> = Vec>; - -/// DistributionPoint as defined in [RFC 5280 Section 4.2.1.13]. -/// -/// ```text -/// DistributionPoint ::= SEQUENCE { -/// distributionPoint [0] DistributionPointName OPTIONAL, -/// reasons [1] ReasonFlags OPTIONAL, -/// cRLIssuer [2] GeneralNames OPTIONAL -/// } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 -#[derive(Clone, Debug, PartialEq, Eq, Sequence)] -#[allow(missing_docs)] -pub struct DistributionPoint<'a> { - #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")] - pub distribution_point: Option>, - - #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] - pub reasons: Option, - - #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] - pub crl_issuer: Option>, -} - -/// DistributionPointName as defined in [RFC 5280 Section 4.2.1.13]. -/// -/// ```text -/// DistributionPointName ::= CHOICE { -/// fullName [0] GeneralNames, -/// nameRelativeToCRLIssuer [1] RelativeDistinguishedName -/// } -/// ``` -/// -/// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 -#[derive(Clone, Debug, Eq, PartialEq, Choice)] -#[allow(missing_docs)] -pub enum DistributionPointName<'a> { - #[asn1(context_specific = "0", tag_mode = "IMPLICIT", constructed = "true")] - FullName(GeneralNames<'a>), - - #[asn1(context_specific = "1", tag_mode = "IMPLICIT", constructed = "true")] - NameRelativeToCRLIssuer(RelativeDistinguishedName<'a>), -} - -/// Freshest CRL extension as defined in [RFC 5280 Section 5.2.6] and as identified by the [`PKIX_CE_FRESHEST_CRL`](constant.PKIX_CE_FRESHEST_CRL.html) OID. -/// -/// ```text -/// FreshestCRL ::= CRLDistributionPoints -/// ``` -/// -/// [RFC 5280 Section 5.2.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.6 -pub type FreshestCRL<'a> = CRLDistributionPoints<'a>; - -/// IssuingDistributionPoint as defined in [RFC 5280 Section 5.2.5]. -/// -/// This extension is identified by the [`PKIX_PE_SUBJECTINFOACCESS`](constant.PKIX_PE_SUBJECTINFOACCESS.html) OID. -/// -/// ```text -/// IssuingDistributionPoint ::= SEQUENCE { -/// distributionPoint [0] DistributionPointName OPTIONAL, -/// onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, -/// onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, -/// onlySomeReasons [3] ReasonFlags OPTIONAL, -/// indirectCRL [4] BOOLEAN DEFAULT FALSE, -/// onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE -/// -- at most one of onlyContainsUserCerts, onlyContainsCACerts, -/// -- and onlyContainsAttributeCerts may be set to TRUE. -/// } -/// ``` -/// -/// [RFC 5280 Section 5.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] -#[allow(missing_docs)] -pub struct IssuingDistributionPoint<'a> { - #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")] - pub distribution_point: Option>, - - #[asn1( - context_specific = "1", - tag_mode = "IMPLICIT", - default = "Default::default" - )] - pub only_contains_user_certs: bool, - - #[asn1( - context_specific = "2", - tag_mode = "IMPLICIT", - default = "Default::default" - )] - pub only_contains_ca_certs: bool, - - #[asn1(context_specific = "3", tag_mode = "IMPLICIT", optional = "true")] - pub only_some_reasons: Option, - - #[asn1( - context_specific = "4", - tag_mode = "IMPLICIT", - default = "Default::default" - )] - pub indirect_crl: bool, - - #[asn1( - context_specific = "5", - tag_mode = "IMPLICIT", - default = "Default::default" - )] - pub only_contains_attribute_certs: bool, -} - -/// The PIV NACI extension is defined in [FIPS 201-2 Appendix B] and is identified by the [`PIV_NACI_INDICATOR`](constant.PIV_NACI_INDICATOR.html) OID. -/// -/// ```text -/// NACI-indicator ::= BOOLEAN -/// ``` -/// -/// [FIPS 201-2 Appendix B]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.201-2.pdf -pub type PivNaciIndicator = bool; diff --git a/x509/src/pkix_oids.rs b/x509/src/pkix_oids.rs deleted file mode 100644 index 14b7d0a4d..000000000 --- a/x509/src/pkix_oids.rs +++ /dev/null @@ -1,190 +0,0 @@ -//! Object identifier values from PKIX1Implicit and PKIX1Explicit ASN.1 modules -use crate::ObjectIdentifier; - -/// OID for CPS qualifier: 1.3.6.1.5.5.7.2.1 -pub const PKIX_QT_CPS: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.2.1"); - -/// OID for user notice qualifier: 1.3.6.1.5.5.7.2.2 -pub const PKIX_QT_UNOTICE: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.2.2"); - -/// OID for OCSP access descriptor: 1.3.6.1.5.5.7.48.1: 1.3.6.1.5.5.7.48.1 -pub const PKIX_AD_OCSP: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.1"); - -/// OID for caIssuers access descriptor: 1.3.6.1.5.5.7.48.2 -pub const PKIX_AD_CA_ISSUERS: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.2"); - -/// OID for timeStamping access descriptor: 1.3.6.1.5.5.7.48.3 -pub const PKIX_AD_TIME_STAMPING: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.3"); - -/// OID for caRepository access descriptor: 1.3.6.1.5.5.7.48.5 -pub const PKIX_AD_CA_REPOSITORY: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.5"); - -/// OID for Name attribute: 2.5.4.41 -pub const PKIX_AT_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.41"); - -/// OID for Surname attribute: 2.5.4.4 -pub const PKIX_AT_SURNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.4"); - -/// OID for givenName attribute: 2.5.4.42 -pub const PKIX_AT_GIVENNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.42"); - -/// OID for Initials attribute: 2.5.4.43 -pub const PKIX_AT_INITIALS: ObjectIdentifier = ObjectIdentifier::new("2.5.4.43"); - -/// OID for generationQualifier attribute: 2.5.4.44 -pub const PKIX_AT_GENERATION_QUALIFIER: ObjectIdentifier = ObjectIdentifier::new("2.5.4.44"); - -/// OID for commonName attribute: 2.5.4.3 -pub const PKIX_AT_COMMON_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.3"); - -/// OID for localityName attribute: 2.5.4.7 -pub const PKIX_AT_LOCALITY_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.7"); - -/// OID for stateOrProvinceName attribute: 2.5.4.8 -pub const PKIX_AT_STATEORPROVINCENAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.8"); - -/// OID for street attribute: 2.5.4.9 -pub const PKIX_AT_STREET: ObjectIdentifier = ObjectIdentifier::new("2.5.4.9"); - -/// OID for organizationName attribute: 2.5.4.10 -pub const PKIX_AT_ORGANIZATIONNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.10"); - -/// OID for organizationalUnitName attribute: 2.5.4.11 -pub const PKIX_AT_ORGANIZATIONALUNITNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.11"); - -/// OID for title attribute: 2.5.4.12 -pub const PKIX_AT_TITLE: ObjectIdentifier = ObjectIdentifier::new("2.5.4.12"); - -/// OID for dnQualifier attribute: 2.5.4.46 -pub const PKIX_AT_DNQUALIFIER: ObjectIdentifier = ObjectIdentifier::new("2.5.4.46"); - -/// OID for countryName attribute: 2.5.4.6 -pub const PKIX_AT_COUNTRYNAME: ObjectIdentifier = ObjectIdentifier::new("2.5.4.6"); - -/// OID for serialNumber attribute: 2.5.4.5 -pub const PKIX_AT_SERIALNUMBER: ObjectIdentifier = ObjectIdentifier::new("2.5.4.5"); - -/// OID for pseudonym attribute: 2.5.4.65 -pub const PKIX_AT_PSEUDONYM: ObjectIdentifier = ObjectIdentifier::new("2.5.4.65"); - -/// OID for domainComponent attribute: 0.9.2342.19200300.100.1.25 -pub const PKIX_DOMAINCOMPONENT: ObjectIdentifier = - ObjectIdentifier::new("0.9.2342.19200300.100.1.25"); - -/// OID for emailAddress attribute: 1.2.840.113549.1.9.1 -pub const PKIX_EMAILADDRESS: ObjectIdentifier = ObjectIdentifier::new("1.2.840.113549.1.9.1"); - -/// OID for anyPolicy extension: 2.5.29.32.0 -pub const PKIX_CE_ANYPOLICY: ObjectIdentifier = ObjectIdentifier::new("2.5.29.32.0"); - -/// OID for extKeyUsage extension: 2.5.29.37. See [`ExtendedKeyUsage`](type.ExtendedKeyUsage.html). -pub const PKIX_CE_EXTKEYUSAGE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.37"); - -/// OID for anyExtendedKeyUsage EKU value: 2.5.29.37.0 -pub const PKIX_CE_ANYEXTENDEDKEYUSAGE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.37.0"); - -/// OID for serverAuth key purpose: 1.3.6.1.5.5.7.3.31 -pub const PKIX_KP_SERVERAUTH: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.31"); - -/// OID for clientAuth key purpose: 1.3.6.1.5.5.7.3.32 -pub const PKIX_KP_CLIENTAUTH: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.32"); - -/// OID for codeSigning key purpose: 1.3.6.1.5.5.7.3.33 -pub const PKIX_KP_CODESIGNING: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.33"); - -/// OID for emailProtection key purpose: 1.3.6.1.5.5.7.3.34 -pub const PKIX_KP_EMAILPROTECTION: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.34"); - -/// OID for timeStamping key purpose: 1.3.6.1.5.5.7.3.38 -pub const PKIX_KP_TIMESTAMPING: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.38"); - -/// OID for OCSPSigning key purpose: 1.3.6.1.5.5.7.3.39 -pub const PKIX_KP_OCSPSIGNING: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.3.39"); - -/// OID for authorityInfoAccess extension: 1.3.6.1.5.5.7.1.1 -pub const PKIX_PE_AUTHORITYINFOACCESS: ObjectIdentifier = - ObjectIdentifier::new("1.3.6.1.5.5.7.1.1"); - -/// OID for subjectInfoAccess extension: 1.3.6.1.5.5.7.1.11 -pub const PKIX_PE_SUBJECTINFOACCESS: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.1.11"); - -/// OID for subjectDirectoryAttributes extension: 2.5.29.9. See [`SubjectDirectoryAttributes`](type.SubjectDirectoryAttributes.html). -pub const PKIX_CE_SUBJECT_DIRECTORY_ATTRIBUTES: ObjectIdentifier = - ObjectIdentifier::new("2.5.29.9"); - -/// OID for subjectKeyIdentifier extension: 2.5.29.14. See [`SubjectKeyIdentifier`](type.SubjectKeyIdentifier.html). -pub const PKIX_CE_SUBJECT_KEY_IDENTIFIER: ObjectIdentifier = ObjectIdentifier::new("2.5.29.14"); - -/// OID for keyUsage extension: 2.5.29.15. See [`KeyUsage`](type.KeyUsage.html). -pub const PKIX_CE_KEY_USAGE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.15"); - -/// OID for privateKeyUsagePeriod extension: 2.5.29.16. See [`PrivateKeyUsagePeriod`](struct.PrivateKeyUsagePeriod.html). -pub const PKIX_CE_PRIVATE_KEY_USAGE_PERIOD: ObjectIdentifier = ObjectIdentifier::new("2.5.29.16"); - -/// OID for subjectAltName extension: 2.5.29.17. See [`SubjectAltName`](type.SubjectAltName.html). -pub const PKIX_CE_SUBJECT_ALT_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.29.17"); - -/// OID for issuerAltName extension: 2.5.29.18. See [`IssuerAltName`](type.IssuerAltName.html). -pub const PKIX_CE_ISSUER_ALT_NAME: ObjectIdentifier = ObjectIdentifier::new("2.5.29.18"); - -/// OID for basicConstraints extension: 2.5.29.19. See [`BasicConstraints`](struct.BasicConstraints.html). -pub const PKIX_CE_BASIC_CONSTRAINTS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.19"); - -/// OID for cRLNumber extension: 2.5.29.20 -pub const PKIX_CE_CRLNUMBER: ObjectIdentifier = ObjectIdentifier::new("2.5.29.20"); - -/// OID for cRLReasons extension: 2.5.29.21 -pub const PKIX_CE_CRLREASONS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.21"); - -/// OID for issuingDistributionPoint extension: 2.5.29.28 -pub const PKIX_CE_ISSUINGDISTRIBUTIONPOINT: ObjectIdentifier = ObjectIdentifier::new("2.5.29.28"); - -/// OID for deltaCRLIndicator extension: 2.5.29.27 -pub const PKIX_CE_DELTACRLINDICATOR: ObjectIdentifier = ObjectIdentifier::new("2.5.29.27"); - -/// OID for certificateIssuer extension: 2.5.29.29 -pub const PKIX_CE_CERTIFICATEISSUER: ObjectIdentifier = ObjectIdentifier::new("2.5.29.29"); - -/// OID for holdInstructionCode extension: 2.5.29.23 -pub const PKIX_CE_HOLDINSTRUCTIONCODE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.23"); - -/// OID forholdinstruction-callissuer attribute: 2.2.840.10040.2.2 -pub const PKIX_HI_HOLDINSTRUCTION_CALLISSUER: ObjectIdentifier = - ObjectIdentifier::new("2.2.840.10040.2.2"); - -/// OID for holdinstruction-reject attribute: 2.2.840.10040.23 -pub const PKIX_HI_HOLDINSTRUCTION_REJECT: ObjectIdentifier = - ObjectIdentifier::new("2.2.840.10040.23"); - -/// OID for invalidityDate extension: 2.5.29.24 -pub const PKIX_CE_INVALIDITYDATE: ObjectIdentifier = ObjectIdentifier::new("2.5.29.24"); - -/// OID for nameConstraints extension: 2.5.29.30. See [`CertificatePolicies`](type.CertificatePolicies.html). -pub const PKIX_CE_NAME_CONSTRAINTS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.30"); - -/// OID for cRLDistributionPoints extension: 2.5.29.31. See [`CertificatePolicies`](type.CertificatePolicies.html). -pub const PKIX_CE_CRL_DISTRIBUTION_POINTS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.31"); - -/// OID for certificatePolicies extension: 2.5.29.32. See [`CertificatePolicies`](type.CertificatePolicies.html). -pub const PKIX_CE_CERTIFICATE_POLICIES: ObjectIdentifier = ObjectIdentifier::new("2.5.29.32"); - -/// OID for policyMappings extension: 2.5.29.33. See [`PolicyMappings`](type.PolicyMappings.html). -pub const PKIX_CE_POLICY_MAPPINGS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.33"); - -/// OID for authorityKeyIdentifier extension: 2.5.29.35. See [`AuthorityKeyIdentifier`](type.AuthorityKeyIdentifier.html). -pub const PKIX_CE_AUTHORITY_KEY_IDENTIFIER: ObjectIdentifier = ObjectIdentifier::new("2.5.29.35"); - -/// OID for policyConstraints extension: 2.5.29.36. See [`PolicyConstraints`](struct.PolicyConstraints.html). -pub const PKIX_CE_POLICY_CONSTRAINTS: ObjectIdentifier = ObjectIdentifier::new("2.5.29.36"); - -/// OID for policyConstraints extension: 2.5.29.46. See [`PolicyConstraints`](type.FreshestCRL.html). -pub const PKIX_CE_FRESHEST_CRL: ObjectIdentifier = ObjectIdentifier::new("2.5.29.46"); - -/// OID for inhibitAnyPolicy extension: 2.5.29.54. See [`InhibitAnyPolicy`](type.InhibitAnyPolicy.html). -pub const PKIX_CE_INHIBIT_ANY_POLICY: ObjectIdentifier = ObjectIdentifier::new("2.5.29.54"); - -/// OID for ocspNoCheck extension: 1.3.6.1.5.5.7.48.1.5. See [`OcspNoCheck`](type.OcspNoCheck.html). -pub const PKIX_OCSP_NOCHECK: ObjectIdentifier = ObjectIdentifier::new("1.3.6.1.5.5.7.48.1.5"); - -/// OID for PIV NACI extension: 2.16.840.1.101.3.6.9.1. See [`PivNaciIndicator`](type.PivNaciIndicator.html). -pub const PIV_NACI_INDICATOR: ObjectIdentifier = ObjectIdentifier::new("2.16.840.1.101.3.6.9.1"); diff --git a/x509/tests/certificate.rs b/x509/tests/certificate.rs index 0e5bbdaeb..440f98ec8 100644 --- a/x509/tests/certificate.rs +++ b/x509/tests/certificate.rs @@ -1,7 +1,8 @@ //! Certificate tests -use der::asn1::{BitString, UIntBytes}; +use der::asn1::{BitString, ObjectIdentifier, UIntBytes}; use der::{Decodable, Decoder, Encodable, Tag, Tagged}; use hex_literal::hex; +use spki::AlgorithmIdentifier; use x509::Certificate; use x509::*; diff --git a/x509/tests/pkix_extensions.rs b/x509/tests/pkix_extensions.rs index 978eaf355..ac826befe 100644 --- a/x509/tests/pkix_extensions.rs +++ b/x509/tests/pkix_extensions.rs @@ -3,9 +3,12 @@ use der::asn1::{BitString, UIntBytes}; use der::{Decodable, Encodable, ErrorKind, Length, Tag, Tagged}; use hex_literal::hex; use x501::name::Name; -use x509::KeyUsage; -use x509::*; -use x509::{BasicConstraints, Certificate, CertificatePolicies, GeneralName, SubjectKeyIdentifier}; +use x509::ext::other::{OcspNoCheck, PivNaciIndicator}; +use x509::ext::pkix::crl::dp::{DistributionPoint, ReasonFlags, Reasons}; +use x509::ext::pkix::name::{DistributionPointName, GeneralName, GeneralNames}; +use x509::ext::pkix::{oids::*, *}; +use x509::ext::Extensions; +use x509::{Certificate, Version}; fn spin_over_exts<'a>(exts: Extensions<'a>) { let i = exts.iter(); @@ -67,7 +70,7 @@ fn spin_over_exts<'a>(exts: Extensions<'a>) { let reencoded = nc.to_vec().unwrap(); assert_eq!(ext.extn_value, reencoded); } else if "2.5.29.31" == ext.extn_id.to_string() { - let crldps_result = CRLDistributionPoints::from_der(ext.extn_value); + let crldps_result = CrlDistributionPoints::from_der(ext.extn_value); assert!(crldps_result.is_ok()); let crldps = crldps_result.unwrap(); @@ -109,7 +112,7 @@ fn spin_over_exts<'a>(exts: Extensions<'a>) { let reencoded = eku.to_vec().unwrap(); assert_eq!(ext.extn_value, reencoded); } else if "2.5.29.46" == ext.extn_id.to_string() { - let fc_result = FreshestCRL::from_der(ext.extn_value); + let fc_result = FreshestCrl::from_der(ext.extn_value); assert!(fc_result.is_ok()); let fc = fc_result.unwrap(); @@ -237,7 +240,6 @@ fn decode_general_name() { } // OtherName - let bytes = hex!("A021060A2B060104018237140203A0130C1155706E5F323134393530313330406D696C"); match GeneralName::from_der(&bytes).unwrap() { GeneralName::OtherName(other_name) => { @@ -262,7 +264,7 @@ fn decode_cert() { let mut counter = 0; for ext in i { if 0 == counter { - assert_eq!(ext.extn_id.to_string(), PKIX_CE_KEY_USAGE.to_string()); + assert_eq!(ext.extn_id.to_string(), CE_KEY_USAGE.to_string()); assert_eq!(ext.critical, true); let ku = KeyUsage::from_der(ext.extn_value).unwrap(); @@ -271,10 +273,7 @@ fn decode_cert() { let reencoded = ku.to_vec().unwrap(); assert_eq!(ext.extn_value, reencoded); } else if 1 == counter { - assert_eq!( - ext.extn_id.to_string(), - PKIX_CE_BASIC_CONSTRAINTS.to_string() - ); + assert_eq!(ext.extn_id.to_string(), CE_BASIC_CONSTRAINTS.to_string()); assert_eq!(ext.critical, true); let bc = BasicConstraints::from_der(ext.extn_value).unwrap(); assert_eq!(true, bc.ca); @@ -283,7 +282,7 @@ fn decode_cert() { let reencoded = bc.to_vec().unwrap(); assert_eq!(ext.extn_value, reencoded); } else if 2 == counter { - assert_eq!(ext.extn_id.to_string(), PKIX_CE_POLICY_MAPPINGS.to_string()); + assert_eq!(ext.extn_id.to_string(), CE_POLICY_MAPPINGS.to_string()); assert_eq!(ext.critical, false); let pm = PolicyMappings::from_der(ext.extn_value).unwrap(); assert_eq!(19, pm.len()); @@ -348,10 +347,7 @@ fn decode_cert() { counter_pm += 1; } } else if 3 == counter { - assert_eq!( - ext.extn_id.to_string(), - PKIX_CE_CERTIFICATE_POLICIES.to_string() - ); + assert_eq!(ext.extn_id.to_string(), CE_CERTIFICATE_POLICIES.to_string()); assert_eq!(ext.critical, false); let cps = CertificatePolicies::from_der(ext.extn_value).unwrap(); assert_eq!(19, cps.len()); @@ -411,7 +407,7 @@ fn decode_cert() { } else if 4 == counter { assert_eq!( ext.extn_id.to_string(), - PKIX_CE_SUBJECT_KEY_IDENTIFIER.to_string() + CE_SUBJECT_KEY_IDENTIFIER.to_string() ); assert_eq!(ext.critical, false); let skid = SubjectKeyIdentifier::from_der(ext.extn_value).unwrap(); @@ -426,10 +422,10 @@ fn decode_cert() { } else if 5 == counter { assert_eq!( ext.extn_id.to_string(), - PKIX_CE_CRL_DISTRIBUTION_POINTS.to_string() + CE_CRL_DISTRIBUTION_POINTS.to_string() ); assert_eq!(ext.critical, false); - let crl_dps = CRLDistributionPoints::from_der(ext.extn_value).unwrap(); + let crl_dps = CrlDistributionPoints::from_der(ext.extn_value).unwrap(); assert_eq!(2, crl_dps.len()); let reencoded = crl_dps.to_vec().unwrap(); @@ -482,10 +478,7 @@ fn decode_cert() { crldp_counter += 1; } } else if 6 == counter { - assert_eq!( - ext.extn_id.to_string(), - PKIX_PE_SUBJECTINFOACCESS.to_string() - ); + assert_eq!(ext.extn_id.to_string(), PE_SUBJECTINFOACCESS.to_string()); assert_eq!(ext.critical, false); let sias = SubjectInfoAccessSyntax::from_der(ext.extn_value).unwrap(); assert_eq!(1, sias.len()); @@ -509,10 +502,7 @@ fn decode_cert() { } } } else if 7 == counter { - assert_eq!( - ext.extn_id.to_string(), - PKIX_PE_AUTHORITYINFOACCESS.to_string() - ); + assert_eq!(ext.extn_id.to_string(), PE_AUTHORITYINFOACCESS.to_string()); assert_eq!(ext.critical, false); let aias = AuthorityInfoAccessSyntax::from_der(ext.extn_value).unwrap(); assert_eq!(2, aias.len()); @@ -555,10 +545,7 @@ fn decode_cert() { aia_counter += 1; } } else if 8 == counter { - assert_eq!( - ext.extn_id.to_string(), - PKIX_CE_INHIBIT_ANY_POLICY.to_string() - ); + assert_eq!(ext.extn_id.to_string(), CE_INHIBIT_ANY_POLICY.to_string()); assert_eq!(ext.critical, false); let iap = InhibitAnyPolicy::from_der(ext.extn_value).unwrap(); assert_eq!(0, iap); @@ -568,7 +555,7 @@ fn decode_cert() { } else if 9 == counter { assert_eq!( ext.extn_id.to_string(), - PKIX_CE_AUTHORITY_KEY_IDENTIFIER.to_string() + CE_AUTHORITY_KEY_IDENTIFIER.to_string() ); assert_eq!(ext.critical, false); let akid = AuthorityKeyIdentifier::from_der(ext.extn_value).unwrap(); @@ -710,7 +697,7 @@ fn decode_cert() { if 0 == counter { assert_eq!( ext.extn_id.to_string(), - PKIX_CE_AUTHORITY_KEY_IDENTIFIER.to_string() + CE_AUTHORITY_KEY_IDENTIFIER.to_string() ); assert_eq!(ext.critical, false); let akid = AuthorityKeyIdentifier::from_der(ext.extn_value).unwrap(); @@ -721,7 +708,7 @@ fn decode_cert() { } else if 1 == counter { assert_eq!( ext.extn_id.to_string(), - PKIX_CE_SUBJECT_KEY_IDENTIFIER.to_string() + CE_SUBJECT_KEY_IDENTIFIER.to_string() ); assert_eq!(ext.critical, false); let skid = SubjectKeyIdentifier::from_der(ext.extn_value).unwrap(); @@ -730,15 +717,12 @@ fn decode_cert() { &hex!("580184241BBC2B52944A3DA510721451F5AF3AC9")[..] ); } else if 2 == counter { - assert_eq!(ext.extn_id.to_string(), PKIX_CE_KEY_USAGE.to_string()); + assert_eq!(ext.extn_id.to_string(), CE_KEY_USAGE.to_string()); assert_eq!(ext.critical, true); let ku = KeyUsage::from_der(ext.extn_value).unwrap(); assert_eq!(KeyUsages::KeyCertSign | KeyUsages::CRLSign, ku); } else if 3 == counter { - assert_eq!( - ext.extn_id.to_string(), - PKIX_CE_CERTIFICATE_POLICIES.to_string() - ); + assert_eq!(ext.extn_id.to_string(), CE_CERTIFICATE_POLICIES.to_string()); assert_eq!(ext.critical, false); let r = CertificatePolicies::from_der(ext.extn_value); let cp = r.unwrap(); @@ -747,10 +731,7 @@ fn decode_cert() { assert_eq!(p.policy_identifier.to_string(), "2.16.840.1.101.3.2.1.48.1"); } } else if 4 == counter { - assert_eq!( - ext.extn_id.to_string(), - PKIX_CE_BASIC_CONSTRAINTS.to_string() - ); + assert_eq!(ext.extn_id.to_string(), CE_BASIC_CONSTRAINTS.to_string()); assert_eq!(ext.critical, true); let bc = BasicConstraints::from_der(ext.extn_value).unwrap(); assert_eq!(bc.ca, true); diff --git a/x509/tests/trust_anchor_format.rs b/x509/tests/trust_anchor_format.rs index 5f46980c8..7f873e353 100644 --- a/x509/tests/trust_anchor_format.rs +++ b/x509/tests/trust_anchor_format.rs @@ -1,8 +1,7 @@ -use der::{Decodable, Decoder}; +use der::{Decodable, Decoder, Encodable}; use hex_literal::hex; -use x509::der::Encodable; -use x509::trust_anchor_format::{CertPolicies, TrustAnchorChoice}; -use x509::*; +use x509::anchor::{CertPolicies, TrustAnchorChoice}; +use x509::ext::pkix::name::GeneralName; #[test] fn decode_ta1() {