diff --git a/x509-cert/src/builder.rs b/x509-cert/src/builder.rs index 32bdbfd04..29037748d 100644 --- a/x509-cert/src/builder.rs +++ b/x509-cert/src/builder.rs @@ -219,10 +219,12 @@ where /// Extensions need to implement [`AsExtension`], examples may be found in /// in [`AsExtension` documentation](../ext/trait.AsExtension.html#examples) or /// [the implementors](../ext/trait.AsExtension.html#implementors). - pub fn add_extension(&mut self, extension: &E) -> Result<()> { + pub fn add_extension( + &mut self, + extension: &E, + ) -> core::result::Result<(), E::Error> { let ext = extension.to_extension(&self.tbs.subject, &self.extensions)?; self.extensions.push(ext); - Ok(()) } } diff --git a/x509-cert/src/ext.rs b/x509-cert/src/ext.rs index 71232fabc..511659304 100644 --- a/x509-cert/src/ext.rs +++ b/x509-cert/src/ext.rs @@ -44,6 +44,26 @@ pub struct Extension { /// [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9 pub type Extensions = alloc::vec::Vec; +/// Trait for types that define their default criticality as an extension. +/// +/// This is used for most der::Encode types that are used as extensions. +pub trait Criticality { + /// Should the extension be marked critical + /// + /// This affects the behavior of a validator when using the generated certificate. + /// See [RFC 5280 Section 4.2]: + /// ```text + /// A certificate-using system MUST reject the certificate if it encounters + /// a critical extension it does not recognize or a critical extension + /// that contains information that it cannot process. A non-critical + /// extension MAY be ignored if it is not recognized, but MUST be + /// processed if it is recognized. + /// ``` + /// + /// [RFC 5280 Section 4.2]: https://www.rfc-editor.org/rfc/rfc5280#section-4.2 + fn criticality(&self, subject: &crate::name::Name, extensions: &[Extension]) -> bool; +} + /// Trait to be implemented by extensions to allow them to be formatted as x509 v3 extensions by /// builder. /// @@ -65,40 +85,50 @@ pub type Extensions = alloc::vec::Vec; /// const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.32473.1"); /// } /// -/// impl ext::AsExtension for CaptainAge { -/// fn critical(&self, _subject: &name::Name, _extensions: &[ext::Extension]) -> bool { +/// impl ext::Criticality for CaptainAge { +/// fn criticality(&self, _subject: &name::Name, _extensions: &[ext::Extension]) -> bool { /// false /// } /// } /// ``` -pub trait AsExtension: AssociatedOid + der::Encode { - /// Should the extension be marked critical - /// - /// This affects the behavior of a validator when using the generated certificate. - /// See [RFC 5280 Section 4.2]: - /// ```text - /// A certificate-using system MUST reject the certificate if it encounters - /// a critical extension it does not recognize or a critical extension - /// that contains information that it cannot process. A non-critical - /// extension MAY be ignored if it is not recognized, but MUST be - /// processed if it is recognized. - /// ``` - /// - /// [RFC 5280 Section 4.2]: https://www.rfc-editor.org/rfc/rfc5280#section-4.2 - fn critical(&self, subject: &crate::name::Name, extensions: &[Extension]) -> bool; +pub trait AsExtension { + /// The error type returned when encoding the extension. + type Error; /// Returns the Extension with the content encoded. fn to_extension( &self, subject: &crate::name::Name, extensions: &[Extension], - ) -> Result { - let content = OctetString::new(::to_der(self)?)?; + ) -> Result; +} + +impl AsExtension for T { + type Error = der::Error; + fn to_extension( + &self, + subject: &crate::name::Name, + extensions: &[Extension], + ) -> Result { Ok(Extension { extn_id: ::OID, - critical: self.critical(subject, extensions), - extn_value: content, + critical: self.criticality(subject, extensions), + extn_value: OctetString::new(self.to_der()?)?, }) } } + +impl AsExtension for (bool, T) { + type Error = T::Error; + + fn to_extension( + &self, + subject: &crate::name::Name, + extensions: &[Extension], + ) -> Result { + let mut extension = self.1.to_extension(subject, extensions)?; + extension.critical = self.0; + Ok(extension) + } +} diff --git a/x509-cert/src/ext/pkix.rs b/x509-cert/src/ext/pkix.rs index 911bc4664..d280015c0 100644 --- a/x509-cert/src/ext/pkix.rs +++ b/x509-cert/src/ext/pkix.rs @@ -78,8 +78,8 @@ impl AssociatedOid for SubjectAltName { impl_newtype!(SubjectAltName, name::GeneralNames); -impl crate::ext::AsExtension for SubjectAltName { - fn critical(&self, subject: &crate::name::Name, _extensions: &[super::Extension]) -> bool { +impl crate::ext::Criticality for SubjectAltName { + fn criticality(&self, subject: &crate::name::Name, _extensions: &[super::Extension]) -> bool { // https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6 // Further, if the only subject identity included in the certificate is // an alternative name form (e.g., an electronic mail address), then the diff --git a/x509-cert/src/ext/pkix/constraints/basic.rs b/x509-cert/src/ext/pkix/constraints/basic.rs index 0f3b4b4bf..ea135e1d9 100644 --- a/x509-cert/src/ext/pkix/constraints/basic.rs +++ b/x509-cert/src/ext/pkix/constraints/basic.rs @@ -23,8 +23,8 @@ impl AssociatedOid for BasicConstraints { const OID: ObjectIdentifier = ID_CE_BASIC_CONSTRAINTS; } -impl crate::ext::AsExtension for BasicConstraints { - fn critical( +impl crate::ext::Criticality for BasicConstraints { + fn criticality( &self, _subject: &crate::name::Name, _extensions: &[crate::ext::Extension], diff --git a/x509-cert/src/macros.rs b/x509-cert/src/macros.rs index c9f5153d8..d397db79f 100644 --- a/x509-cert/src/macros.rs +++ b/x509-cert/src/macros.rs @@ -81,14 +81,14 @@ macro_rules! impl_newtype { }; } -/// Implements the AsExtension traits for every defined Extension paylooad +/// Implements the Criticality trait for every defined Extension paylooad macro_rules! impl_extension { ($newtype:ty) => { impl_extension!($newtype, critical = false); }; ($newtype:ty, critical = $critical:expr) => { - impl crate::ext::AsExtension for $newtype { - fn critical( + impl crate::ext::Criticality for $newtype { + fn criticality( &self, _subject: &crate::name::Name, _extensions: &[crate::ext::Extension], diff --git a/x509-cert/src/request/builder.rs b/x509-cert/src/request/builder.rs index 07926824b..db26fda57 100644 --- a/x509-cert/src/request/builder.rs +++ b/x509-cert/src/request/builder.rs @@ -80,7 +80,10 @@ impl RequestBuilder { /// Extensions need to implement [`AsExtension`], examples may be found in /// in [`AsExtension` documentation](../ext/trait.AsExtension.html#examples) or /// [the implementors](../ext/trait.AsExtension.html#implementors). - pub fn add_extension(&mut self, extension: &E) -> Result<()> { + pub fn add_extension( + &mut self, + extension: &E, + ) -> core::result::Result<(), E::Error> { let ext = extension.to_extension(&self.info.subject, &self.extension_req.0)?; self.extension_req.0.push(ext); diff --git a/x509-ocsp/src/basic.rs b/x509-ocsp/src/basic.rs index 62d39a413..e4dfb72b2 100644 --- a/x509-ocsp/src/basic.rs +++ b/x509-ocsp/src/basic.rs @@ -171,7 +171,7 @@ mod builder { /// extension encoding fails. /// /// [RFC 6960 Section 4.4]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.4 - pub fn with_extension(mut self, ext: impl AsExtension) -> Result { + pub fn with_extension(mut self, ext: E) -> Result { let ext = ext.to_extension(&Name::default(), &[])?; match self.single_extensions { Some(ref mut exts) => exts.push(ext), diff --git a/x509-ocsp/src/builder/request.rs b/x509-ocsp/src/builder/request.rs index 607306eb3..1b9bc54f7 100644 --- a/x509-ocsp/src/builder/request.rs +++ b/x509-ocsp/src/builder/request.rs @@ -96,7 +96,7 @@ impl OcspRequestBuilder { /// extension encoding fails. /// /// [RFC 6960 Section 4.4]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.4 - pub fn with_extension(mut self, ext: impl AsExtension) -> Result { + pub fn with_extension(mut self, ext: E) -> Result { let ext = ext.to_extension(&Name::default(), &[])?; match self.tbs.request_extensions { Some(ref mut exts) => exts.push(ext), diff --git a/x509-ocsp/src/builder/response.rs b/x509-ocsp/src/builder/response.rs index b355fd642..06061ac74 100644 --- a/x509-ocsp/src/builder/response.rs +++ b/x509-ocsp/src/builder/response.rs @@ -101,7 +101,7 @@ impl OcspResponseBuilder { /// extension encoding fails. /// /// [RFC 6960 Section 4.4]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.4 - pub fn with_extension(mut self, ext: impl AsExtension) -> Result { + pub fn with_extension(mut self, ext: E) -> Result { let ext = ext.to_extension(&Name::default(), &[])?; match self.response_extensions { Some(ref mut exts) => exts.push(ext), diff --git a/x509-ocsp/src/ext.rs b/x509-ocsp/src/ext.rs index c80c6da8a..457a8f4a5 100644 --- a/x509-ocsp/src/ext.rs +++ b/x509-ocsp/src/ext.rs @@ -15,7 +15,7 @@ use der::{ }; use spki::AlgorithmIdentifierOwned; use x509_cert::{ - ext::{AsExtension, Extension, pkix::AuthorityInfoAccessSyntax}, + ext::{Criticality, Extension, pkix::AuthorityInfoAccessSyntax}, impl_newtype, name::Name, }; @@ -26,8 +26,8 @@ use rand_core::CryptoRng; // x509-cert's is not exported macro_rules! impl_extension { ($newtype:ty, critical = $critical:expr) => { - impl AsExtension for $newtype { - fn critical(&self, _subject: &Name, _extensions: &[Extension]) -> bool { + impl Criticality for $newtype { + fn criticality(&self, _subject: &Name, _extensions: &[Extension]) -> bool { $critical } } diff --git a/x509-ocsp/src/request.rs b/x509-ocsp/src/request.rs index db0a62324..53b67f432 100644 --- a/x509-ocsp/src/request.rs +++ b/x509-ocsp/src/request.rs @@ -172,7 +172,7 @@ mod builder { /// extension encoding fails. /// /// [RFC 6960 Section 4.4]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.4 - pub fn with_extension(mut self, ext: impl AsExtension) -> Result { + pub fn with_extension(mut self, ext: E) -> Result { let ext = ext.to_extension(&Name::default(), &[])?; match self.single_request_extensions { Some(ref mut exts) => exts.push(ext),