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

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

Issue 1849773002: Adding OCSP Verification Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix scoped_ptr. Created 4 years, 7 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
(Empty)
1 // Copyright 2016 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 <algorithm>
6
7 #include "base/sha1.h"
8 #include "crypto/sha2.h"
9 #include "net/cert/internal/parse_ocsp.h"
10
11 namespace net {
12
13 OCSPCertID::OCSPCertID() {}
14 OCSPCertID::~OCSPCertID() {}
15
16 OCSPSingleResponse::OCSPSingleResponse() {}
17 OCSPSingleResponse::~OCSPSingleResponse() {}
18
19 OCSPResponseData::OCSPResponseData() {}
20 OCSPResponseData::~OCSPResponseData() {}
21
22 OCSPResponse::OCSPResponse() {}
23 OCSPResponse::~OCSPResponse() {}
24
25 der::Input BasicOCSPResponseOid() {
26 // From RFC 6960:
27 //
28 // id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp }
29 // id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
30 //
31 // In dotted notation: 1.3.6.1.5.5.7.48.1.1
32 static const uint8_t oid[] = {0x2b, 0x06, 0x01, 0x05, 0x05,
33 0x07, 0x30, 0x01, 0x01};
34 return der::Input(oid);
35 }
36
37 // CertID ::= SEQUENCE {
38 // hashAlgorithm AlgorithmIdentifier,
39 // issuerNameHash OCTET STRING, -- Hash of issuer's DN
40 // issuerKeyHash OCTET STRING, -- Hash of issuer's public key
41 // serialNumber CertificateSerialNumber
42 // }
43 bool ParseOCSPCertID(const der::Input& raw_tlv, OCSPCertID* out) {
44 der::Parser outer_parser(raw_tlv);
45 der::Parser parser;
46 if (!outer_parser.ReadSequence(&parser))
47 return false;
48 if (outer_parser.HasMore())
49 return false;
50
51 der::Input sigalg_tlv;
52 if (!parser.ReadRawTLV(&sigalg_tlv))
53 return false;
54 if (!ParseHashAlgorithm(sigalg_tlv, &(out->hash_algorithm)))
55 return false;
56 if (!parser.ReadTag(der::kOctetString, &(out->issuer_name_hash)))
57 return false;
58 if (!parser.ReadTag(der::kOctetString, &(out->issuer_key_hash)))
59 return false;
60 if (!parser.ReadTag(der::kInteger, &(out->serial_number)))
61 return false;
62 if (!VerifySerialNumber(out->serial_number))
63 return false;
64
65 return !parser.HasMore();
66 }
67
68 namespace {
69
70 // Parses |raw_tlv| to extract an OCSP RevokedInfo (RFC 6960) and stores the
71 // result in the OCSPCertStatus |out|. Returns whether the parsing was
72 // successful.
73 //
74 // RevokedInfo ::= SEQUENCE {
75 // revocationTime GeneralizedTime,
76 // revocationReason [0] EXPLICIT CRLReason OPTIONAL
77 // }
78 bool ParseRevokedInfo(const der::Input& raw_tlv, OCSPCertStatus* out) {
79 der::Parser parser(raw_tlv);
80 if (!parser.ReadGeneralizedTime(&(out->revocation_time)))
81 return false;
82
83 der::Input reason_input;
84 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &reason_input,
85 &(out->has_reason))) {
86 return false;
87 }
88 if (out->has_reason) {
89 der::Parser reason_parser(reason_input);
90 der::Input reason_value_input;
91 uint8_t reason_value;
92 if (!reason_parser.ReadTag(der::kEnumerated, &reason_value_input))
93 return false;
94 if (!der::ParseUint8(reason_value_input, &reason_value))
95 return false;
96 if (reason_value >
97 static_cast<uint8_t>(OCSPCertStatus::RevocationReason::LAST)) {
98 return false;
99 }
100 out->revocation_reason =
101 static_cast<OCSPCertStatus::RevocationReason>(reason_value);
102 if (out->revocation_reason == OCSPCertStatus::RevocationReason::UNUSED)
103 return false;
104 if (reason_parser.HasMore())
105 return false;
106 }
107 return !parser.HasMore();
108 }
109
110 // Parses |raw_tlv| to extract an OCSP CertStatus (RFC 6960) and stores the
111 // result in the OCSPCertStatus |out|. Returns whether the parsing was
112 // successful.
113 //
114 // CertStatus ::= CHOICE {
115 // good [0] IMPLICIT NULL,
116 // revoked [1] IMPLICIT RevokedInfo,
117 // unknown [2] IMPLICIT UnknownInfo
118 // }
119 //
120 // UnknownInfo ::= NULL
121 bool ParseCertStatus(const der::Input& raw_tlv, OCSPCertStatus* out) {
122 der::Parser parser(raw_tlv);
123 der::Tag status_tag;
124 der::Input status;
125 if (!parser.ReadTagAndValue(&status_tag, &status))
126 return false;
127
128 out->has_reason = false;
129 if (status_tag == der::ContextSpecificPrimitive(0)) {
130 out->status = OCSPCertStatus::Status::GOOD;
131 } else if (status_tag == der::ContextSpecificConstructed(1)) {
132 out->status = OCSPCertStatus::Status::REVOKED;
133 if (!ParseRevokedInfo(status, out))
134 return false;
135 } else if (status_tag == der::ContextSpecificPrimitive(2)) {
136 out->status = OCSPCertStatus::Status::UNKNOWN;
137 } else {
138 return false;
139 }
140
141 return !parser.HasMore();
142 }
143
144 } // namespace
145
146 // SingleResponse ::= SEQUENCE {
147 // certID CertID,
148 // certStatus CertStatus,
149 // thisUpdate GeneralizedTime,
150 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
151 // singleExtensions [1] EXPLICIT Extensions OPTIONAL
152 // }
153 bool ParseOCSPSingleResponse(const der::Input& raw_tlv,
154 OCSPSingleResponse* out) {
155 der::Parser outer_parser(raw_tlv);
156 der::Parser parser;
157 if (!outer_parser.ReadSequence(&parser))
158 return false;
159 if (outer_parser.HasMore())
160 return false;
161
162 if (!parser.ReadRawTLV(&(out->cert_id_tlv)))
163 return false;
164 der::Input status_tlv;
165 if (!parser.ReadRawTLV(&status_tlv))
166 return false;
167 if (!ParseCertStatus(status_tlv, &(out->cert_status)))
168 return false;
169 if (!parser.ReadGeneralizedTime(&(out->this_update)))
170 return false;
171
172 der::Input next_update_input;
173 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0),
174 &next_update_input, &(out->has_next_update))) {
175 return false;
176 }
177 if (out->has_next_update) {
178 der::Parser next_update_parser(next_update_input);
179 if (!next_update_parser.ReadGeneralizedTime(&(out->next_update)))
180 return false;
181 if (next_update_parser.HasMore())
182 return false;
183 }
184
185 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(1),
186 &(out->extensions), &(out->has_extensions))) {
187 return false;
188 }
189
190 return !parser.HasMore();
191 }
192
193 namespace {
194
195 // Parses |raw_tlv| to extract a ResponderID (RFC 6960) and stores the
196 // result in the ResponderID |out|. Returns whether the parsing was successful.
197 //
198 // ResponderID ::= CHOICE {
199 // byName [1] Name,
200 // byKey [2] KeyHash
201 // }
202 bool ParseResponderID(const der::Input& raw_tlv,
203 OCSPResponseData::ResponderID* out) {
204 der::Parser parser(raw_tlv);
205 der::Tag id_tag;
206 der::Input id_input;
207 if (!parser.ReadTagAndValue(&id_tag, &id_input))
208 return false;
209
210 if (id_tag == der::ContextSpecificConstructed(1)) {
211 out->type = OCSPResponseData::ResponderType::NAME;
212 out->name = id_input;
213 } else if (id_tag == der::ContextSpecificConstructed(2)) {
214 der::Parser key_parser(id_input);
215 der::Input responder_key;
216 if (!key_parser.ReadTag(der::kOctetString, &responder_key))
217 return false;
218 if (key_parser.HasMore())
219 return false;
220
221 SHA1HashValue key_hash;
222 if (responder_key.Length() != sizeof(key_hash.data))
223 return false;
224 memcpy(key_hash.data, responder_key.UnsafeData(), sizeof(key_hash.data));
225 out->type = OCSPResponseData::ResponderType::KEY_HASH;
226 out->key_hash = HashValue(key_hash);
227 } else {
228 return false;
229 }
230 return !parser.HasMore();
231 }
232
233 } // namespace
234
235 // ResponseData ::= SEQUENCE {
236 // version [0] EXPLICIT Version DEFAULT v1,
237 // responderID ResponderID,
238 // producedAt GeneralizedTime,
239 // responses SEQUENCE OF SingleResponse,
240 // responseExtensions [1] EXPLICIT Extensions OPTIONAL
241 // }
242 bool ParseOCSPResponseData(const der::Input& raw_tlv, OCSPResponseData* out) {
243 der::Parser outer_parser(raw_tlv);
244 der::Parser parser;
245 if (!outer_parser.ReadSequence(&parser))
246 return false;
247 if (outer_parser.HasMore())
248 return false;
249
250 der::Input version_input;
251 bool version_present;
252 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0),
253 &version_input, &version_present)) {
254 return false;
255 }
256
257 // For compatibilty, we ignore the restriction from X.690 Section 11.5 that
258 // DEFAULT values should be omitted for values equal to the default value.
259 // TODO: Add warning about non-strict parsing.
260 if (version_present) {
261 der::Parser version_parser(version_input);
262 if (!version_parser.ReadUint8(&(out->version)))
263 return false;
264 if (version_parser.HasMore())
265 return false;
266 } else {
267 out->version = 0;
268 }
269
270 if (out->version != 0)
271 return false;
272
273 der::Input responder_input;
274 if (!parser.ReadRawTLV(&responder_input))
275 return false;
276 if (!ParseResponderID(responder_input, &(out->responder_id)))
277 return false;
278 if (!parser.ReadGeneralizedTime(&(out->produced_at)))
279 return false;
280
281 der::Parser responses_parser;
282 if (!parser.ReadSequence(&responses_parser))
283 return false;
284 out->responses.clear();
285 while (responses_parser.HasMore()) {
286 der::Input single_response;
287 if (!responses_parser.ReadRawTLV(&single_response))
288 return false;
289 out->responses.push_back(single_response);
290 }
291
292 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(1),
293 &(out->extensions), &(out->has_extensions))) {
294 return false;
295 }
296
297 return !parser.HasMore();
298 }
299
300 namespace {
301
302 // Parses |raw_tlv| to extract a BasicOCSPResponse (RFC 6960) and stores the
303 // result in the OCSPResponse |out|. Returns whether the parsing was
304 // successful.
305 //
306 // BasicOCSPResponse ::= SEQUENCE {
307 // tbsResponseData ResponseData,
308 // signatureAlgorithm AlgorithmIdentifier,
309 // signature BIT STRING,
310 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
311 // }
312 bool ParseBasicOCSPResponse(const der::Input& raw_tlv, OCSPResponse* out) {
313 der::Parser outer_parser(raw_tlv);
314 der::Parser parser;
315 if (!outer_parser.ReadSequence(&parser))
316 return false;
317 if (outer_parser.HasMore())
318 return false;
319
320 if (!parser.ReadRawTLV(&(out->data)))
321 return false;
322 der::Input sigalg_tlv;
323 if (!parser.ReadRawTLV(&sigalg_tlv))
324 return false;
325 out->signature_algorithm = SignatureAlgorithm::CreateFromDer(sigalg_tlv);
326 if (!out->signature_algorithm)
327 return false;
328 if (!parser.ReadBitString(&(out->signature)))
329 return false;
330 der::Input certs_input;
331 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &certs_input,
332 &(out->has_certs))) {
333 return false;
334 }
335
336 out->certs.clear();
337 if (out->has_certs) {
338 der::Parser certs_seq_parser(certs_input);
339 der::Parser certs_parser;
340 if (!certs_seq_parser.ReadSequence(&certs_parser))
341 return false;
342 if (certs_seq_parser.HasMore())
343 return false;
344 while (certs_parser.HasMore()) {
345 der::Input cert_tlv;
346 if (!certs_parser.ReadRawTLV(&cert_tlv))
347 return false;
348 out->certs.push_back(cert_tlv);
349 }
350 }
351
352 return !parser.HasMore();
353 }
354
355 } // namespace
356
357 // OCSPResponse ::= SEQUENCE {
358 // responseStatus OCSPResponseStatus,
359 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL
360 // }
361 //
362 // ResponseBytes ::= SEQUENCE {
363 // responseType OBJECT IDENTIFIER,
364 // response OCTET STRING
365 // }
366 bool ParseOCSPResponse(const der::Input& raw_tlv, OCSPResponse* out) {
367 der::Parser outer_parser(raw_tlv);
368 der::Parser parser;
369 if (!outer_parser.ReadSequence(&parser))
370 return false;
371 if (outer_parser.HasMore())
372 return false;
373
374 der::Input response_status_input;
375 uint8_t response_status;
376 if (!parser.ReadTag(der::kEnumerated, &response_status_input))
377 return false;
378 if (!der::ParseUint8(response_status_input, &response_status))
379 return false;
380 if (response_status >
381 static_cast<uint8_t>(OCSPResponse::ResponseStatus::LAST)) {
382 return false;
383 }
384 out->status = static_cast<OCSPResponse::ResponseStatus>(response_status);
385 if (out->status == OCSPResponse::ResponseStatus::UNUSED)
386 return false;
387
388 if (out->status == OCSPResponse::ResponseStatus::SUCCESSFUL) {
389 der::Parser outer_bytes_parser;
390 der::Parser bytes_parser;
391 if (!parser.ReadConstructed(der::ContextSpecificConstructed(0),
392 &outer_bytes_parser)) {
393 return false;
394 }
395 if (!outer_bytes_parser.ReadSequence(&bytes_parser))
396 return false;
397 if (outer_bytes_parser.HasMore())
398 return false;
399
400 der::Input type_oid;
401 if (!bytes_parser.ReadTag(der::kOid, &type_oid))
402 return false;
403 if (type_oid != BasicOCSPResponseOid())
404 return false;
405
406 // As per RFC 6960 Section 4.2.1, the value of |response| SHALL be the DER
407 // encoding of BasicOCSPResponse.
408 der::Input response;
409 if (!bytes_parser.ReadTag(der::kOctetString, &response))
410 return false;
411 if (!ParseBasicOCSPResponse(response, out))
412 return false;
413 if (bytes_parser.HasMore())
414 return false;
415 }
416
417 return !parser.HasMore();
418 }
419
420 namespace {
421
422 // Checks that the |type| hash of |value| is equal to |hash|
423 bool VerifyHash(HashValueTag type,
424 const der::Input& hash,
425 const der::Input& value) {
426 HashValue target(type);
427 if (target.size() != hash.Length())
428 return false;
429 memcpy(target.data(), hash.UnsafeData(), target.size());
430
431 HashValue value_hash(type);
432 if (type == HASH_VALUE_SHA1) {
433 base::SHA1HashBytes(value.UnsafeData(), value.Length(), value_hash.data());
434 } else if (type == HASH_VALUE_SHA256) {
435 std::string hash_string = crypto::SHA256HashString(value.AsString());
436 memcpy(value_hash.data(), hash_string.data(), value_hash.size());
437 } else {
438 return false;
439 }
440
441 return target.Equals(value_hash);
442 }
443
444 // Checks that the input |id_tlv| parses to a valid CertID and matches the
445 // issuer |issuer| name and key, as well as the serial number |serial_number|.
446 bool CheckCertID(const der::Input& id_tlv,
447 const ParsedTbsCertificate& certificate,
448 const ParsedTbsCertificate& issuer,
449 const der::Input& serial_number) {
450 OCSPCertID id;
451 if (!ParseOCSPCertID(id_tlv, &id))
452 return false;
453
454 HashValueTag type = HASH_VALUE_SHA1;
455 switch (id.hash_algorithm) {
456 case DigestAlgorithm::Sha1:
457 type = HASH_VALUE_SHA1;
458 break;
459 case DigestAlgorithm::Sha256:
460 type = HASH_VALUE_SHA256;
461 break;
462 case DigestAlgorithm::Sha384:
463 case DigestAlgorithm::Sha512:
464 NOTIMPLEMENTED();
465 return false;
466 }
467
468 if (!VerifyHash(type, id.issuer_name_hash, certificate.issuer_tlv))
469 return false;
470
471 // SubjectPublicKeyInfo ::= SEQUENCE {
472 // algorithm AlgorithmIdentifier,
473 // subjectPublicKey BIT STRING
474 // }
475 der::Parser outer_parser(issuer.spki_tlv);
476 der::Parser spki_parser;
477 der::BitString key_bits;
478 if (!outer_parser.ReadSequence(&spki_parser))
479 return false;
480 if (outer_parser.HasMore())
481 return false;
482 if (!spki_parser.SkipTag(der::kSequence))
483 return false;
484 if (!spki_parser.ReadBitString(&key_bits))
485 return false;
486 der::Input key_tlv = key_bits.bytes();
487 if (!VerifyHash(type, id.issuer_key_hash, key_tlv))
488 return false;
489
490 return id.serial_number == serial_number;
491 }
492
493 } // namespace
494
495 bool GetOCSPCertStatus(const OCSPResponseData& response_data,
496 const ParsedCertificate& issuer,
497 const ParsedCertificate& cert,
498 OCSPCertStatus* out) {
499 out->status = OCSPCertStatus::Status::GOOD;
500
501 ParsedTbsCertificate tbs_cert;
502 if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs_cert))
503 return false;
504 ParsedTbsCertificate issuer_tbs_cert;
505 if (!ParseTbsCertificate(issuer.tbs_certificate_tlv, &issuer_tbs_cert))
506 return false;
507
508 bool found = false;
509 for (const auto& response : response_data.responses) {
510 OCSPSingleResponse single_response;
511 if (!ParseOCSPSingleResponse(response, &single_response))
512 return false;
513 if (CheckCertID(single_response.cert_id_tlv, tbs_cert, issuer_tbs_cert,
514 tbs_cert.serial_number)) {
515 OCSPCertStatus new_status = single_response.cert_status;
516 found = true;
517 // In the case that we receive multiple responses, we keep only the
518 // strictest status (REVOKED > UNKNOWN > GOOD).
519 if (out->status == OCSPCertStatus::Status::GOOD ||
520 new_status.status == OCSPCertStatus::Status::REVOKED) {
521 *out = new_status;
522 }
523 }
524 }
525
526 if (!found)
527 out->status = OCSPCertStatus::Status::UNKNOWN;
528
529 return found;
530 }
531
532 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698