OLD | NEW |
(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 |
OLD | NEW |