diff options
Diffstat (limited to 'src/ext/pkix')
-rw-r--r-- | src/ext/pkix/access.rs | 18 | ||||
-rw-r--r-- | src/ext/pkix/authkeyid.rs | 24 | ||||
-rw-r--r-- | src/ext/pkix/certpolicy.rs | 43 | ||||
-rw-r--r-- | src/ext/pkix/constraints/basic.rs | 25 | ||||
-rw-r--r-- | src/ext/pkix/constraints/name.rs | 16 | ||||
-rw-r--r-- | src/ext/pkix/constraints/policy.rs | 2 | ||||
-rw-r--r-- | src/ext/pkix/crl.rs | 36 | ||||
-rw-r--r-- | src/ext/pkix/crl/dp.rs | 16 | ||||
-rw-r--r-- | src/ext/pkix/keyusage.rs | 119 | ||||
-rw-r--r-- | src/ext/pkix/name/dirstr.rs | 11 | ||||
-rw-r--r-- | src/ext/pkix/name/dp.rs | 6 | ||||
-rw-r--r-- | src/ext/pkix/name/ediparty.rs | 6 | ||||
-rw-r--r-- | src/ext/pkix/name/general.rs | 66 | ||||
-rw-r--r-- | src/ext/pkix/name/other.rs | 12 | ||||
-rw-r--r-- | src/ext/pkix/policymap.rs | 1 |
15 files changed, 309 insertions, 92 deletions
diff --git a/src/ext/pkix/access.rs b/src/ext/pkix/access.rs index 0390235..4d2d9db 100644 --- a/src/ext/pkix/access.rs +++ b/src/ext/pkix/access.rs @@ -16,13 +16,14 @@ use der::{asn1::ObjectIdentifier, Sequence, ValueOrd}; /// /// [RFC 5280 Section 4.2.2.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1 #[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct AuthorityInfoAccessSyntax<'a>(pub Vec<AccessDescription<'a>>); +pub struct AuthorityInfoAccessSyntax(pub Vec<AccessDescription>); -impl<'a> AssociatedOid for AuthorityInfoAccessSyntax<'a> { +impl AssociatedOid for AuthorityInfoAccessSyntax { const OID: ObjectIdentifier = ID_PE_AUTHORITY_INFO_ACCESS; } -impl_newtype!(AuthorityInfoAccessSyntax<'a>, Vec<AccessDescription<'a>>); +impl_newtype!(AuthorityInfoAccessSyntax, Vec<AccessDescription>); +impl_extension!(AuthorityInfoAccessSyntax, critical = false); /// SubjectInfoAccessSyntax as defined in [RFC 5280 Section 4.2.2.2]. /// @@ -32,13 +33,14 @@ impl_newtype!(AuthorityInfoAccessSyntax<'a>, Vec<AccessDescription<'a>>); /// /// [RFC 5280 Section 4.2.2.2]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.2 #[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct SubjectInfoAccessSyntax<'a>(pub Vec<AccessDescription<'a>>); +pub struct SubjectInfoAccessSyntax(pub Vec<AccessDescription>); -impl<'a> AssociatedOid for SubjectInfoAccessSyntax<'a> { +impl AssociatedOid for SubjectInfoAccessSyntax { const OID: ObjectIdentifier = ID_PE_SUBJECT_INFO_ACCESS; } -impl_newtype!(SubjectInfoAccessSyntax<'a>, Vec<AccessDescription<'a>>); +impl_newtype!(SubjectInfoAccessSyntax, Vec<AccessDescription>); +impl_extension!(SubjectInfoAccessSyntax, critical = false); /// AccessDescription as defined in [RFC 5280 Section 4.2.2.1]. /// @@ -52,7 +54,7 @@ impl_newtype!(SubjectInfoAccessSyntax<'a>, Vec<AccessDescription<'a>>); /// [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, ValueOrd)] #[allow(missing_docs)] -pub struct AccessDescription<'a> { +pub struct AccessDescription { pub access_method: ObjectIdentifier, - pub access_location: GeneralName<'a>, + pub access_location: GeneralName, } diff --git a/src/ext/pkix/authkeyid.rs b/src/ext/pkix/authkeyid.rs index e7644f5..60b61e5 100644 --- a/src/ext/pkix/authkeyid.rs +++ b/src/ext/pkix/authkeyid.rs @@ -1,8 +1,9 @@ use super::name::GeneralNames; +use crate::serial_number::SerialNumber; use const_oid::db::rfc5280::ID_CE_AUTHORITY_KEY_IDENTIFIER; use const_oid::{AssociatedOid, ObjectIdentifier}; -use der::asn1::{OctetStringRef, UIntRef}; +use der::asn1::OctetString; use der::Sequence; /// AuthorityKeyIdentifier as defined in [RFC 5280 Section 4.2.1.1]. @@ -18,19 +19,28 @@ use der::Sequence; /// ``` /// /// [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)] +#[derive(Clone, Debug, Eq, PartialEq, Sequence, Default)] #[allow(missing_docs)] -pub struct AuthorityKeyIdentifier<'a> { +pub struct AuthorityKeyIdentifier { #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")] - pub key_identifier: Option<OctetStringRef<'a>>, + pub key_identifier: Option<OctetString>, #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] - pub authority_cert_issuer: Option<GeneralNames<'a>>, + pub authority_cert_issuer: Option<GeneralNames>, #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] - pub authority_cert_serial_number: Option<UIntRef<'a>>, + pub authority_cert_serial_number: Option<SerialNumber>, } -impl<'a> AssociatedOid for AuthorityKeyIdentifier<'a> { +impl AssociatedOid for AuthorityKeyIdentifier { const OID: ObjectIdentifier = ID_CE_AUTHORITY_KEY_IDENTIFIER; } + +impl_extension!(AuthorityKeyIdentifier, critical = false); +impl_key_identifier!( + AuthorityKeyIdentifier, + (|result: &[u8]| Ok(Self { + key_identifier: Some(OctetString::new(result)?), + ..Default::default() + })) +); diff --git a/src/ext/pkix/certpolicy.rs b/src/ext/pkix/certpolicy.rs index bb2211f..85820c1 100644 --- a/src/ext/pkix/certpolicy.rs +++ b/src/ext/pkix/certpolicy.rs @@ -1,11 +1,11 @@ //! PKIX Certificate Policies extension -use alloc::vec::Vec; +use alloc::{string::String, vec::Vec}; use const_oid::db::rfc5912::ID_CE_CERTIFICATE_POLICIES; use const_oid::AssociatedOid; -use der::asn1::{GeneralizedTime, Ia5StringRef, ObjectIdentifier, UIntRef, Utf8StringRef}; -use der::{AnyRef, Choice, Sequence, ValueOrd}; +use der::asn1::{GeneralizedTime, Ia5String, ObjectIdentifier, Uint}; +use der::{Any, Choice, Sequence, ValueOrd}; /// CertificatePolicies as defined in [RFC 5280 Section 4.2.1.4]. /// @@ -14,14 +14,19 @@ use der::{AnyRef, Choice, Sequence, ValueOrd}; /// ``` /// /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 +// If this extension is +// critical, the path validation software MUST be able to interpret this +// extension (including the optional qualifier), or MUST reject the +// certificate. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct CertificatePolicies<'a>(pub Vec<PolicyInformation<'a>>); +pub struct CertificatePolicies(pub Vec<PolicyInformation>); -impl<'a> AssociatedOid for CertificatePolicies<'a> { +impl AssociatedOid for CertificatePolicies { const OID: ObjectIdentifier = ID_CE_CERTIFICATE_POLICIES; } -impl_newtype!(CertificatePolicies<'a>, Vec<PolicyInformation<'a>>); +impl_newtype!(CertificatePolicies, Vec<PolicyInformation>); +impl_extension!(CertificatePolicies); /// PolicyInformation as defined in [RFC 5280 Section 4.2.1.4]. /// @@ -37,9 +42,9 @@ impl_newtype!(CertificatePolicies<'a>, Vec<PolicyInformation<'a>>); /// [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, ValueOrd)] #[allow(missing_docs)] -pub struct PolicyInformation<'a> { +pub struct PolicyInformation { pub policy_identifier: ObjectIdentifier, - pub policy_qualifiers: Option<Vec<PolicyQualifierInfo<'a>>>, + pub policy_qualifiers: Option<Vec<PolicyQualifierInfo>>, } /// PolicyQualifierInfo as defined in [RFC 5280 Section 4.2.1.4]. @@ -54,9 +59,9 @@ pub struct PolicyInformation<'a> { /// [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, ValueOrd)] #[allow(missing_docs)] -pub struct PolicyQualifierInfo<'a> { +pub struct PolicyQualifierInfo { pub policy_qualifier_id: ObjectIdentifier, - pub qualifier: Option<AnyRef<'a>>, + pub qualifier: Option<Any>, } /// CpsUri as defined in [RFC 5280 Section 4.2.1.4]. @@ -66,7 +71,7 @@ pub struct PolicyQualifierInfo<'a> { /// ``` /// /// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4 -pub type CpsUri<'a> = Ia5StringRef<'a>; +pub type CpsUri = Ia5String; /// UserNotice as defined in [RFC 5280 Section 4.2.1.4]. /// @@ -80,9 +85,9 @@ pub type CpsUri<'a> = Ia5StringRef<'a>; /// [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 struct UserNotice { pub notice_ref: Option<GeneralizedTime>, - pub explicit_text: Option<DisplayText<'a>>, + pub explicit_text: Option<DisplayText>, } /// NoticeReference as defined in [RFC 5280 Section 4.2.1.4]. @@ -96,9 +101,9 @@ pub struct UserNotice<'a> { /// [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<Vec<UIntRef<'a>>>, +pub struct NoticeReference { + pub organization: DisplayText, + pub notice_numbers: Option<Vec<Uint>>, } /// DisplayText as defined in [RFC 5280 Section 4.2.1.4]. @@ -117,10 +122,10 @@ pub struct NoticeReference<'a> { /// [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> { +pub enum DisplayText { #[asn1(type = "IA5String")] - Ia5String(Ia5StringRef<'a>), + Ia5String(Ia5String), #[asn1(type = "UTF8String")] - Utf8String(Utf8StringRef<'a>), + Utf8String(String), } diff --git a/src/ext/pkix/constraints/basic.rs b/src/ext/pkix/constraints/basic.rs index 5972cc8..c50d8e8 100644 --- a/src/ext/pkix/constraints/basic.rs +++ b/src/ext/pkix/constraints/basic.rs @@ -22,3 +22,28 @@ pub struct BasicConstraints { impl AssociatedOid for BasicConstraints { const OID: ObjectIdentifier = ID_CE_BASIC_CONSTRAINTS; } + +impl crate::ext::AsExtension for BasicConstraints { + fn critical( + &self, + _subject: &crate::name::Name, + _extensions: &[crate::ext::Extension], + ) -> bool { + // https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.9 + // Conforming CAs MUST include this extension in all CA certificates + // that contain public keys used to validate digital signatures on + // certificates and MUST mark the extension as critical in such + // certificates. This extension MAY appear as a critical or non- + // critical extension in CA certificates that contain public keys used + // exclusively for purposes other than validating digital signatures on + // certificates. Such CA certificates include ones that contain public + // keys used exclusively for validating digital signatures on CRLs and + // ones that contain key management public keys used with certificate + // enrollment protocols. This extension MAY appear as a critical or + // non-critical extension in end entity certificates. + + // NOTE(baloo): from the spec, it doesn't appear to hurt if we force the extension + // to be critical. + true + } +} diff --git a/src/ext/pkix/constraints/name.rs b/src/ext/pkix/constraints/name.rs index 658f1e2..c05d005 100644 --- a/src/ext/pkix/constraints/name.rs +++ b/src/ext/pkix/constraints/name.rs @@ -19,18 +19,20 @@ use super::super::name::GeneralName; /// [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> { +pub struct NameConstraints { #[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")] - pub permitted_subtrees: Option<GeneralSubtrees<'a>>, + pub permitted_subtrees: Option<GeneralSubtrees>, #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] - pub excluded_subtrees: Option<GeneralSubtrees<'a>>, + pub excluded_subtrees: Option<GeneralSubtrees>, } -impl<'a> AssociatedOid for NameConstraints<'a> { +impl AssociatedOid for NameConstraints { const OID: ObjectIdentifier = ID_CE_NAME_CONSTRAINTS; } +impl_extension!(NameConstraints, critical = true); + /// GeneralSubtrees as defined in [RFC 5280 Section 4.2.1.10]. /// /// ```text @@ -38,7 +40,7 @@ impl<'a> AssociatedOid for NameConstraints<'a> { /// ``` /// /// [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<'a>>; +pub type GeneralSubtrees = Vec<GeneralSubtree>; /// GeneralSubtree as defined in [RFC 5280 Section 4.2.1.10]. /// @@ -53,8 +55,8 @@ pub type GeneralSubtrees<'a> = Vec<GeneralSubtree<'a>>; /// [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>, +pub struct GeneralSubtree { + pub base: GeneralName, #[asn1( context_specific = "0", diff --git a/src/ext/pkix/constraints/policy.rs b/src/ext/pkix/constraints/policy.rs index dcb1a8c..c409737 100644 --- a/src/ext/pkix/constraints/policy.rs +++ b/src/ext/pkix/constraints/policy.rs @@ -24,3 +24,5 @@ pub struct PolicyConstraints { impl AssociatedOid for PolicyConstraints { const OID: ObjectIdentifier = ID_CE_POLICY_CONSTRAINTS; } + +impl_extension!(PolicyConstraints, critical = true); diff --git a/src/ext/pkix/crl.rs b/src/ext/pkix/crl.rs index d65b837..f3e9397 100644 --- a/src/ext/pkix/crl.rs +++ b/src/ext/pkix/crl.rs @@ -11,7 +11,7 @@ pub use dp::IssuingDistributionPoint; use alloc::vec::Vec; -use der::{asn1::UIntRef, Enumerated}; +use der::{asn1::Uint, Enumerated}; /// CrlNumber as defined in [RFC 5280 Section 5.2.3]. /// @@ -20,14 +20,15 @@ use der::{asn1::UIntRef, Enumerated}; /// ``` /// /// [RFC 5280 Section 5.2.3]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.3 -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct CrlNumber<'a>(pub UIntRef<'a>); +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CrlNumber(pub Uint); -impl<'a> AssociatedOid for CrlNumber<'a> { +impl AssociatedOid for CrlNumber { const OID: ObjectIdentifier = ID_CE_CRL_NUMBER; } -impl_newtype!(CrlNumber<'a>, UIntRef<'a>); +impl_newtype!(CrlNumber, Uint); +impl_extension!(CrlNumber, critical = false); /// BaseCRLNumber as defined in [RFC 5280 Section 5.2.4]. /// @@ -36,14 +37,15 @@ impl_newtype!(CrlNumber<'a>, UIntRef<'a>); /// ``` /// /// [RFC 5280 Section 5.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.4 -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct BaseCrlNumber<'a>(pub UIntRef<'a>); +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct BaseCrlNumber(pub Uint); -impl<'a> AssociatedOid for BaseCrlNumber<'a> { +impl AssociatedOid for BaseCrlNumber { const OID: ObjectIdentifier = ID_CE_DELTA_CRL_INDICATOR; } -impl_newtype!(BaseCrlNumber<'a>, UIntRef<'a>); +impl_newtype!(BaseCrlNumber, Uint); +impl_extension!(BaseCrlNumber, critical = true); /// CrlDistributionPoints as defined in [RFC 5280 Section 4.2.1.13]. /// @@ -53,13 +55,14 @@ impl_newtype!(BaseCrlNumber<'a>, UIntRef<'a>); /// /// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13 #[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct CrlDistributionPoints<'a>(pub Vec<dp::DistributionPoint<'a>>); +pub struct CrlDistributionPoints(pub Vec<dp::DistributionPoint>); -impl<'a> AssociatedOid for CrlDistributionPoints<'a> { +impl AssociatedOid for CrlDistributionPoints { const OID: ObjectIdentifier = ID_CE_CRL_DISTRIBUTION_POINTS; } -impl_newtype!(CrlDistributionPoints<'a>, Vec<dp::DistributionPoint<'a>>); +impl_newtype!(CrlDistributionPoints, Vec<dp::DistributionPoint>); +impl_extension!(CrlDistributionPoints, critical = false); /// FreshestCrl as defined in [RFC 5280 Section 5.2.6]. /// @@ -69,13 +72,14 @@ impl_newtype!(CrlDistributionPoints<'a>, Vec<dp::DistributionPoint<'a>>); /// /// [RFC 5280 Section 5.2.6]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.6 #[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct FreshestCrl<'a>(pub Vec<dp::DistributionPoint<'a>>); +pub struct FreshestCrl(pub Vec<dp::DistributionPoint>); -impl<'a> AssociatedOid for FreshestCrl<'a> { +impl AssociatedOid for FreshestCrl { const OID: ObjectIdentifier = ID_CE_FRESHEST_CRL; } -impl_newtype!(FreshestCrl<'a>, Vec<dp::DistributionPoint<'a>>); +impl_newtype!(FreshestCrl, Vec<dp::DistributionPoint>); +impl_extension!(FreshestCrl, critical = false); /// CRLReason as defined in [RFC 5280 Section 5.3.1]. /// @@ -114,3 +118,5 @@ pub enum CrlReason { impl AssociatedOid for CrlReason { const OID: ObjectIdentifier = ID_CE_CRL_REASONS; } + +impl_extension!(CrlReason, critical = false); diff --git a/src/ext/pkix/crl/dp.rs b/src/ext/pkix/crl/dp.rs index f7d1ab7..7acd2c9 100644 --- a/src/ext/pkix/crl/dp.rs +++ b/src/ext/pkix/crl/dp.rs @@ -1,8 +1,8 @@ //! PKIX distribution point types use const_oid::{db::rfc5280::ID_PE_SUBJECT_INFO_ACCESS, AssociatedOid, ObjectIdentifier}; +use der::flagset::{flags, FlagSet}; use der::{Sequence, ValueOrd}; -use flagset::{flags, FlagSet}; use crate::ext::pkix::name::{DistributionPointName, GeneralNames}; @@ -24,9 +24,9 @@ use crate::ext::pkix::name::{DistributionPointName, GeneralNames}; /// [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> { +pub struct IssuingDistributionPoint { #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")] - pub distribution_point: Option<DistributionPointName<'a>>, + pub distribution_point: Option<DistributionPointName>, #[asn1( context_specific = "1", @@ -60,10 +60,12 @@ pub struct IssuingDistributionPoint<'a> { pub only_contains_attribute_certs: bool, } -impl<'a> AssociatedOid for IssuingDistributionPoint<'a> { +impl AssociatedOid for IssuingDistributionPoint { const OID: ObjectIdentifier = ID_PE_SUBJECT_INFO_ACCESS; } +impl_extension!(IssuingDistributionPoint, critical = true); + /// DistributionPoint as defined in [RFC 5280 Section 4.2.1.13]. /// /// ```text @@ -76,15 +78,15 @@ impl<'a> AssociatedOid for IssuingDistributionPoint<'a> { /// [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, ValueOrd)] #[allow(missing_docs)] -pub struct DistributionPoint<'a> { +pub struct DistributionPoint { #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")] - pub distribution_point: Option<DistributionPointName<'a>>, + pub distribution_point: Option<DistributionPointName>, #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] pub reasons: Option<ReasonFlags>, #[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")] - pub crl_issuer: Option<GeneralNames<'a>>, + pub crl_issuer: Option<GeneralNames>, } /// ReasonFlags as defined in [RFC 5280 Section 4.2.1.13]. diff --git a/src/ext/pkix/keyusage.rs b/src/ext/pkix/keyusage.rs index cd051fe..833db69 100644 --- a/src/ext/pkix/keyusage.rs +++ b/src/ext/pkix/keyusage.rs @@ -1,12 +1,12 @@ use alloc::vec::Vec; use const_oid::db::rfc5280::{ - ID_CE_EXT_KEY_USAGE, ID_CE_KEY_USAGE, ID_CE_PRIVATE_KEY_USAGE_PERIOD, + ANY_EXTENDED_KEY_USAGE, ID_CE_EXT_KEY_USAGE, ID_CE_KEY_USAGE, ID_CE_PRIVATE_KEY_USAGE_PERIOD, }; use const_oid::AssociatedOid; use der::asn1::{GeneralizedTime, ObjectIdentifier}; +use der::flagset::{flags, FlagSet}; use der::Sequence; -use flagset::{flags, FlagSet}; flags! { /// Key usage flags as defined in [RFC 5280 Section 4.2.1.3]. @@ -52,6 +52,66 @@ impl AssociatedOid for KeyUsage { } impl_newtype!(KeyUsage, FlagSet<KeyUsages>); +impl_extension!(KeyUsage, critical = true); + +impl KeyUsage { + /// The subject public key is used for verifying digital signatures + pub fn digital_signature(&self) -> bool { + self.0.contains(KeyUsages::DigitalSignature) + } + + /// When the subject public key is used to verify digital signatures, + /// it is asserted as non-repudiation. + pub fn non_repudiation(&self) -> bool { + self.0.contains(KeyUsages::NonRepudiation) + } + + /// The subject public key is used for enciphering private or + /// secret keys, i.e., for key transport. + pub fn key_encipherment(&self) -> bool { + self.0.contains(KeyUsages::KeyEncipherment) + } + + /// The subject public key is used for directly enciphering + /// raw user data without the use of an intermediate symmetric cipher. + pub fn data_encipherment(&self) -> bool { + self.0.contains(KeyUsages::DataEncipherment) + } + + /// The subject public key is used for key agreement + pub fn key_agreement(&self) -> bool { + self.0.contains(KeyUsages::KeyAgreement) + } + + /// The subject public key is used for enciphering private or + /// secret keys, i.e., for key transport. + pub fn key_cert_sign(&self) -> bool { + self.0.contains(KeyUsages::KeyCertSign) + } + + /// The subject public key is used for verifying signatures + /// on certificate revocation lists (e.g., CRLs, delta CRLs, + /// or ARLs). + pub fn crl_sign(&self) -> bool { + self.0.contains(KeyUsages::CRLSign) + } + + /// The meaning of the `encipher_only` is undefined when `key_agreement` + /// returns false. When `encipher_only` returns true and + /// `key_agreement` also returns true, the subject public key may be + /// used only for enciphering data while performing key agreement. + pub fn encipher_only(&self) -> bool { + self.0.contains(KeyUsages::EncipherOnly) + } + + /// The meaning of the `decipher_only` is undefined when `key_agreement` + /// returns false. When `encipher_only` returns true and + /// `key_agreement` also returns true, the subject public key may be + /// used only for deciphering data while performing key agreement. + pub fn decipher_only(&self) -> bool { + self.0.contains(KeyUsages::DecipherOnly) + } +} /// ExtKeyUsageSyntax as defined in [RFC 5280 Section 4.2.1.12]. /// @@ -78,6 +138,30 @@ impl AssociatedOid for ExtendedKeyUsage { impl_newtype!(ExtendedKeyUsage, Vec<ObjectIdentifier>); +impl crate::ext::AsExtension for ExtendedKeyUsage { + fn critical( + &self, + _subject: &crate::name::Name, + _extensions: &[crate::ext::Extension], + ) -> bool { + // https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.12 + // This extension MAY, at the option of the certificate issuer, be + // either critical or non-critical. + // + // If a CA includes extended key usages to satisfy such applications, + // but does not wish to restrict usages of the key, the CA can include + // the special KeyPurposeId anyExtendedKeyUsage in addition to the + // particular key purposes required by the applications. Conforming CAs + // SHOULD NOT mark this extension as critical if the anyExtendedKeyUsage + // KeyPurposeId is present. Applications that require the presence of a + // particular purpose MAY reject certificates that include the + // anyExtendedKeyUsage OID but not the particular OID expected for the + // application. + + !self.0.iter().any(|el| *el == ANY_EXTENDED_KEY_USAGE) + } +} + /// PrivateKeyUsagePeriod as defined in [RFC 3280 Section 4.2.1.4]. /// /// RFC 5280 states "use of this ISO standard extension is neither deprecated nor recommended for use in the Internet PKI." @@ -103,3 +187,34 @@ pub struct PrivateKeyUsagePeriod { impl AssociatedOid for PrivateKeyUsagePeriod { const OID: ObjectIdentifier = ID_CE_PRIVATE_KEY_USAGE_PERIOD; } + +impl_extension!(PrivateKeyUsagePeriod, critical = false); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn digital_signature_contains_digital_signature() { + let key_usage = KeyUsage(KeyUsages::DigitalSignature.into()); + assert!(key_usage.digital_signature()); + } + + #[test] + fn all_contains_digital_signature() { + let key_usage = KeyUsage(FlagSet::full()); + assert!(key_usage.digital_signature()); + } + + #[test] + fn key_encipherment_not_contains_digital_signature() { + let key_usage = KeyUsage(KeyUsages::KeyEncipherment.into()); + assert!(!key_usage.digital_signature()); + } + + #[test] + fn empty_not_contains_digital_signature() { + let key_usage = KeyUsage(None.into()); + assert!(!key_usage.digital_signature()); + } +} diff --git a/src/ext/pkix/name/dirstr.rs b/src/ext/pkix/name/dirstr.rs index 2aaa732..a6a0117 100644 --- a/src/ext/pkix/name/dirstr.rs +++ b/src/ext/pkix/name/dirstr.rs @@ -1,4 +1,5 @@ -use der::asn1::{PrintableStringRef, TeletexStringRef, Utf8StringRef}; +use alloc::string::String; +use der::asn1::{PrintableString, TeletexString}; use der::{Choice, ValueOrd}; /// DirectoryString as defined in [RFC 5280 Section 4.2.1.4]. @@ -40,13 +41,13 @@ use der::{Choice, ValueOrd}; /// [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, ValueOrd)] #[allow(missing_docs)] -pub enum DirectoryString<'a> { +pub enum DirectoryString { #[asn1(type = "PrintableString")] - PrintableString(PrintableStringRef<'a>), + PrintableString(PrintableString), #[asn1(type = "TeletexString")] - TeletexString(TeletexStringRef<'a>), + TeletexString(TeletexString), #[asn1(type = "UTF8String")] - Utf8String(Utf8StringRef<'a>), + Utf8String(String), } diff --git a/src/ext/pkix/name/dp.rs b/src/ext/pkix/name/dp.rs index e895f88..0965564 100644 --- a/src/ext/pkix/name/dp.rs +++ b/src/ext/pkix/name/dp.rs @@ -15,10 +15,10 @@ use der::{Choice, ValueOrd}; /// [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, ValueOrd)] #[allow(missing_docs)] -pub enum DistributionPointName<'a> { +pub enum DistributionPointName { #[asn1(context_specific = "0", tag_mode = "IMPLICIT", constructed = "true")] - FullName(GeneralNames<'a>), + FullName(GeneralNames), #[asn1(context_specific = "1", tag_mode = "IMPLICIT", constructed = "true")] - NameRelativeToCRLIssuer(RelativeDistinguishedName<'a>), + NameRelativeToCRLIssuer(RelativeDistinguishedName), } diff --git a/src/ext/pkix/name/ediparty.rs b/src/ext/pkix/name/ediparty.rs index 94af09b..9d10040 100644 --- a/src/ext/pkix/name/ediparty.rs +++ b/src/ext/pkix/name/ediparty.rs @@ -27,10 +27,10 @@ use super::DirectoryString; /// [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, ValueOrd)] #[allow(missing_docs)] -pub struct EdiPartyName<'a> { +pub struct EdiPartyName { #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")] - pub name_assigner: Option<DirectoryString<'a>>, + pub name_assigner: Option<DirectoryString>, #[asn1(context_specific = "1", tag_mode = "EXPLICIT")] - pub party_name: DirectoryString<'a>, + pub party_name: DirectoryString, } diff --git a/src/ext/pkix/name/general.rs b/src/ext/pkix/name/general.rs index f6861d4..bd0fa7e 100644 --- a/src/ext/pkix/name/general.rs +++ b/src/ext/pkix/name/general.rs @@ -3,7 +3,7 @@ use super::{EdiPartyName, OtherName}; use crate::name::Name; -use der::asn1::{Ia5StringRef, ObjectIdentifier, OctetStringRef}; +use der::asn1::{Ia5String, ObjectIdentifier, OctetString}; use der::{Choice, ValueOrd}; /// GeneralNames as defined in [RFC 5280 Section 4.2.1.6]. @@ -13,7 +13,7 @@ use der::{Choice, ValueOrd}; /// ``` /// /// [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<'a>>; +pub type GeneralNames = alloc::vec::Vec<GeneralName>; /// GeneralName as defined in [RFC 5280 Section 4.2.1.6]. /// @@ -36,28 +36,74 @@ pub type GeneralNames<'a> = alloc::vec::Vec<GeneralName<'a>>; /// [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, ValueOrd)] #[allow(missing_docs)] -pub enum GeneralName<'a> { +pub enum GeneralName { #[asn1(context_specific = "0", tag_mode = "IMPLICIT", constructed = "true")] - OtherName(OtherName<'a>), + OtherName(OtherName), #[asn1(context_specific = "1", tag_mode = "IMPLICIT")] - Rfc822Name(Ia5StringRef<'a>), + Rfc822Name(Ia5String), #[asn1(context_specific = "2", tag_mode = "IMPLICIT")] - DnsName(Ia5StringRef<'a>), + DnsName(Ia5String), #[asn1(context_specific = "4", tag_mode = "EXPLICIT", constructed = "true")] - DirectoryName(Name<'a>), + DirectoryName(Name), #[asn1(context_specific = "5", tag_mode = "IMPLICIT", constructed = "true")] - EdiPartyName(EdiPartyName<'a>), + EdiPartyName(EdiPartyName), #[asn1(context_specific = "6", tag_mode = "IMPLICIT")] - UniformResourceIdentifier(Ia5StringRef<'a>), + UniformResourceIdentifier(Ia5String), #[asn1(context_specific = "7", tag_mode = "IMPLICIT")] - IpAddress(OctetStringRef<'a>), + IpAddress(OctetString), #[asn1(context_specific = "8", tag_mode = "IMPLICIT")] RegisteredId(ObjectIdentifier), } + +#[cfg(feature = "std")] +impl From<std::net::IpAddr> for GeneralName { + fn from(ip: std::net::IpAddr) -> Self { + // Safety: this is unfailable here, OctetString will issue an error if you go + // over 256MiB, here the buffer is at most 16 bytes (ipv6). The two `expect`s + // below are safe. + let buf = match ip { + std::net::IpAddr::V4(v) => { + let value = v.octets(); + OctetString::new(&value[..]) + .expect("OctetString is not expected to fail with a 4 bytes long buffer") + } + std::net::IpAddr::V6(v) => { + let value = v.octets(); + OctetString::new(&value[..]) + .expect("OctetString is not expected to fail with a 16 bytes long buffer") + } + }; + + GeneralName::IpAddress(buf) + } +} + +#[cfg(all(feature = "std", test))] +mod tests { + use super::*; + use der::Encode; + + #[test] + fn test_convert() { + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + + let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); + let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + + assert_eq!( + GeneralName::from(localhost_v4).to_der().unwrap(), + &[135, 4, 127, 0, 0, 1][..] + ); + assert_eq!( + GeneralName::from(localhost_v6).to_der().unwrap(), + &[135, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1][..] + ); + } +} diff --git a/src/ext/pkix/name/other.rs b/src/ext/pkix/name/other.rs index a33601c..26b93bc 100644 --- a/src/ext/pkix/name/other.rs +++ b/src/ext/pkix/name/other.rs @@ -1,4 +1,4 @@ -use der::{asn1::ObjectIdentifier, AnyRef, Sequence, ValueOrd}; +use der::{asn1::ObjectIdentifier, Any, Sequence, ValueOrd}; /// OtherName as defined in [RFC 5280 Section 4.2.1.6]. /// @@ -12,26 +12,26 @@ use der::{asn1::ObjectIdentifier, AnyRef, Sequence, ValueOrd}; /// [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, ValueOrd)] #[allow(missing_docs)] -pub struct OtherName<'a> { +pub struct OtherName { pub type_id: ObjectIdentifier, #[asn1(context_specific = "0", tag_mode = "EXPLICIT")] - pub value: AnyRef<'a>, + pub value: Any, } #[test] #[cfg(test)] fn test() { use alloc::string::ToString; - use der::{Decode, Encode}; + use der::{asn1::Utf8StringRef, Decode, Encode}; use hex_literal::hex; let input = hex!("3021060A2B060104018237140203A0130C1155706E5F323134393530313330406D696C"); let decoded = OtherName::from_der(&input).unwrap(); - let onval = decoded.value.utf8_string().unwrap(); + let onval = Utf8StringRef::try_from(&decoded.value).unwrap(); assert_eq!(onval.to_string(), "Upn_214950130@mil"); - let encoded = decoded.to_vec().unwrap(); + let encoded = decoded.to_der().unwrap(); assert_eq!(&input[..], &encoded); } diff --git a/src/ext/pkix/policymap.rs b/src/ext/pkix/policymap.rs index e6b55ba..1997f54 100644 --- a/src/ext/pkix/policymap.rs +++ b/src/ext/pkix/policymap.rs @@ -20,6 +20,7 @@ impl AssociatedOid for PolicyMappings { } impl_newtype!(PolicyMappings, Vec<PolicyMapping>); +impl_extension!(PolicyMappings, critical = true); /// PolicyMapping as defined in [RFC 5280 Section 4.2.1.5]. /// |