@@ -10,7 +10,7 @@ use crate::{
1010 Certificate , CertificateParams , Error , Issuer , PublicKeyData , SignatureAlgorithm , SigningKey ,
1111} ;
1212#[ cfg( feature = "x509-parser" ) ]
13- use crate :: { DistinguishedName , SanType } ;
13+ use crate :: { CustomExtension , DistinguishedName , SanType } ;
1414
1515/// A public key, extracted from a CSR
1616#[ derive( Debug , PartialEq , Eq , Hash ) ]
@@ -65,6 +65,18 @@ impl From<CertificateSigningRequest> for CertificateSigningRequestDer<'static> {
6565 }
6666}
6767
68+ /// A unsupported extension.
69+ #[ derive( Debug , Clone , Eq , PartialEq ) ]
70+ #[ cfg( feature = "x509-parser" ) ]
71+ pub struct UnsupportedExtension < ' a > {
72+ /// The Object ID of the extension.
73+ pub oid : Vec < u64 > ,
74+ /// The unparsed value.
75+ pub value : & ' a [ u8 ] ,
76+ /// Whether the extension is critical.
77+ pub critical : bool ,
78+ }
79+
6880/// Parameters for a certificate signing request
6981#[ derive( Debug ) ]
7082pub struct CertificateSigningRequestParams {
@@ -84,6 +96,23 @@ impl CertificateSigningRequestParams {
8496 Self :: from_der ( & csr. contents ( ) . into ( ) )
8597 }
8698
99+ /// Parse a certificate signing request from the ASCII PEM format
100+ /// using the provided validator function to handle unknown extension
101+ /// types.
102+ ///
103+ /// The validator function must return an error if the attribute OID or value
104+ /// is incorrect.
105+ ///
106+ /// See [`from_der`](Self::from_der) for more details.
107+ #[ cfg( all( feature = "pem" , feature = "x509-parser" ) ) ]
108+ pub fn from_pem_custom_validator < F > ( pem_str : & str , valid_fn : F ) -> Result < Self , Error >
109+ where
110+ F : FnMut ( & UnsupportedExtension < ' _ > ) -> Result < ( ) , Error > ,
111+ {
112+ let csr = pem:: parse ( pem_str) . or ( Err ( Error :: CouldNotParseCertificationRequest ) ) ?;
113+ Self :: from_der_custom_validator ( & csr. contents ( ) . into ( ) , valid_fn)
114+ }
115+
87116 /// Parse a certificate signing request from DER-encoded bytes
88117 ///
89118 /// Currently, this only supports the `Subject Alternative Name` extension.
@@ -96,6 +125,24 @@ impl CertificateSigningRequestParams {
96125 /// [`rustls_pemfile::csr()`]: https://docs.rs/rustls-pemfile/latest/rustls_pemfile/fn.csr.html
97126 #[ cfg( feature = "x509-parser" ) ]
98127 pub fn from_der ( csr : & CertificateSigningRequestDer < ' _ > ) -> Result < Self , Error > {
128+ Self :: from_der_custom_validator ( csr, |_| Ok ( ( ) ) )
129+ }
130+
131+ /// Parse a certificate signing request from DER-encoded bytes using the provided
132+ /// validator function to handle unknown extension types.
133+ ///
134+ /// The validator function must return an error if the attribute OID or value
135+ /// is incorrect.
136+ ///
137+ /// See [`from_der`](Self::from_der) for more details.
138+ #[ cfg( feature = "x509-parser" ) ]
139+ pub fn from_der_custom_validator < F > (
140+ csr : & CertificateSigningRequestDer < ' _ > ,
141+ mut valid_fn : F ,
142+ ) -> Result < Self , Error >
143+ where
144+ F : FnMut ( & UnsupportedExtension < ' _ > ) -> Result < ( ) , Error > ,
145+ {
99146 use crate :: KeyUsagePurpose ;
100147 use x509_parser:: prelude:: FromDer ;
101148
@@ -171,7 +218,25 @@ impl CertificateSigningRequestParams {
171218 return Err ( Error :: UnsupportedExtension ) ;
172219 }
173220 } ,
174- _ => return Err ( Error :: UnsupportedExtension ) ,
221+ x509_parser:: extensions:: ParsedExtension :: UnsupportedExtension ( val) => {
222+ let oid: Vec < u64 > = match val. oid . iter ( ) {
223+ Some ( iter) => iter. collect ( ) ,
224+ None => return Err ( Error :: UnsupportedExtension ) ,
225+ } ;
226+ let ext = UnsupportedExtension {
227+ oid,
228+ value : val. value ,
229+ critical : val. critical ,
230+ } ;
231+ valid_fn ( & ext) ?;
232+ let mut ext =
233+ CustomExtension :: from_oid_content ( & ext. oid , val. value . to_vec ( ) ) ;
234+ ext. set_criticality ( val. critical ) ;
235+ params. custom_extensions . push ( ext) ;
236+ } ,
237+ _ => {
238+ return Err ( Error :: UnsupportedExtension ) ;
239+ } ,
175240 }
176241 }
177242 }
0 commit comments