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

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

Issue 1541213002: Adding OCSP Parser (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing cert comments. Created 4 years, 10 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_ocsp.h ('k') | net/cert/internal/parse_ocsp_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
(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/extended_key_usage.h"
10 #include "net/cert/internal/parse_ocsp.h"
11 #include "net/cert/internal/signature_policy.h"
12 #include "net/cert/internal/verify_name_match.h"
13 #include "net/cert/internal/verify_signed_data.h"
14
15 namespace net {
16
17 OCSPCertID::OCSPCertID() {}
18 OCSPCertID::~OCSPCertID() {}
19
20 OCSPSingleResponse::OCSPSingleResponse() {}
21 OCSPSingleResponse::~OCSPSingleResponse() {}
22
23 OCSPResponseData::OCSPResponseData() {}
24 OCSPResponseData::~OCSPResponseData() {}
25
26 OCSPResponse::OCSPResponse() {}
27 OCSPResponse::~OCSPResponse() {}
28
29 der::Input BasicOCSPResponseOid() {
30 // From RFC 6960:
31 //
32 // id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp }
33 // id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
34 //
35 // In dotted notation: 1.3.6.1.5.5.7.48.1.1
36 static const uint8_t oid[] = {0x2b, 0x06, 0x01, 0x05, 0x05,
37 0x07, 0x30, 0x01, 0x01};
38 return der::Input(oid);
39 }
40
41 // CertID ::= SEQUENCE {
42 // hashAlgorithm AlgorithmIdentifier,
43 // issuerNameHash OCTET STRING, -- Hash of issuer's DN
44 // issuerKeyHash OCTET STRING, -- Hash of issuer's public key
45 // serialNumber CertificateSerialNumber
46 // }
47 bool ParseOCSPCertID(const der::Input& raw_tlv, OCSPCertID* out) {
48 der::Parser outer_parser(raw_tlv);
49 der::Parser parser;
50 if (!outer_parser.ReadSequence(&parser))
51 return false;
52 if (outer_parser.HasMore())
53 return false;
54
55 der::Input sigalg_tlv;
56 if (!parser.ReadRawTLV(&sigalg_tlv))
57 return false;
58 if (!ParseHashAlgorithm(sigalg_tlv, &(out->hash_algorithm)))
59 return false;
60 if (!parser.ReadTag(der::kOctetString, &(out->issuer_name_hash)))
61 return false;
62 if (!parser.ReadTag(der::kOctetString, &(out->issuer_key_hash)))
63 return false;
64 if (!parser.ReadTag(der::kInteger, &(out->serial_number)))
65 return false;
66 if (!VerifySerialNumber(out->serial_number))
67 return false;
68
69 return !parser.HasMore();
70 }
71
72 namespace {
73
74 // Parses |raw_tlv| to extract an OCSP RevokedInfo (RFC 6960) and stores the
75 // result in the OCSPCertStatus |out|. Returns whether the parsing was
76 // successful.
77 //
78 // RevokedInfo ::= SEQUENCE {
79 // revocationTime GeneralizedTime,
80 // revocationReason [0] EXPLICIT CRLReason OPTIONAL
81 // }
82 bool ParseRevokedInfo(const der::Input& raw_tlv, OCSPCertStatus* out) {
83 der::Parser parser(raw_tlv);
84 if (!parser.ReadGeneralizedTime(&(out->revocation_time)))
85 return false;
86
87 der::Input reason_input;
88 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &reason_input,
89 &(out->has_reason))) {
90 return false;
91 }
92 if (out->has_reason) {
93 der::Parser reason_parser(reason_input);
94 der::Input reason_value_input;
95 uint8_t reason_value;
96 if (!reason_parser.ReadTag(der::kEnumerated, &reason_value_input))
97 return false;
98 if (!der::ParseUint8(reason_value_input, &reason_value))
99 return false;
100 if (reason_value >
101 static_cast<uint8_t>(OCSPCertStatus::RevocationReason::LAST)) {
102 return false;
103 }
104 out->revocation_reason =
105 static_cast<OCSPCertStatus::RevocationReason>(reason_value);
106 if (out->revocation_reason == OCSPCertStatus::RevocationReason::UNUSED)
107 return false;
108 if (reason_parser.HasMore())
109 return false;
110 }
111 return !parser.HasMore();
112 }
113
114 // Parses |raw_tlv| to extract an OCSP CertStatus (RFC 6960) and stores the
115 // result in the OCSPCertStatus |out|. Returns whether the parsing was
116 // successful.
117 //
118 // CertStatus ::= CHOICE {
119 // good [0] IMPLICIT NULL,
120 // revoked [1] IMPLICIT RevokedInfo,
121 // unknown [2] IMPLICIT UnknownInfo
122 // }
123 //
124 // UnknownInfo ::= NULL
125 bool ParseCertStatus(const der::Input& raw_tlv, OCSPCertStatus* out) {
126 der::Parser parser(raw_tlv);
127 der::Tag status_tag;
128 der::Input status;
129 if (!parser.ReadTagAndValue(&status_tag, &status))
130 return false;
131
132 out->has_reason = false;
133 if (status_tag == der::ContextSpecificPrimitive(0)) {
134 out->status = OCSPCertStatus::Status::GOOD;
135 } else if (status_tag == der::ContextSpecificConstructed(1)) {
136 out->status = OCSPCertStatus::Status::REVOKED;
137 if (!ParseRevokedInfo(status, out))
138 return false;
139 } else if (status_tag == der::ContextSpecificPrimitive(2)) {
140 out->status = OCSPCertStatus::Status::UNKNOWN;
141 } else {
142 return false;
143 }
144
145 return !parser.HasMore();
146 }
147
148 } // namespace
149
150 // SingleResponse ::= SEQUENCE {
151 // certID CertID,
152 // certStatus CertStatus,
153 // thisUpdate GeneralizedTime,
154 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
155 // singleExtensions [1] EXPLICIT Extensions OPTIONAL
156 // }
157 bool ParseOCSPSingleResponse(const der::Input& raw_tlv,
158 OCSPSingleResponse* out) {
159 der::Parser outer_parser(raw_tlv);
160 der::Parser parser;
161 if (!outer_parser.ReadSequence(&parser))
162 return false;
163 if (outer_parser.HasMore())
164 return false;
165
166 if (!parser.ReadRawTLV(&(out->cert_id_tlv)))
167 return false;
168 der::Input status_tlv;
169 if (!parser.ReadRawTLV(&status_tlv))
170 return false;
171 if (!ParseCertStatus(status_tlv, &(out->cert_status)))
172 return false;
173 if (!parser.ReadGeneralizedTime(&(out->this_update)))
174 return false;
175
176 der::Input next_update_input;
177 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0),
178 &next_update_input, &(out->has_next_update))) {
179 return false;
180 }
181 if (out->has_next_update) {
182 der::Parser next_update_parser(next_update_input);
183 if (!next_update_parser.ReadGeneralizedTime(&(out->next_update)))
184 return false;
185 if (next_update_parser.HasMore())
186 return false;
187 }
188
189 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(1),
190 &(out->extensions), &(out->has_extensions))) {
191 return false;
192 }
193
194 return !parser.HasMore();
195 }
196
197 namespace {
198
199 // Parses |raw_tlv| to extract a ResponderID (RFC 6960) and stores the
200 // result in the ResponderID |out|. Returns whether the parsing was successful.
201 //
202 // ResponderID ::= CHOICE {
203 // byName [1] Name,
204 // byKey [2] KeyHash
205 // }
206 bool ParseResponderID(const der::Input& raw_tlv,
207 OCSPResponseData::ResponderID* out) {
208 der::Parser parser(raw_tlv);
209 der::Tag id_tag;
210 der::Input id_input;
211 if (!parser.ReadTagAndValue(&id_tag, &id_input))
212 return false;
213
214 if (id_tag == der::ContextSpecificConstructed(1)) {
215 out->type = OCSPResponseData::ResponderType::NAME;
216 out->name = id_input;
217 } else if (id_tag == der::ContextSpecificConstructed(2)) {
218 der::Parser key_parser(id_input);
219 der::Input responder_key;
220 if (!key_parser.ReadTag(der::kOctetString, &responder_key))
221 return false;
222 if (key_parser.HasMore())
223 return false;
224
225 SHA1HashValue key_hash;
226 if (responder_key.Length() != sizeof(key_hash.data))
227 return false;
228 memcpy(key_hash.data, responder_key.UnsafeData(), sizeof(key_hash.data));
229 out->type = OCSPResponseData::ResponderType::KEY_HASH;
230 out->key_hash = HashValue(key_hash);
231 } else {
232 return false;
233 }
234 return !parser.HasMore();
235 }
236
237 } // namespace
238
239 // ResponseData ::= SEQUENCE {
240 // version [0] EXPLICIT Version DEFAULT v1,
241 // responderID ResponderID,
242 // producedAt GeneralizedTime,
243 // responses SEQUENCE OF SingleResponse,
244 // responseExtensions [1] EXPLICIT Extensions OPTIONAL
245 // }
246 bool ParseOCSPResponseData(const der::Input& raw_tlv, OCSPResponseData* out) {
247 der::Parser outer_parser(raw_tlv);
248 der::Parser parser;
249 if (!outer_parser.ReadSequence(&parser))
250 return false;
251 if (outer_parser.HasMore())
252 return false;
253
254 der::Input version_input;
255 bool version_present;
256 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0),
257 &version_input, &version_present)) {
258 return false;
259 }
260
261 // For compatibilty, we ignore the restriction from X.690 Section 11.5 that
262 // DEFAULT values should be omitted for values equal to the default value.
263 // TODO: Add warning about non-strict parsing.
264 if (version_present) {
265 der::Parser version_parser(version_input);
266 if (!version_parser.ReadUint8(&(out->version)))
eroman 2016/02/23 22:29:03 Where is the version number being checked? RFC 696
svaldez 2016/02/24 16:44:37 Adding a check. It looks like we don't have any ca
267 return false;
268 if (version_parser.HasMore())
269 return false;
270 } else {
271 out->version = 0;
272 }
273
274 der::Input responder_input;
275 if (!parser.ReadRawTLV(&responder_input))
276 return false;
277 if (!ParseResponderID(responder_input, &(out->responder_id)))
278 return false;
279 if (!parser.ReadGeneralizedTime(&(out->produced_at)))
280 return false;
281
282 der::Parser responses_parser;
283 if (!parser.ReadSequence(&responses_parser))
284 return false;
285 out->responses.clear();
286 while (responses_parser.HasMore()) {
287 der::Input single_response;
288 if (!responses_parser.ReadRawTLV(&single_response))
289 return false;
290 out->responses.push_back(single_response);
291 }
292
293 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(1),
294 &(out->extensions), &(out->has_extensions))) {
295 return false;
296 }
297
298 return !parser.HasMore();
299 }
300
301 namespace {
302
303 // Parses |raw_tlv| to extract a BasicOCSPResponse (RFC 6960) and stores the
304 // result in the OCSPResponse |out|. Returns whether the parsing was
305 // successful.
306 //
307 // BasicOCSPResponse ::= SEQUENCE {
308 // tbsResponseData ResponseData,
309 // signatureAlgorithm AlgorithmIdentifier,
310 // signature BIT STRING,
311 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
312 // }
313 bool ParseBasicOCSPResponse(const der::Input& raw_tlv, OCSPResponse* out) {
314 der::Parser outer_parser(raw_tlv);
315 der::Parser parser;
316 if (!outer_parser.ReadSequence(&parser))
317 return false;
318 if (outer_parser.HasMore())
319 return false;
320
321 if (!parser.ReadRawTLV(&(out->data)))
322 return false;
323 der::Input sigalg_tlv;
324 if (!parser.ReadRawTLV(&sigalg_tlv))
325 return false;
326 out->signature_algorithm = SignatureAlgorithm::CreateFromDer(sigalg_tlv);
327 if (!out->signature_algorithm)
328 return false;
329 if (!parser.ReadBitString(&(out->signature)))
330 return false;
331 der::Input certs_input;
332 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &certs_input,
333 &(out->has_certs))) {
334 return false;
335 }
336
337 out->certs.clear();
338 if (out->has_certs) {
339 der::Parser certs_seq_parser(certs_input);
340 der::Parser certs_parser;
341 if (!certs_seq_parser.ReadSequence(&certs_parser))
342 return false;
343 if (certs_seq_parser.HasMore())
344 return false;
345 while (certs_parser.HasMore()) {
346 der::Input cert_tlv;
347 if (!certs_parser.ReadRawTLV(&cert_tlv))
348 return false;
349 out->certs.push_back(cert_tlv);
350 }
351 }
352
353 return !parser.HasMore();
354 }
355
356 } // namespace
357
358 // OCSPResponse ::= SEQUENCE {
359 // responseStatus OCSPResponseStatus,
360 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL
361 // }
362 //
363 // ResponseBytes ::= SEQUENCE {
364 // responseType OBJECT IDENTIFIER,
365 // response OCTET STRING
366 // }
367 bool ParseOCSPResponse(const der::Input& raw_tlv, OCSPResponse* out) {
368 der::Parser outer_parser(raw_tlv);
369 der::Parser parser;
370 if (!outer_parser.ReadSequence(&parser))
371 return false;
372 if (outer_parser.HasMore())
373 return false;
374
375 der::Input response_status_input;
376 uint8_t response_status;
377 if (!parser.ReadTag(der::kEnumerated, &response_status_input))
378 return false;
379 if (!der::ParseUint8(response_status_input, &response_status))
380 return false;
381 if (response_status >
382 static_cast<uint8_t>(OCSPResponse::ResponseStatus::LAST)) {
383 return false;
384 }
385 out->status = static_cast<OCSPResponse::ResponseStatus>(response_status);
386 if (out->status == OCSPResponse::ResponseStatus::UNUSED)
387 return false;
388
389 if (out->status == OCSPResponse::ResponseStatus::SUCCESSFUL) {
390 der::Parser outer_bytes_parser;
391 der::Parser bytes_parser;
392 if (!parser.ReadConstructed(der::ContextSpecificConstructed(0),
393 &outer_bytes_parser)) {
394 return false;
395 }
396 if (!outer_bytes_parser.ReadSequence(&bytes_parser))
397 return false;
398 if (outer_bytes_parser.HasMore())
399 return false;
400
401 der::Input type_oid;
402 if (!bytes_parser.ReadTag(der::kOid, &type_oid))
403 return false;
404 if (type_oid != BasicOCSPResponseOid())
405 return false;
406
407 // As per RFC 6960 Section 4.2.1, the value of |response| SHALL be the DER
408 // encoding of BasicOCSPResponse.
409 der::Input response;
410 if (!bytes_parser.ReadTag(der::kOctetString, &response))
411 return false;
412 if (!ParseBasicOCSPResponse(response, out))
413 return false;
414 if (bytes_parser.HasMore())
415 return false;
416 }
417
418 return !parser.HasMore();
419 }
420
421 namespace {
422
423 // Checks that the |type| hash of |value| is equal to |hash|
424 bool VerifyHash(HashValueTag type,
425 const der::Input& hash,
426 const der::Input& value) {
427 HashValue target(type);
428 if (target.size() != hash.Length())
429 return false;
430 memcpy(target.data(), hash.UnsafeData(), target.size());
431
432 HashValue value_hash(type);
433 if (type == HASH_VALUE_SHA1) {
434 base::SHA1HashBytes(value.UnsafeData(), value.Length(), value_hash.data());
435 } else if (type == HASH_VALUE_SHA256) {
436 std::string hash_string = crypto::SHA256HashString(value.AsString());
437 memcpy(value_hash.data(), hash_string.data(), value_hash.size());
438 } else {
439 return false;
440 }
441
442 return target.Equals(value_hash);
443 }
444
445 // Checks that the input |id_tlv| parses to a valid CertID and matches the
446 // issuer |issuer| and serial number |serial_number|.
447 bool CheckCertID(const der::Input& id_tlv,
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;
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, issuer.subject_tlv))
469 return false;
470
471 der::Parser outer_parser(issuer.spki_tlv);
472 der::Parser spki_parser;
473 der::BitString key_bits;
474 if (!outer_parser.ReadSequence(&spki_parser))
475 return false;
476 if (outer_parser.HasMore())
477 return false;
478 if (!spki_parser.SkipTag(der::kSequence))
479 return false;
480 if (!spki_parser.ReadBitString(&key_bits))
481 return false;
482 der::Input key_tlv = key_bits.bytes();
483 if (!VerifyHash(type, id.issuer_key_hash, key_tlv))
484 return false;
485
486 return id.serial_number == serial_number;
487 }
488
489 } // namespace
490
491 bool GetOCSPCertStatus(const OCSPResponseData& response_data,
492 const ParsedCertificate& issuer,
493 const ParsedCertificate& cert,
494 OCSPCertStatus* out) {
495 out->status = OCSPCertStatus::Status::UNKNOWN;
496
497 ParsedTbsCertificate tbs_cert;
498 if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs_cert))
499 return false;
500 ParsedTbsCertificate issuer_tbs_cert;
501 if (!ParseTbsCertificate(issuer.tbs_certificate_tlv, &issuer_tbs_cert))
502 return false;
503
504 for (const auto& response : response_data.responses) {
505 OCSPSingleResponse single_response;
506 if (!ParseOCSPSingleResponse(response, &single_response))
507 return false;
508 if (CheckCertID(single_response.cert_id_tlv, issuer_tbs_cert,
509 tbs_cert.serial_number)) {
510 *out = single_response.cert_status;
511 if (single_response.cert_status.status != OCSPCertStatus::Status::GOOD)
512 return true;
513 }
514 }
515
516 return true;
517 }
518
519 // Verify Code Below (MOVING TO SEPARATE CL)
eroman 2016/02/23 22:29:03 What is the resolution to this comment?
svaldez 2016/02/24 16:44:37 Will end up removing right before committing, sinc
eroman 2016/02/25 00:15:59 This is easily managed through git. Create a new b
520
521 namespace {
522
523 // Checks that the ResponderID |id| matches the certificate |cert|.
524 bool CheckResponder(const OCSPResponseData::ResponderID& id,
525 const ParsedTbsCertificate& cert) {
526 if (id.type == OCSPResponseData::ResponderType::NAME) {
527 der::Input name_rdn;
528 der::Input cert_rdn;
529 if (!der::Parser(id.name).ReadTag(der::kSequence, &name_rdn) ||
530 !der::Parser(cert.subject_tlv).ReadTag(der::kSequence, &cert_rdn))
531 return false;
532 return VerifyNameMatch(name_rdn, cert_rdn);
533 } else {
534 der::Parser parser(cert.spki_tlv);
535 der::Parser spki_parser;
536 der::BitString key_bits;
537 if (!parser.ReadSequence(&spki_parser))
538 return false;
539 if (!spki_parser.SkipTag(der::kSequence))
540 return false;
541 if (!spki_parser.ReadBitString(&key_bits))
542 return false;
543
544 der::Input key = key_bits.bytes();
545 HashValue key_hash(HASH_VALUE_SHA1);
546 base::SHA1HashBytes(key.UnsafeData(), key.Length(), key_hash.data());
547 return key_hash.Equals(id.key_hash);
548 }
549 }
550
551 } // namespace
552
553 bool VerifyOCSPResponse(const OCSPResponse& response,
554 const ParsedCertificate& issuer_cert) {
555 SimpleSignaturePolicy signature_policy(1024);
556
557 OCSPResponseData response_data;
558 if (!ParseOCSPResponseData(response.data, &response_data))
559 return false;
560
561 ParsedTbsCertificate issuer;
562 ParsedTbsCertificate responder;
563 if (!ParseTbsCertificate(issuer_cert.tbs_certificate_tlv, &issuer))
564 return false;
565
566 if (CheckResponder(response_data.responder_id, issuer)) {
567 responder = issuer;
568 } else {
569 bool found = false;
570 for (const auto& responder_cert_tlv : response.certs) {
571 ParsedCertificate responder_cert;
572 ParsedTbsCertificate tbs_cert;
573 if (!ParseCertificate(responder_cert_tlv, &responder_cert))
574 return false;
575 if (!ParseTbsCertificate(responder_cert.tbs_certificate_tlv, &tbs_cert))
576 return false;
577
578 if (CheckResponder(response_data.responder_id, tbs_cert)) {
579 found = true;
580 responder = tbs_cert;
581
582 scoped_ptr<SignatureAlgorithm> signature_algorithm =
583 SignatureAlgorithm::CreateFromDer(
584 responder_cert.signature_algorithm_tlv);
585 if (!signature_algorithm)
586 return false;
587 der::Input issuer_spki = issuer.spki_tlv;
588 if (!VerifySignedData(*signature_algorithm,
589 responder_cert.tbs_certificate_tlv,
590 responder_cert.signature_value, issuer_spki,
591 &signature_policy)) {
592 return false;
593 }
594
595 std::map<der::Input, ParsedExtension> extensions;
596 std::vector<der::Input> eku;
597 if (!ParseExtensions(responder.extensions_tlv, &extensions))
598 return false;
599 if (!ParseEKUExtension(extensions[ExtKeyUsageOid()].value, &eku))
600 return false;
601 if (std::find(eku.begin(), eku.end(), OCSPSigning()) == eku.end())
602 return false;
603 break;
604 }
605 }
606 if (!found)
607 return false;
608 }
609 return VerifySignedData(*(response.signature_algorithm), response.data,
610 response.signature, responder.spki_tlv,
611 &signature_policy);
612 }
613
614 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/internal/parse_ocsp.h ('k') | net/cert/internal/parse_ocsp_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698