3
3
use crate :: { name:: Name , serial_number:: SerialNumber , time:: Validity } ;
4
4
use alloc:: vec:: Vec ;
5
5
use const_oid:: AssociatedOid ;
6
- use core:: cmp:: Ordering ;
6
+ use core:: { cmp:: Ordering , fmt :: Debug , marker :: PhantomData } ;
7
7
use der:: asn1:: BitString ;
8
- use der:: { Decode , Enumerated , Error , ErrorKind , Sequence , ValueOrd } ;
8
+ use der:: { Decode , Enumerated , Error , ErrorKind , Sequence , Tag , ValueOrd } ;
9
9
use spki:: { AlgorithmIdentifierOwned , SubjectPublicKeyInfoOwned } ;
10
10
11
11
#[ cfg( feature = "pem" ) ]
12
12
use der:: pem:: PemLabel ;
13
13
14
+ /// [`Profile`] allows the consumer of this crate to customize the behavior when parsing
15
+ /// certificates.
16
+ /// By default, parsing will be made in a rfc5280-compliant manner.
17
+ pub trait Profile : PartialEq + Debug + Eq + Clone {
18
+ /// Checks to run when parsing serial numbers
19
+ fn check_serial_number ( serial : & SerialNumber < Self > ) -> der:: Result < ( ) > {
20
+ // See the note in `SerialNumber::new`: we permit lengths of 21 bytes here,
21
+ // since some X.509 implementations interpret the limit of 20 bytes to refer
22
+ // to the pre-encoded value.
23
+ if serial. inner . len ( ) > SerialNumber :: < Self > :: MAX_DECODE_LEN {
24
+ Err ( Tag :: Integer . value_error ( ) )
25
+ } else {
26
+ Ok ( ( ) )
27
+ }
28
+ }
29
+ }
30
+
31
+ #[ derive( Debug , PartialEq , Eq , Clone ) ]
32
+ /// Parse certificates with rfc5280-compliant checks
33
+ pub struct Rfc5280 ;
34
+
35
+ impl Profile for Rfc5280 { }
36
+
37
+ #[ cfg( feature = "hazmat" ) ]
38
+ #[ derive( Debug , PartialEq , Eq , Clone ) ]
39
+ /// Parse raw x509 certificate and disable all the checks
40
+ pub struct Raw ;
41
+
42
+ #[ cfg( feature = "hazmat" ) ]
43
+ impl Profile for Raw {
44
+ fn check_serial_number ( _serial : & SerialNumber < Self > ) -> der:: Result < ( ) > {
45
+ Ok ( ( ) )
46
+ }
47
+ }
48
+
14
49
/// Certificate `Version` as defined in [RFC 5280 Section 4.1].
15
50
///
16
51
/// ```text
@@ -45,6 +80,9 @@ impl Default for Version {
45
80
}
46
81
}
47
82
83
+ /// X.509 `TbsCertificate` as defined in [RFC 5280 Section 4.1]
84
+ pub type TbsCertificate = TbsCertificateInner < Rfc5280 > ;
85
+
48
86
/// X.509 `TbsCertificate` as defined in [RFC 5280 Section 4.1]
49
87
///
50
88
/// ASN.1 structure containing the names of the subject and issuer, a public
@@ -73,7 +111,7 @@ impl Default for Version {
73
111
#[ cfg_attr( feature = "arbitrary" , derive( arbitrary:: Arbitrary ) ) ]
74
112
#[ derive( Clone , Debug , Eq , PartialEq , Sequence , ValueOrd ) ]
75
113
#[ allow( missing_docs) ]
76
- pub struct TbsCertificate {
114
+ pub struct TbsCertificateInner < P : Profile = Rfc5280 > {
77
115
/// The certificate version
78
116
///
79
117
/// Note that this value defaults to Version 1 per the RFC. However,
@@ -83,7 +121,7 @@ pub struct TbsCertificate {
83
121
#[ asn1( context_specific = "0" , default = "Default::default" ) ]
84
122
pub version : Version ,
85
123
86
- pub serial_number : SerialNumber ,
124
+ pub serial_number : SerialNumber < P > ,
87
125
pub signature : AlgorithmIdentifierOwned ,
88
126
pub issuer : Name ,
89
127
pub validity : Validity ,
@@ -98,9 +136,11 @@ pub struct TbsCertificate {
98
136
99
137
#[ asn1( context_specific = "3" , tag_mode = "EXPLICIT" , optional = "true" ) ]
100
138
pub extensions : Option < crate :: ext:: Extensions > ,
139
+
140
+ pub ( crate ) _profile : PhantomData < P > ,
101
141
}
102
142
103
- impl TbsCertificate {
143
+ impl < P : Profile > TbsCertificateInner < P > {
104
144
/// Decodes a single extension
105
145
///
106
146
/// Returns an error if multiple of these extensions is present. Returns
@@ -132,6 +172,11 @@ impl TbsCertificate {
132
172
}
133
173
}
134
174
175
+ /// X.509 certificates are defined in [RFC 5280 Section 4.1].
176
+ ///
177
+ /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
178
+ pub type Certificate = CertificateInner < Rfc5280 > ;
179
+
135
180
/// X.509 certificates are defined in [RFC 5280 Section 4.1].
136
181
///
137
182
/// ```text
@@ -146,14 +191,14 @@ impl TbsCertificate {
146
191
#[ cfg_attr( feature = "arbitrary" , derive( arbitrary:: Arbitrary ) ) ]
147
192
#[ derive( Clone , Debug , Eq , PartialEq , Sequence , ValueOrd ) ]
148
193
#[ allow( missing_docs) ]
149
- pub struct Certificate {
150
- pub tbs_certificate : TbsCertificate ,
194
+ pub struct CertificateInner < P : Profile = Rfc5280 > {
195
+ pub tbs_certificate : TbsCertificateInner < P > ,
151
196
pub signature_algorithm : AlgorithmIdentifierOwned ,
152
197
pub signature : BitString ,
153
198
}
154
199
155
200
#[ cfg( feature = "pem" ) ]
156
- impl PemLabel for Certificate {
201
+ impl < P : Profile > PemLabel for CertificateInner < P > {
157
202
const PEM_LABEL : & ' static str = "CERTIFICATE" ;
158
203
}
159
204
0 commit comments