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

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

Powered by Google App Engine
This is Rietveld 408576698