Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Side by Side Diff: net/cert/internal/parse_certificate.cc

Issue 1279963003: Add a function for parsing RFC 5280's "TBSCertificate". (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert_mapper
Patch Set: rebase onto master Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698