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

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: more reformatting 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:
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 bool unused_negative;
96 size_t unused_numeric_length;
97 if (!der::IsValidInteger(value, &unused_negative, &unused_numeric_length))
98 return false;
99
100 // Check if the serial number is too long per RFC 5280.
101 if (value.Length() > 20)
102 return false;
103
104 return true;
105 }
106
31 } // namespace 107 } // namespace
32 108
109 ParsedTbsCertificate::ParsedTbsCertificate()
110 : version(CertificateVersion::V1),
111 has_issuer_unique_id(false),
112 has_subject_unique_id(false),
113 has_extensions(false) {}
davidben 2015/08/17 21:16:02 Optional: Non-static initializers are allowed now,
eroman 2015/08/18 00:20:50 Done. As an aside, I have gotten feedback from R
davidben 2015/08/18 00:22:56 Interesting! I'm pretty sure I've gotten feedback
eroman 2015/08/18 00:35:52 As an aside: I understand member initializers bett
114
115 ParsedTbsCertificate::~ParsedTbsCertificate() {}
116
33 bool ParseCertificate(const der::Input& certificate_tlv, 117 bool ParseCertificate(const der::Input& certificate_tlv,
34 ParsedCertificate* out) { 118 ParsedCertificate* out) {
35 der::Parser parser(certificate_tlv); 119 der::Parser parser(certificate_tlv);
36 120
37 // Certificate ::= SEQUENCE { 121 // Certificate ::= SEQUENCE {
38 der::Parser certificate_parser; 122 der::Parser certificate_parser;
39 if (!parser.ReadSequence(&certificate_parser)) 123 if (!parser.ReadSequence(&certificate_parser))
40 return false; 124 return false;
41 125
42 // tbsCertificate TBSCertificate, 126 // tbsCertificate TBSCertificate,
(...skipping 13 matching lines...) Expand all
56 return false; 140 return false;
57 141
58 // By definition the input was a single Certificate, so there shouldn't be 142 // By definition the input was a single Certificate, so there shouldn't be
59 // unconsumed data. 143 // unconsumed data.
60 if (parser.HasMore()) 144 if (parser.HasMore())
61 return false; 145 return false;
62 146
63 return true; 147 return true;
64 } 148 }
65 149
150 // From RFC 5280 section 4.1:
151 //
152 // TBSCertificate ::= SEQUENCE {
153 // version [0] EXPLICIT Version DEFAULT v1,
154 // serialNumber CertificateSerialNumber,
155 // signature AlgorithmIdentifier,
156 // issuer Name,
157 // validity Validity,
158 // subject Name,
159 // subjectPublicKeyInfo SubjectPublicKeyInfo,
160 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
161 // -- If present, version MUST be v2 or v3
162 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
163 // -- If present, version MUST be v2 or v3
164 // extensions [3] EXPLICIT Extensions OPTIONAL
165 // -- If present, version MUST be v3
166 // }
167 bool ParseTbsCertificate(const der::Input& tbs_tlv, ParsedTbsCertificate* out) {
168 der::Parser parser(tbs_tlv);
169
170 // Certificate ::= SEQUENCE {
171 der::Parser tbs_parser;
172 if (!parser.ReadSequence(&tbs_parser))
173 return false;
174
175 // version [0] EXPLICIT Version DEFAULT v1,
176 der::Input version;
177 bool has_version;
178 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &version,
179 &has_version)) {
180 return false;
181 }
182 if (has_version) {
183 if (!ParseVersion(version, &out->version))
184 return false;
185 if (out->version == CertificateVersion::V1) {
186 // The correct way to specify v1 is to omit the version field since v1 is
187 // the DEFAULT.
188 return false;
189 }
190 } else {
191 out->version = CertificateVersion::V1;
192 }
193
194 // serialNumber CertificateSerialNumber,
195 if (!tbs_parser.ReadTag(der::kInteger, &out->serial_number))
196 return false;
197 if (!VerifySerialNumber(out->serial_number))
198 return false;
199
200 // signature AlgorithmIdentifier,
201 if (!ReadSequenceTLV(&tbs_parser, &out->signature_algorithm_tlv))
202 return false;
203
204 // issuer Name,
205 if (!ReadSequenceTLV(&tbs_parser, &out->issuer_tlv))
206 return false;
207
208 // validity Validity,
209 if (!ReadSequenceTLV(&tbs_parser, &out->validity_tlv))
210 return false;
211
212 // subject Name,
213 if (!ReadSequenceTLV(&tbs_parser, &out->subject_tlv))
214 return false;
215
216 // subjectPublicKeyInfo SubjectPublicKeyInfo,
217 if (!ReadSequenceTLV(&tbs_parser, &out->spki_tlv))
218 return false;
219
220 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
221 // -- If present, version MUST be v2 or v3
222 der::Input issuer_unique_id;
223 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(1),
224 &issuer_unique_id,
225 &out->has_issuer_unique_id)) {
226 return false;
227 }
228 if (out->has_issuer_unique_id) {
229 if (!der::ParseBitString(issuer_unique_id, &out->issuer_unique_id))
230 return false;
231 if (out->version != CertificateVersion::V2 &&
232 out->version != CertificateVersion::V3) {
233 return false;
234 }
235 }
236
237 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
238 // -- If present, version MUST be v2 or v3
239 der::Input subject_unique_id;
240 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(2),
241 &subject_unique_id,
242 &out->has_subject_unique_id)) {
243 return false;
244 }
245 if (out->has_subject_unique_id) {
246 if (!der::ParseBitString(subject_unique_id, &out->subject_unique_id))
247 return false;
248 if (out->version != CertificateVersion::V2 &&
249 out->version != CertificateVersion::V3) {
250 return false;
251 }
252 }
253
254 // extensions [3] EXPLICIT Extensions OPTIONAL
255 // -- If present, version MUST be v3
256 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(3),
257 &out->extensions_tlv, &out->has_extensions)) {
258 return false;
259 }
260 if (out->has_extensions) {
261 // extensions_tlv must be a single element. Also check that it is a
262 // SEQUENCE.
263 if (!IsSequenceTLV(out->extensions_tlv))
264 return false;
265 if (out->version != CertificateVersion::V3)
266 return false;
267 }
268
269 // Note that there IS an extension point at the end of TBSCertificate
270 // (according to RFC 5912), so from that interpretation, unconsumed data would
271 // be allowed in |tbs_parser|.
272 //
273 // However because only v1, v2, and v3 certificates are supported by the
274 // parsing, there shouldn't be any subsequent data in those versions, so
275 // reject.
276 if (tbs_parser.HasMore())
277 return false;
278
279 // By definition the input was a single TBSCertificate, so there shouldn't be
280 // unconsumed data.
281 if (parser.HasMore())
282 return false;
283
284 return true;
285 }
286
66 } // namespace net 287 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698