OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/cert/internal/parse_certificate.h" | |
6 | |
7 #include "net/der/input.h" | |
8 #include "net/der/parse_values.h" | |
9 #include "net/der/parser.h" | |
10 | |
11 namespace net { | |
12 | |
13 namespace { | |
14 | |
15 // Parses a Version according to RFC 5280: | |
16 // | |
17 // Version ::= INTEGER { v1(0), v2(1), v3(2) } | |
18 // | |
19 // No value other that v1, v2, or v3 is allowed (and if given will fail). RFC | |
20 // 5280 minimally requires the handling of v3 (and overwhelmingly these are the | |
21 // certificate versions in use today): | |
davidben
2015/08/11 20:31:56
Do we need to handle this unspecified v4 thing?
eroman
2015/08/11 21:13:33
From what I can tell v4 is not really a thing yet
davidben
2015/08/11 22:39:20
I know nothing about what v4 is. I think Ryan said
eroman
2015/08/12 00:37:10
Acknowledged. I will try and follow-up with v4 req
| |
22 // | |
23 // Implementations SHOULD be prepared to accept any version certificate. | |
24 // At a minimum, conforming implementations MUST recognize version 3 | |
25 // certificates. | |
26 // | |
27 WARN_UNUSED_RESULT bool ParseVersion(const der::Input& in, | |
28 CertificateVersion* version) { | |
29 der::Parser parser(in); | |
30 uint64_t version64; | |
31 if (!parser.ReadUint64(&version64)) | |
32 return false; | |
33 | |
34 switch (version64) { | |
35 case 0: | |
36 *version = CertificateVersion::V1; | |
37 break; | |
38 case 1: | |
39 *version = CertificateVersion::V2; | |
40 break; | |
41 case 2: | |
42 *version = CertificateVersion::V3; | |
43 break; | |
44 default: | |
45 // Don't allow any other version identifier. | |
46 return false; | |
47 } | |
48 | |
49 // By definition the input to this function was a single INTEGER, so there | |
50 // shouldn't be anything else after it. | |
51 return !parser.HasMore(); | |
52 } | |
53 | |
54 // Returns true if the given serial number (CertificateSerialNumber in RFC 5280) | |
55 // is valid: | |
56 // | |
57 // CertificateSerialNumber ::= INTEGER | |
58 // | |
59 // The input to this function is the (unverified) value octets of the INTEGER. | |
60 // This function will verify that: | |
61 // | |
62 // * The octets are a valid DER-encoding of an INTEGER (for instance, minimal | |
63 // encoding length). | |
64 // | |
65 // * No more than 20 octets are used. | |
66 // | |
67 // Note that it DOES NOT reject non-positive values (zero or negative). | |
68 // | |
69 // For reference, here is what RFC 5280 section 4.1.2.2 says: | |
70 // | |
71 // Given the uniqueness requirements above, serial numbers can be | |
72 // expected to contain long integers. Certificate users MUST be able to | |
73 // handle serialNumber values up to 20 octets. Conforming CAs MUST NOT | |
74 // use serialNumber values longer than 20 octets. | |
75 // | |
76 // Note: Non-conforming CAs may issue certificates with serial numbers | |
77 // that are negative or zero. Certificate users SHOULD be prepared to | |
78 // gracefully handle such certificates. | |
79 WARN_UNUSED_RESULT bool VerifySerialNumber(const der::Input& value) { | |
80 der::ByteReader reader(value); | |
81 | |
82 if (value.Length() == 0) | |
83 return false; // Not a valid DER-encoded INTEGER. | |
84 | |
85 // Check if the serial number is too long per RFC 5280. | |
86 if (value.Length() > 20) | |
87 return false; | |
88 | |
89 // Accept any single-byte serial number (including zero and negatives). | |
90 if (value.Length() == 1) | |
91 return true; | |
92 | |
93 // INTEGER values in DER should be minimal. They should only contain a leading | |
94 // zero if the second octet has its most significant bit set to 1 (since | |
95 // without the leading zero the described number would be negative). | |
96 uint8_t first_byte; | |
97 if (!reader.ReadByte(&first_byte)) | |
98 return false; // Unexpected | |
99 | |
100 if (first_byte == 0) { | |
101 uint8_t second_byte; | |
102 if (!reader.ReadByte(&second_byte)) | |
103 return false; // Unexpected | |
104 | |
105 if ((second_byte & 0x80) == 0) | |
106 return false; // MSB must be 1. | |
107 } | |
108 | |
109 return true; | |
110 } | |
111 | |
112 } // namespace | |
113 | |
114 ParsedTbsCertificate::ParsedTbsCertificate() | |
115 : version(CertificateVersion::V1), | |
116 has_issuer_unique_id(false), | |
117 has_subject_unique_id(false), | |
118 has_extensions(false) {} | |
119 | |
120 ParsedTbsCertificate::~ParsedTbsCertificate() {} | |
121 | |
122 bool ParseCertificate(const der::Input& certificate_tlv, | |
123 ParsedCertificate* out) { | |
davidben
2015/08/11 20:31:56
[I probably would have written this function in Bo
eroman
2015/08/11 21:13:33
This is a good point. I found it convenient in the
davidben
2015/08/11 22:39:20
Either's fine by me. I have noticed that Chromium
| |
124 der::Parser parser(certificate_tlv); | |
125 | |
126 // Certificate ::= SEQUENCE { | |
127 der::Parser certificate_parser; | |
128 if (!parser.ReadSequence(&certificate_parser)) | |
129 return false; | |
130 | |
131 // tbsCertificate TBSCertificate, | |
132 if (!certificate_parser.ReadRawTLV(&out->tbs_certificate_tlv)) | |
133 return false; | |
134 | |
135 // signatureAlgorithm AlgorithmIdentifier, | |
136 if (!certificate_parser.ReadRawTLV(&out->signature_algorithm_tlv)) | |
137 return false; | |
138 | |
139 // signatureValue BIT STRING } | |
140 if (!certificate_parser.ReadBitString(&out->signature_value)) | |
141 return false; | |
142 | |
143 // By definition the input was a single Certificate, so there shouldn't be | |
144 // unconsumed data. | |
145 if (parser.HasMore()) | |
146 return false; | |
147 | |
148 // There isn't an extension point at the end of Certificate. | |
149 if (certificate_parser.HasMore()) | |
150 return false; | |
davidben
2015/08/11 20:31:56
Nit: It seems better to check certificate_parser b
eroman
2015/08/11 21:13:33
Will do.
eroman
2015/08/12 00:37:10
Done.
| |
151 | |
152 return true; | |
153 } | |
154 | |
155 // From RFC 5280 section 4.1: | |
156 // | |
157 // Certificate ::= SEQUENCE { | |
158 // tbsCertificate TBSCertificate, | |
159 // signatureAlgorithm AlgorithmIdentifier, | |
160 // signatureValue BIT STRING } | |
161 // | |
162 // TBSCertificate ::= SEQUENCE { | |
163 // version [0] EXPLICIT Version DEFAULT v1, | |
164 // serialNumber CertificateSerialNumber, | |
165 // signature AlgorithmIdentifier, | |
166 // issuer Name, | |
167 // validity Validity, | |
168 // subject Name, | |
169 // subjectPublicKeyInfo SubjectPublicKeyInfo, | |
170 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, | |
171 // -- If present, version MUST be v2 or v3 | |
172 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, | |
173 // -- If present, version MUST be v2 or v3 | |
174 // extensions [3] EXPLICIT Extensions OPTIONAL | |
175 // -- If present, version MUST be v3 | |
176 // } | |
177 bool ParseTbsCertificate(const der::Input& tbs_tlv, ParsedTbsCertificate* out) { | |
178 der::Parser parser(tbs_tlv); | |
179 | |
180 // Certificate ::= SEQUENCE { | |
181 der::Parser tbs_parser; | |
182 if (!parser.ReadSequence(&tbs_parser)) | |
183 return false; | |
184 | |
185 // version [0] EXPLICIT Version DEFAULT v1, | |
186 der::Input version; | |
187 bool has_version; | |
188 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &version, | |
189 &has_version)) { | |
190 return false; | |
191 } | |
192 if (has_version) { | |
193 if (!ParseVersion(version, &out->version)) | |
194 return false; | |
davidben
2015/08/11 20:31:56
Although it seems we can't enforce it, there is a
eroman
2015/08/11 21:13:33
Good point!
I should enforce that here, and will d
davidben
2015/08/11 22:39:20
I believe mozilla::pkix doesn't. Although, actuall
eroman
2015/08/12 00:37:10
Acknowledged thanks for the context!
I have added
| |
195 } else { | |
196 out->version = CertificateVersion::V1; | |
197 } | |
198 | |
199 // serialNumber CertificateSerialNumber, | |
200 if (!tbs_parser.ReadTag(der::kInteger, &out->serial_number)) | |
201 return false; | |
202 if (!VerifySerialNumber(out->serial_number)) | |
203 return false; | |
204 | |
205 // signature AlgorithmIdentifier, | |
206 if (!tbs_parser.ReadRawTLV(&out->signature_algorithm_tlv)) | |
207 return false; | |
208 | |
209 // issuer Name, | |
210 if (!tbs_parser.ReadRawTLV(&out->issuer_tlv)) | |
211 return false; | |
212 | |
213 // validity Validity, | |
214 if (!tbs_parser.ReadRawTLV(&out->validity_tlv)) | |
215 return false; | |
216 | |
217 // subject Name, | |
218 if (!tbs_parser.ReadRawTLV(&out->subject_tlv)) | |
219 return false; | |
220 | |
221 // subjectPublicKeyInfo SubjectPublicKeyInfo, | |
222 if (!tbs_parser.ReadRawTLV(&out->spki_tlv)) | |
223 return false; | |
224 | |
225 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, | |
226 // -- If present, version MUST be v2 or v3 | |
227 der::Input issuer_unique_id; | |
228 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(1), | |
229 &issuer_unique_id, | |
230 &out->has_issuer_unique_id)) { | |
231 return false; | |
232 } | |
233 if (out->has_issuer_unique_id) { | |
234 if (!der::ParseBitString(issuer_unique_id, &out->issuer_unique_id)) | |
davidben
2015/08/11 20:31:56
[Verified that ParseBitString does NOT expect a TL
| |
235 return false; | |
236 if (out->version != CertificateVersion::V2 && | |
237 out->version != CertificateVersion::V3) { | |
238 return false; | |
239 } | |
240 } | |
241 | |
242 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, | |
243 // -- If present, version MUST be v2 or v3 | |
244 der::Input subject_unique_id; | |
245 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(2), | |
246 &subject_unique_id, | |
247 &out->has_subject_unique_id)) { | |
248 return false; | |
249 } | |
250 if (out->has_subject_unique_id) { | |
251 if (!der::ParseBitString(subject_unique_id, &out->subject_unique_id)) | |
252 return false; | |
253 if (out->version != CertificateVersion::V2 && | |
254 out->version != CertificateVersion::V3) { | |
255 return false; | |
256 } | |
257 } | |
258 | |
259 // extensions [3] EXPLICIT Extensions OPTIONAL | |
260 // -- If present, version MUST be v3 | |
261 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(3), | |
262 &out->extensions_tlv, &out->has_extensions)) { | |
263 return false; | |
264 } | |
265 if (out->has_extensions) { | |
266 if (out->version != CertificateVersion::V3) | |
267 return false; | |
268 } | |
269 | |
270 // By definition the input was a single TBSCertificate, so there shouldn't be | |
271 // unconsumed data. | |
272 if (parser.HasMore()) | |
273 return false; | |
274 | |
275 // Note that there IS an extension point at the end of TBSCertificate | |
276 // (according to RFC 5912), so from that interpretation, unconsumed data would | |
277 // be allowed in |tbs_parser|. | |
278 // | |
279 // However because only v1, v2, and v3 certificates are supported by the | |
280 // parsing, there shouldn't be any subsequent data in those versions, so | |
281 // reject. | |
282 if (tbs_parser.HasMore()) | |
283 return false; | |
davidben
2015/08/11 20:31:56
Nit: Ditto re parser vs tbs_parser order.
eroman
2015/08/12 00:37:10
Done.
| |
284 | |
285 return true; | |
286 } | |
287 | |
288 } // namespace net | |
OLD | NEW |