Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 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/ocsp.h" | |
| 6 | |
| 5 #include <algorithm> | 7 #include <algorithm> |
| 6 | 8 |
| 7 #include "base/sha1.h" | 9 #include "base/sha1.h" |
| 8 #include "crypto/sha2.h" | 10 #include "crypto/sha2.h" |
| 9 #include "net/cert/internal/parse_ocsp.h" | 11 #include "net/cert/internal/extended_key_usage.h" |
| 12 #include "net/cert/internal/verify_name_match.h" | |
| 13 #include "net/cert/internal/verify_signed_data.h" | |
| 10 | 14 |
| 11 namespace net { | 15 namespace net { |
| 12 | 16 |
| 13 OCSPCertID::OCSPCertID() {} | 17 OCSPCertID::OCSPCertID() {} |
| 14 OCSPCertID::~OCSPCertID() {} | 18 OCSPCertID::~OCSPCertID() {} |
| 15 | 19 |
| 16 OCSPSingleResponse::OCSPSingleResponse() {} | 20 OCSPSingleResponse::OCSPSingleResponse() {} |
| 17 OCSPSingleResponse::~OCSPSingleResponse() {} | 21 OCSPSingleResponse::~OCSPSingleResponse() {} |
| 18 | 22 |
| 19 OCSPResponseData::OCSPResponseData() {} | 23 OCSPResponseData::OCSPResponseData() {} |
| 20 OCSPResponseData::~OCSPResponseData() {} | 24 OCSPResponseData::~OCSPResponseData() {} |
| 21 | 25 |
| 22 OCSPResponse::OCSPResponse() {} | 26 OCSPResponse::OCSPResponse() {} |
| 23 OCSPResponse::~OCSPResponse() {} | 27 OCSPResponse::~OCSPResponse() {} |
| 24 | 28 |
| 25 der::Input BasicOCSPResponseOid() { | 29 WARN_UNUSED_RESULT der::Input BasicOCSPResponseOid() { |
| 26 // From RFC 6960: | 30 // From RFC 6960: |
| 27 // | 31 // |
| 28 // id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp } | 32 // id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp } |
| 29 // id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } | 33 // id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } |
| 30 // | 34 // |
| 31 // In dotted notation: 1.3.6.1.5.5.7.48.1.1 | 35 // In dotted notation: 1.3.6.1.5.5.7.48.1.1 |
| 32 static const uint8_t oid[] = {0x2b, 0x06, 0x01, 0x05, 0x05, | 36 static const uint8_t oid[] = {0x2b, 0x06, 0x01, 0x05, 0x05, |
| 33 0x07, 0x30, 0x01, 0x01}; | 37 0x07, 0x30, 0x01, 0x01}; |
| 34 return der::Input(oid); | 38 return der::Input(oid); |
| 35 } | 39 } |
| 36 | 40 |
| 37 // CertID ::= SEQUENCE { | 41 // CertID ::= SEQUENCE { |
| 38 // hashAlgorithm AlgorithmIdentifier, | 42 // hashAlgorithm AlgorithmIdentifier, |
| 39 // issuerNameHash OCTET STRING, -- Hash of issuer's DN | 43 // issuerNameHash OCTET STRING, -- Hash of issuer's DN |
| 40 // issuerKeyHash OCTET STRING, -- Hash of issuer's public key | 44 // issuerKeyHash OCTET STRING, -- Hash of issuer's public key |
| 41 // serialNumber CertificateSerialNumber | 45 // serialNumber CertificateSerialNumber |
| 42 // } | 46 // } |
| 43 bool ParseOCSPCertID(const der::Input& raw_tlv, OCSPCertID* out) { | 47 WARN_UNUSED_RESULT bool ParseOCSPCertID(const der::Input& raw_tlv, |
| 48 OCSPCertID* out) { | |
| 44 der::Parser outer_parser(raw_tlv); | 49 der::Parser outer_parser(raw_tlv); |
| 45 der::Parser parser; | 50 der::Parser parser; |
| 46 if (!outer_parser.ReadSequence(&parser)) | 51 if (!outer_parser.ReadSequence(&parser)) |
| 47 return false; | 52 return false; |
| 48 if (outer_parser.HasMore()) | 53 if (outer_parser.HasMore()) |
| 49 return false; | 54 return false; |
| 50 | 55 |
| 51 der::Input sigalg_tlv; | 56 der::Input sigalg_tlv; |
| 52 if (!parser.ReadRawTLV(&sigalg_tlv)) | 57 if (!parser.ReadRawTLV(&sigalg_tlv)) |
| 53 return false; | 58 return false; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 68 namespace { | 73 namespace { |
| 69 | 74 |
| 70 // Parses |raw_tlv| to extract an OCSP RevokedInfo (RFC 6960) and stores the | 75 // Parses |raw_tlv| to extract an OCSP RevokedInfo (RFC 6960) and stores the |
| 71 // result in the OCSPCertStatus |out|. Returns whether the parsing was | 76 // result in the OCSPCertStatus |out|. Returns whether the parsing was |
| 72 // successful. | 77 // successful. |
| 73 // | 78 // |
| 74 // RevokedInfo ::= SEQUENCE { | 79 // RevokedInfo ::= SEQUENCE { |
| 75 // revocationTime GeneralizedTime, | 80 // revocationTime GeneralizedTime, |
| 76 // revocationReason [0] EXPLICIT CRLReason OPTIONAL | 81 // revocationReason [0] EXPLICIT CRLReason OPTIONAL |
| 77 // } | 82 // } |
| 78 bool ParseRevokedInfo(const der::Input& raw_tlv, OCSPCertStatus* out) { | 83 WARN_UNUSED_RESULT bool ParseRevokedInfo(const der::Input& raw_tlv, |
| 84 OCSPCertStatus* out) { | |
| 79 der::Parser parser(raw_tlv); | 85 der::Parser parser(raw_tlv); |
| 80 if (!parser.ReadGeneralizedTime(&(out->revocation_time))) | 86 if (!parser.ReadGeneralizedTime(&(out->revocation_time))) |
| 81 return false; | 87 return false; |
| 82 | 88 |
| 83 der::Input reason_input; | 89 der::Input reason_input; |
| 84 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &reason_input, | 90 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &reason_input, |
| 85 &(out->has_reason))) { | 91 &(out->has_reason))) { |
| 86 return false; | 92 return false; |
| 87 } | 93 } |
| 88 if (out->has_reason) { | 94 if (out->has_reason) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 111 // result in the OCSPCertStatus |out|. Returns whether the parsing was | 117 // result in the OCSPCertStatus |out|. Returns whether the parsing was |
| 112 // successful. | 118 // successful. |
| 113 // | 119 // |
| 114 // CertStatus ::= CHOICE { | 120 // CertStatus ::= CHOICE { |
| 115 // good [0] IMPLICIT NULL, | 121 // good [0] IMPLICIT NULL, |
| 116 // revoked [1] IMPLICIT RevokedInfo, | 122 // revoked [1] IMPLICIT RevokedInfo, |
| 117 // unknown [2] IMPLICIT UnknownInfo | 123 // unknown [2] IMPLICIT UnknownInfo |
| 118 // } | 124 // } |
| 119 // | 125 // |
| 120 // UnknownInfo ::= NULL | 126 // UnknownInfo ::= NULL |
| 121 bool ParseCertStatus(const der::Input& raw_tlv, OCSPCertStatus* out) { | 127 WARN_UNUSED_RESULT bool ParseCertStatus(const der::Input& raw_tlv, |
| 128 OCSPCertStatus* out) { | |
| 122 der::Parser parser(raw_tlv); | 129 der::Parser parser(raw_tlv); |
| 123 der::Tag status_tag; | 130 der::Tag status_tag; |
| 124 der::Input status; | 131 der::Input status; |
| 125 if (!parser.ReadTagAndValue(&status_tag, &status)) | 132 if (!parser.ReadTagAndValue(&status_tag, &status)) |
| 126 return false; | 133 return false; |
| 127 | 134 |
| 128 out->has_reason = false; | 135 out->has_reason = false; |
| 129 if (status_tag == der::ContextSpecificPrimitive(0)) { | 136 if (status_tag == der::ContextSpecificPrimitive(0)) { |
| 130 out->status = OCSPCertStatus::Status::GOOD; | 137 out->status = OCSPCertStatus::Status::GOOD; |
| 131 } else if (status_tag == der::ContextSpecificConstructed(1)) { | 138 } else if (status_tag == der::ContextSpecificConstructed(1)) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 143 | 150 |
| 144 } // namespace | 151 } // namespace |
| 145 | 152 |
| 146 // SingleResponse ::= SEQUENCE { | 153 // SingleResponse ::= SEQUENCE { |
| 147 // certID CertID, | 154 // certID CertID, |
| 148 // certStatus CertStatus, | 155 // certStatus CertStatus, |
| 149 // thisUpdate GeneralizedTime, | 156 // thisUpdate GeneralizedTime, |
| 150 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, | 157 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, |
| 151 // singleExtensions [1] EXPLICIT Extensions OPTIONAL | 158 // singleExtensions [1] EXPLICIT Extensions OPTIONAL |
| 152 // } | 159 // } |
| 153 bool ParseOCSPSingleResponse(const der::Input& raw_tlv, | 160 WARN_UNUSED_RESULT bool ParseOCSPSingleResponse(const der::Input& raw_tlv, |
| 154 OCSPSingleResponse* out) { | 161 OCSPSingleResponse* out) { |
| 155 der::Parser outer_parser(raw_tlv); | 162 der::Parser outer_parser(raw_tlv); |
| 156 der::Parser parser; | 163 der::Parser parser; |
| 157 if (!outer_parser.ReadSequence(&parser)) | 164 if (!outer_parser.ReadSequence(&parser)) |
| 158 return false; | 165 return false; |
| 159 if (outer_parser.HasMore()) | 166 if (outer_parser.HasMore()) |
| 160 return false; | 167 return false; |
| 161 | 168 |
| 162 if (!parser.ReadRawTLV(&(out->cert_id_tlv))) | 169 if (!parser.ReadRawTLV(&(out->cert_id_tlv))) |
| 163 return false; | 170 return false; |
| 164 der::Input status_tlv; | 171 der::Input status_tlv; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 192 | 199 |
| 193 namespace { | 200 namespace { |
| 194 | 201 |
| 195 // Parses |raw_tlv| to extract a ResponderID (RFC 6960) and stores the | 202 // Parses |raw_tlv| to extract a ResponderID (RFC 6960) and stores the |
| 196 // result in the ResponderID |out|. Returns whether the parsing was successful. | 203 // result in the ResponderID |out|. Returns whether the parsing was successful. |
| 197 // | 204 // |
| 198 // ResponderID ::= CHOICE { | 205 // ResponderID ::= CHOICE { |
| 199 // byName [1] Name, | 206 // byName [1] Name, |
| 200 // byKey [2] KeyHash | 207 // byKey [2] KeyHash |
| 201 // } | 208 // } |
| 202 bool ParseResponderID(const der::Input& raw_tlv, | 209 WARN_UNUSED_RESULT bool ParseResponderID(const der::Input& raw_tlv, |
| 203 OCSPResponseData::ResponderID* out) { | 210 OCSPResponseData::ResponderID* out) { |
| 204 der::Parser parser(raw_tlv); | 211 der::Parser parser(raw_tlv); |
| 205 der::Tag id_tag; | 212 der::Tag id_tag; |
| 206 der::Input id_input; | 213 der::Input id_input; |
| 207 if (!parser.ReadTagAndValue(&id_tag, &id_input)) | 214 if (!parser.ReadTagAndValue(&id_tag, &id_input)) |
| 208 return false; | 215 return false; |
| 209 | 216 |
| 210 if (id_tag == der::ContextSpecificConstructed(1)) { | 217 if (id_tag == der::ContextSpecificConstructed(1)) { |
| 211 out->type = OCSPResponseData::ResponderType::NAME; | 218 out->type = OCSPResponseData::ResponderType::NAME; |
| 212 out->name = id_input; | 219 out->name = id_input; |
| 213 } else if (id_tag == der::ContextSpecificConstructed(2)) { | 220 } else if (id_tag == der::ContextSpecificConstructed(2)) { |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 232 | 239 |
| 233 } // namespace | 240 } // namespace |
| 234 | 241 |
| 235 // ResponseData ::= SEQUENCE { | 242 // ResponseData ::= SEQUENCE { |
| 236 // version [0] EXPLICIT Version DEFAULT v1, | 243 // version [0] EXPLICIT Version DEFAULT v1, |
| 237 // responderID ResponderID, | 244 // responderID ResponderID, |
| 238 // producedAt GeneralizedTime, | 245 // producedAt GeneralizedTime, |
| 239 // responses SEQUENCE OF SingleResponse, | 246 // responses SEQUENCE OF SingleResponse, |
| 240 // responseExtensions [1] EXPLICIT Extensions OPTIONAL | 247 // responseExtensions [1] EXPLICIT Extensions OPTIONAL |
| 241 // } | 248 // } |
| 242 bool ParseOCSPResponseData(const der::Input& raw_tlv, OCSPResponseData* out) { | 249 WARN_UNUSED_RESULT bool ParseOCSPResponseData(const der::Input& raw_tlv, |
| 250 OCSPResponseData* out) { | |
| 243 der::Parser outer_parser(raw_tlv); | 251 der::Parser outer_parser(raw_tlv); |
| 244 der::Parser parser; | 252 der::Parser parser; |
| 245 if (!outer_parser.ReadSequence(&parser)) | 253 if (!outer_parser.ReadSequence(&parser)) |
| 246 return false; | 254 return false; |
| 247 if (outer_parser.HasMore()) | 255 if (outer_parser.HasMore()) |
| 248 return false; | 256 return false; |
| 249 | 257 |
| 250 der::Input version_input; | 258 der::Input version_input; |
| 251 bool version_present; | 259 bool version_present; |
| 252 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), | 260 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 302 // Parses |raw_tlv| to extract a BasicOCSPResponse (RFC 6960) and stores the | 310 // Parses |raw_tlv| to extract a BasicOCSPResponse (RFC 6960) and stores the |
| 303 // result in the OCSPResponse |out|. Returns whether the parsing was | 311 // result in the OCSPResponse |out|. Returns whether the parsing was |
| 304 // successful. | 312 // successful. |
| 305 // | 313 // |
| 306 // BasicOCSPResponse ::= SEQUENCE { | 314 // BasicOCSPResponse ::= SEQUENCE { |
| 307 // tbsResponseData ResponseData, | 315 // tbsResponseData ResponseData, |
| 308 // signatureAlgorithm AlgorithmIdentifier, | 316 // signatureAlgorithm AlgorithmIdentifier, |
| 309 // signature BIT STRING, | 317 // signature BIT STRING, |
| 310 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL | 318 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL |
| 311 // } | 319 // } |
| 312 bool ParseBasicOCSPResponse(const der::Input& raw_tlv, OCSPResponse* out) { | 320 WARN_UNUSED_RESULT bool ParseBasicOCSPResponse(const der::Input& raw_tlv, |
| 321 OCSPResponse* out) { | |
| 313 der::Parser outer_parser(raw_tlv); | 322 der::Parser outer_parser(raw_tlv); |
| 314 der::Parser parser; | 323 der::Parser parser; |
| 315 if (!outer_parser.ReadSequence(&parser)) | 324 if (!outer_parser.ReadSequence(&parser)) |
| 316 return false; | 325 return false; |
| 317 if (outer_parser.HasMore()) | 326 if (outer_parser.HasMore()) |
| 318 return false; | 327 return false; |
| 319 | 328 |
| 320 if (!parser.ReadRawTLV(&(out->data))) | 329 if (!parser.ReadRawTLV(&(out->data))) |
| 321 return false; | 330 return false; |
| 322 der::Input sigalg_tlv; | 331 der::Input sigalg_tlv; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 | 365 |
| 357 // OCSPResponse ::= SEQUENCE { | 366 // OCSPResponse ::= SEQUENCE { |
| 358 // responseStatus OCSPResponseStatus, | 367 // responseStatus OCSPResponseStatus, |
| 359 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL | 368 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL |
| 360 // } | 369 // } |
| 361 // | 370 // |
| 362 // ResponseBytes ::= SEQUENCE { | 371 // ResponseBytes ::= SEQUENCE { |
| 363 // responseType OBJECT IDENTIFIER, | 372 // responseType OBJECT IDENTIFIER, |
| 364 // response OCTET STRING | 373 // response OCTET STRING |
| 365 // } | 374 // } |
| 366 bool ParseOCSPResponse(const der::Input& raw_tlv, OCSPResponse* out) { | 375 WARN_UNUSED_RESULT bool ParseOCSPResponse(const der::Input& raw_tlv, |
| 376 OCSPResponse* out) { | |
| 367 der::Parser outer_parser(raw_tlv); | 377 der::Parser outer_parser(raw_tlv); |
| 368 der::Parser parser; | 378 der::Parser parser; |
| 369 if (!outer_parser.ReadSequence(&parser)) | 379 if (!outer_parser.ReadSequence(&parser)) |
| 370 return false; | 380 return false; |
| 371 if (outer_parser.HasMore()) | 381 if (outer_parser.HasMore()) |
| 372 return false; | 382 return false; |
| 373 | 383 |
| 374 der::Input response_status_input; | 384 der::Input response_status_input; |
| 375 uint8_t response_status; | 385 uint8_t response_status; |
| 376 if (!parser.ReadTag(der::kEnumerated, &response_status_input)) | 386 if (!parser.ReadTag(der::kEnumerated, &response_status_input)) |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 413 if (bytes_parser.HasMore()) | 423 if (bytes_parser.HasMore()) |
| 414 return false; | 424 return false; |
| 415 } | 425 } |
| 416 | 426 |
| 417 return !parser.HasMore(); | 427 return !parser.HasMore(); |
| 418 } | 428 } |
| 419 | 429 |
| 420 namespace { | 430 namespace { |
| 421 | 431 |
| 422 // Checks that the |type| hash of |value| is equal to |hash| | 432 // Checks that the |type| hash of |value| is equal to |hash| |
| 423 bool VerifyHash(HashValueTag type, | 433 WARN_UNUSED_RESULT bool VerifyHash(HashValueTag type, |
| 424 const der::Input& hash, | 434 const der::Input& hash, |
| 425 const der::Input& value) { | 435 const der::Input& value) { |
| 426 HashValue target(type); | 436 HashValue target(type); |
| 427 if (target.size() != hash.Length()) | 437 if (target.size() != hash.Length()) |
| 428 return false; | 438 return false; |
| 429 memcpy(target.data(), hash.UnsafeData(), target.size()); | 439 memcpy(target.data(), hash.UnsafeData(), target.size()); |
| 430 | 440 |
| 431 HashValue value_hash(type); | 441 HashValue value_hash(type); |
| 432 if (type == HASH_VALUE_SHA1) { | 442 if (type == HASH_VALUE_SHA1) { |
| 433 base::SHA1HashBytes(value.UnsafeData(), value.Length(), value_hash.data()); | 443 base::SHA1HashBytes(value.UnsafeData(), value.Length(), value_hash.data()); |
| 434 } else if (type == HASH_VALUE_SHA256) { | 444 } else if (type == HASH_VALUE_SHA256) { |
| 435 std::string hash_string = crypto::SHA256HashString(value.AsString()); | 445 std::string hash_string = crypto::SHA256HashString(value.AsString()); |
| 436 memcpy(value_hash.data(), hash_string.data(), value_hash.size()); | 446 memcpy(value_hash.data(), hash_string.data(), value_hash.size()); |
| 437 } else { | 447 } else { |
| 438 return false; | 448 return false; |
| 439 } | 449 } |
| 440 | 450 |
| 441 return target.Equals(value_hash); | 451 return target.Equals(value_hash); |
| 442 } | 452 } |
| 443 | 453 |
| 444 // Checks that the input |id_tlv| parses to a valid CertID and matches the | 454 // 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|. | 455 // issuer |issuer| name and key, as well as the serial number |serial_number|. |
| 446 bool CheckCertID(const der::Input& id_tlv, | 456 WARN_UNUSED_RESULT bool CheckCertID(const der::Input& id_tlv, |
| 447 const ParsedTbsCertificate& certificate, | 457 const ParsedTbsCertificate& certificate, |
| 448 const ParsedTbsCertificate& issuer, | 458 const ParsedTbsCertificate& issuer, |
| 449 const der::Input& serial_number) { | 459 const der::Input& serial_number) { |
| 450 OCSPCertID id; | 460 OCSPCertID id; |
| 451 if (!ParseOCSPCertID(id_tlv, &id)) | 461 if (!ParseOCSPCertID(id_tlv, &id)) |
| 452 return false; | 462 return false; |
| 453 | 463 |
| 454 HashValueTag type = HASH_VALUE_SHA1; | 464 HashValueTag type = HASH_VALUE_SHA1; |
| 455 switch (id.hash_algorithm) { | 465 switch (id.hash_algorithm) { |
| 456 case DigestAlgorithm::Sha1: | 466 case DigestAlgorithm::Sha1: |
| 457 type = HASH_VALUE_SHA1; | 467 type = HASH_VALUE_SHA1; |
| 458 break; | 468 break; |
| 459 case DigestAlgorithm::Sha256: | 469 case DigestAlgorithm::Sha256: |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 485 return false; | 495 return false; |
| 486 der::Input key_tlv = key_bits.bytes(); | 496 der::Input key_tlv = key_bits.bytes(); |
| 487 if (!VerifyHash(type, id.issuer_key_hash, key_tlv)) | 497 if (!VerifyHash(type, id.issuer_key_hash, key_tlv)) |
| 488 return false; | 498 return false; |
| 489 | 499 |
| 490 return id.serial_number == serial_number; | 500 return id.serial_number == serial_number; |
| 491 } | 501 } |
| 492 | 502 |
| 493 } // namespace | 503 } // namespace |
| 494 | 504 |
| 495 bool GetOCSPCertStatus(const OCSPResponseData& response_data, | 505 WARN_UNUSED_RESULT bool GetOCSPCertStatus(const OCSPResponseData& response_data, |
| 496 const ParsedCertificate& issuer, | 506 const ParsedCertificate& issuer, |
| 497 const ParsedCertificate& cert, | 507 const ParsedCertificate& cert, |
| 498 OCSPCertStatus* out) { | 508 OCSPCertStatus* out) { |
| 499 out->status = OCSPCertStatus::Status::GOOD; | 509 out->status = OCSPCertStatus::Status::GOOD; |
| 500 | 510 |
| 501 ParsedTbsCertificate tbs_cert; | 511 ParsedTbsCertificate tbs_cert; |
| 502 if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs_cert)) | 512 if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs_cert)) |
| 503 return false; | 513 return false; |
| 504 ParsedTbsCertificate issuer_tbs_cert; | 514 ParsedTbsCertificate issuer_tbs_cert; |
| 505 if (!ParseTbsCertificate(issuer.tbs_certificate_tlv, &issuer_tbs_cert)) | 515 if (!ParseTbsCertificate(issuer.tbs_certificate_tlv, &issuer_tbs_cert)) |
| 506 return false; | 516 return false; |
| 507 | 517 |
| 508 bool found = false; | 518 bool found = false; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 522 } | 532 } |
| 523 } | 533 } |
| 524 } | 534 } |
| 525 | 535 |
| 526 if (!found) | 536 if (!found) |
| 527 out->status = OCSPCertStatus::Status::UNKNOWN; | 537 out->status = OCSPCertStatus::Status::UNKNOWN; |
| 528 | 538 |
| 529 return found; | 539 return found; |
| 530 } | 540 } |
| 531 | 541 |
| 542 namespace { | |
| 543 | |
| 544 // Checks that the ResponderID |id| matches the certificate |cert| either | |
| 545 // by verifying the name matches that of the certificate or that the hash | |
| 546 // matches the certificate's public key hash (RFC 6960, 4.2.2.3). | |
| 547 WARN_UNUSED_RESULT bool CheckResponder(const OCSPResponseData::ResponderID& id, | |
|
eroman
2016/05/31 19:12:46
Can you use a more specific name -- how about Resp
| |
| 548 const ParsedTbsCertificate& cert) { | |
| 549 if (id.type == OCSPResponseData::ResponderType::NAME) { | |
| 550 der::Input name_rdn; | |
| 551 der::Input cert_rdn; | |
| 552 if (!der::Parser(id.name).ReadTag(der::kSequence, &name_rdn) || | |
|
eroman
2016/05/31 19:12:46
Can you add documentation for ResponderID indicati
| |
| 553 !der::Parser(cert.subject_tlv).ReadTag(der::kSequence, &cert_rdn)) | |
| 554 return false; | |
| 555 return VerifyNameMatch(name_rdn, cert_rdn); | |
| 556 } | |
|
eroman
2016/05/31 19:12:46
For future proofing my preference is a switch(). B
| |
| 557 | |
| 558 // Otherwise we extract the SPKI and compare the public key hash to key | |
|
eroman
2016/05/31 19:12:46
avoid "we" in comments.
| |
| 559 // in the ResponderID. | |
| 560 der::Parser parser(cert.spki_tlv); | |
| 561 der::Parser spki_parser; | |
| 562 der::BitString key_bits; | |
| 563 if (!parser.ReadSequence(&spki_parser)) | |
| 564 return false; | |
| 565 if (!spki_parser.SkipTag(der::kSequence)) | |
| 566 return false; | |
| 567 if (!spki_parser.ReadBitString(&key_bits)) | |
| 568 return false; | |
| 569 | |
| 570 der::Input key = key_bits.bytes(); | |
| 571 HashValue key_hash(HASH_VALUE_SHA1); | |
| 572 base::SHA1HashBytes(key.UnsafeData(), key.Length(), key_hash.data()); | |
| 573 return key_hash.Equals(id.key_hash); | |
| 574 } | |
| 575 | |
| 576 } // namespace | |
| 577 | |
| 578 WARN_UNUSED_RESULT bool VerifyOCSPResponse( | |
| 579 const OCSPResponse& response, | |
| 580 const ParsedCertificate& issuer_cert, | |
| 581 const SignaturePolicy& signature_policy) { | |
| 582 OCSPResponseData response_data; | |
| 583 if (!ParseOCSPResponseData(response.data, &response_data)) | |
| 584 return false; | |
| 585 | |
| 586 ParsedTbsCertificate issuer; | |
| 587 ParsedTbsCertificate responder; | |
| 588 if (!ParseTbsCertificate(issuer_cert.tbs_certificate_tlv, &issuer)) | |
| 589 return false; | |
| 590 | |
| 591 // In order to verify the OCSP signature, a valid responder matching the OCSP | |
| 592 // Responder ID must be located (RFC 6960, 4.2.2.2). The responder is allowed | |
| 593 // to be either the certificate issuer or a delegated authority directly | |
| 594 // signed by the issuer. | |
| 595 if (CheckResponder(response_data.responder_id, issuer)) { | |
| 596 responder = issuer; | |
| 597 } else { | |
| 598 bool found = false; | |
| 599 // If the authority to sign OCSP responses has been delegated to another | |
| 600 // authority, the OCSP Response will contain the responder certificate. | |
|
eroman
2016/05/31 19:12:46
Is there any normative reference for this logic?
| |
| 601 for (const auto& responder_cert_tlv : response.certs) { | |
| 602 ParsedCertificate responder_cert; | |
| 603 ParsedTbsCertificate tbs_cert; | |
| 604 if (!ParseCertificate(responder_cert_tlv, &responder_cert)) | |
| 605 return false; | |
| 606 if (!ParseTbsCertificate(responder_cert.tbs_certificate_tlv, &tbs_cert)) | |
| 607 return false; | |
| 608 | |
| 609 // The OCSP Responder ID is checked against each provided certificate to | |
| 610 // determine whether it is the correct Authorized Responder. | |
| 611 if (CheckResponder(response_data.responder_id, tbs_cert)) { | |
| 612 found = true; | |
| 613 responder = tbs_cert; | |
| 614 | |
| 615 // The Authorized Responder must be directly signed by the issuer of the | |
| 616 // certificate being checked. | |
| 617 std::unique_ptr<SignatureAlgorithm> signature_algorithm = | |
| 618 SignatureAlgorithm::CreateFromDer( | |
| 619 responder_cert.signature_algorithm_tlv); | |
| 620 if (!signature_algorithm) | |
| 621 return false; | |
| 622 der::Input issuer_spki = issuer.spki_tlv; | |
| 623 if (!VerifySignedData(*signature_algorithm, | |
| 624 responder_cert.tbs_certificate_tlv, | |
| 625 responder_cert.signature_value, issuer_spki, | |
| 626 &signature_policy)) { | |
| 627 return false; | |
| 628 } | |
| 629 | |
| 630 // The Authorized Responder must include the value id-kp-OCSPSigning as | |
| 631 // part of the extended key usage extension. | |
| 632 std::map<der::Input, ParsedExtension> extensions; | |
| 633 std::vector<der::Input> eku; | |
| 634 if (!ParseExtensions(responder.extensions_tlv, &extensions)) | |
| 635 return false; | |
| 636 if (!ParseEKUExtension(extensions[ExtKeyUsageOid()].value, &eku)) | |
| 637 return false; | |
| 638 if (std::find(eku.begin(), eku.end(), OCSPSigning()) == eku.end()) | |
| 639 return false; | |
| 640 | |
| 641 // TODO(svaldez): Add Revocation Checking of Authorized Responder. | |
| 642 break; | |
|
eroman
2016/05/31 19:12:46
Can you pull this out to a separate function inste
| |
| 643 } | |
| 644 } | |
| 645 if (!found) | |
| 646 return false; | |
| 647 } | |
| 648 // Once a valid responder has been found, the signature of the OCSP | |
| 649 // response is verified against the public key of the responder. | |
| 650 return VerifySignedData(*(response.signature_algorithm), response.data, | |
| 651 response.signature, responder.spki_tlv, | |
| 652 &signature_policy); | |
| 653 } | |
| 654 | |
| 532 } // namespace net | 655 } // namespace net |
| OLD | NEW |