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