3
3
use core:: fmt:: Display ;
4
4
5
5
use der:: {
6
- asn1:: Int , DecodeValue , EncodeValue , ErrorKind , FixedTag , Header , Length , Reader , Result , Tag ,
7
- ValueOrd , Writer ,
6
+ asn1:: Int , asn1 :: Uint , DecodeValue , EncodeValue , ErrorKind , FixedTag , Header , Length , Reader ,
7
+ Result , Tag , ValueOrd , Writer ,
8
8
} ;
9
9
10
10
/// [RFC 5280 Section 4.1.2.2.] Serial Number
@@ -32,15 +32,27 @@ impl SerialNumber {
32
32
/// Maximum length in bytes for a [`SerialNumber`]
33
33
pub const MAX_LEN : Length = Length :: new ( 20 ) ;
34
34
35
+ /// See notes in `SerialNumber::new` and `SerialNumber::decode_value`.
36
+ const MAX_DECODE_LEN : Length = Length :: new ( 21 ) ;
37
+
35
38
/// Create a new [`SerialNumber`] from a byte slice.
39
+ ///
40
+ /// The byte slice **must** represent a positive integer.
36
41
pub fn new ( bytes : & [ u8 ] ) -> Result < Self > {
37
- let inner = Int :: new ( bytes) ?;
38
-
39
- if inner. len ( ) > SerialNumber :: MAX_LEN {
42
+ let inner = Uint :: new ( bytes) ?;
43
+
44
+ // The user might give us a 20 byte unsigned integer with a high MSB,
45
+ // which we'd then encode with 21 octets to preserve the sign bit.
46
+ // RFC 5280 is ambiguous about whether this is valid, so we limit
47
+ // `SerialNumber` *encodings* to 20 bytes or fewer while permitting
48
+ // `SerialNumber` *decodings* to have up to 21 bytes below.
49
+ if inner. value_len ( ) ? > SerialNumber :: MAX_LEN {
40
50
return Err ( ErrorKind :: Overlength . into ( ) ) ;
41
51
}
42
52
43
- Ok ( Self { inner } )
53
+ Ok ( Self {
54
+ inner : inner. into ( ) ,
55
+ } )
44
56
}
45
57
46
58
/// Borrow the inner byte slice which contains the least significant bytes
@@ -64,7 +76,10 @@ impl<'a> DecodeValue<'a> for SerialNumber {
64
76
fn decode_value < R : Reader < ' a > > ( reader : & mut R , header : Header ) -> Result < Self > {
65
77
let inner = Int :: decode_value ( reader, header) ?;
66
78
67
- if inner. len ( ) > SerialNumber :: MAX_LEN {
79
+ // See the note in `SerialNumber::new`: we permit lengths of 21 bytes here,
80
+ // since some X.509 implementations interpret the limit of 20 bytes to refer
81
+ // to the pre-encoded value.
82
+ if inner. len ( ) > SerialNumber :: MAX_DECODE_LEN {
68
83
return Err ( ErrorKind :: Overlength . into ( ) ) ;
69
84
}
70
85
@@ -112,11 +127,44 @@ mod tests {
112
127
113
128
use super :: * ;
114
129
130
+ #[ test]
131
+ fn serial_number_invariants ( ) {
132
+ // Creating a new serial with an oversized encoding (due to high MSB) fails.
133
+ {
134
+ let too_big = [ 0x80 ; 20 ] ;
135
+ assert ! ( SerialNumber :: new( & too_big) . is_err( ) ) ;
136
+ }
137
+
138
+ // Creating a new serial with the maximum encoding succeeds.
139
+ {
140
+ let just_enough = [
141
+ 0x7F , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
142
+ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
143
+ ] ;
144
+ assert ! ( SerialNumber :: new( & just_enough) . is_ok( ) ) ;
145
+ }
146
+ }
147
+
115
148
#[ test]
116
149
fn serial_number_display ( ) {
117
- let sn = SerialNumber :: new ( & [ 0xAA , 0xBB , 0xCC , 0x01 , 0x10 , 0x00 , 0x11 ] )
118
- . expect ( "unexpected error" ) ;
150
+ {
151
+ let sn = SerialNumber :: new ( & [ 0x11 , 0x22 , 0x33 ] ) . unwrap ( ) ;
152
+
153
+ assert_eq ! ( sn. to_string( ) , "11:22:33" )
154
+ }
155
+
156
+ {
157
+ let sn = SerialNumber :: new ( & [ 0xAA , 0xBB , 0xCC , 0x01 , 0x10 , 0x00 , 0x11 ] ) . unwrap ( ) ;
119
158
120
- assert_eq ! ( sn. to_string( ) , "AA:BB:CC:01:10:00:11" )
159
+ // We force the user's serial to be positive if they give us a negative one.
160
+ assert_eq ! ( sn. to_string( ) , "00:AA:BB:CC:01:10:00:11" )
161
+ }
162
+
163
+ {
164
+ let sn = SerialNumber :: new ( & [ 0x00 , 0x00 , 0x01 ] ) . unwrap ( ) ;
165
+
166
+ // Leading zeroes are ignored, due to canonicalization.
167
+ assert_eq ! ( sn. to_string( ) , "01" )
168
+ }
121
169
}
122
170
}
0 commit comments