Chromium Code Reviews| 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/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 namespace { | |
| 18 | |
| 19 // Continues reading from |parser| to extract an OCSP CertStatus (RFC 6960) | |
| 20 // and stores the result in the OCSPSingleResponse |out|. Returns whether | |
| 21 // the parsing was successful. | |
| 22 bool ParseOCSPStatus(der::Parser* parser, OCSPCertStatus* out) { | |
|
eroman
2016/02/13 00:56:50
I would find it useful when reading this to duplic
svaldez
2016/02/16 17:25:11
Acknowledged.
| |
| 23 der::Tag status_tag; | |
| 24 der::Input status; | |
| 25 | |
| 26 if (!parser->ReadTagAndValue(&status_tag, &status)) | |
| 27 return false; | |
| 28 | |
| 29 if (status_tag == der::ContextSpecificPrimitive(0)) { | |
| 30 out->status = OCSPCertStatus::Status::GOOD; | |
| 31 } else if (status_tag == der::ContextSpecificConstructed(1)) { | |
| 32 out->status = OCSPCertStatus::Status::REVOKED; | |
| 33 der::Parser revoked_info_parser(status); | |
| 34 der::Input revocation_time; | |
| 35 der::Input revocation_reason_input; | |
| 36 if (!revoked_info_parser.ReadGeneralizedTime(&(out->revocation_time))) | |
| 37 return false; | |
| 38 if (!revoked_info_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), | |
| 39 &revocation_reason_input, | |
| 40 &(out->has_reason))) { | |
|
eroman
2016/02/13 00:56:49
How about initializing has_reason to false at the
svaldez
2016/02/16 17:25:11
Done.
| |
| 41 return false; | |
| 42 } | |
| 43 if (revoked_info_parser.HasMore()) | |
| 44 return false; | |
| 45 if (!out->has_reason) | |
| 46 return true; | |
|
eroman
2016/02/13 00:56:49
From a future-proofing perspective, earlier return
svaldez
2016/02/16 17:25:11
Done.
| |
| 47 der::Parser reason_parser(revocation_reason_input); | |
| 48 der::Input revocation_reason; | |
| 49 if (!reason_parser.ReadTag(der::kEnumerated, &revocation_reason)) | |
|
eroman
2016/02/13 00:56:49
Why is this der::kEnumerated?
I assumed the defin
svaldez
2016/02/16 17:25:10
CRLReason is defined as an ENUMERATED in RFC5912 (
| |
| 50 return false; | |
| 51 uint8_t revocation_reason_value; | |
| 52 if (!der::ParseUint8(revocation_reason, &revocation_reason_value)) | |
| 53 return false; | |
| 54 if (revocation_reason_value >= | |
| 55 (uint8_t)OCSPCertStatus::RevocationReason::REVOCATION_REASON_MAX) { | |
|
eroman
2016/02/13 00:56:49
static_cast<>
svaldez
2016/02/16 17:25:10
Done.
| |
| 56 return false; | |
| 57 } | |
| 58 out->revocation_reason = | |
| 59 static_cast<OCSPCertStatus::RevocationReason>(revocation_reason_value); | |
|
eroman
2016/02/13 00:56:49
I don't see that reason_parser.HasMore() is checke
svaldez
2016/02/16 17:25:11
Done.
| |
| 60 } else if (status_tag == der::ContextSpecificPrimitive(2)) { | |
| 61 out->status = OCSPCertStatus::Status::UNKNOWN; | |
|
eroman
2016/02/13 00:56:49
For sanity it would be a good idea to reset all th
svaldez
2016/02/16 17:25:10
Done.
| |
| 62 } else { | |
| 63 return false; | |
| 64 } | |
| 65 | |
| 66 return true; | |
| 67 } | |
| 68 | |
| 69 // Continues reading from |parser| to extract the ResponderID (RFC 6960) and | |
| 70 // stores the result in |out|. Returns whether the parsing was successful. | |
| 71 bool ParseOCSPResponder(der::Parser* parser, | |
| 72 OCSPResponseData::ResponderID* out) { | |
| 73 der::Tag id_tag; | |
| 74 der::Input responder_id_input; | |
| 75 if (!parser->ReadTagAndValue(&id_tag, &responder_id_input)) | |
| 76 return false; | |
| 77 | |
| 78 OCSPResponseData::ResponderID responder_id; | |
|
eroman
2016/02/13 00:56:50
Why this temporary rather than writing directly to
svaldez
2016/02/16 17:25:11
Done.
| |
| 79 if (id_tag == der::ContextSpecificConstructed(1)) { | |
| 80 responder_id.type = OCSPResponseData::ResponderType::NAME; | |
| 81 responder_id.name = responder_id_input; | |
| 82 } else if (id_tag == der::ContextSpecificConstructed(2)) { | |
| 83 der::Parser key_parser(responder_id_input); | |
| 84 der::Input responder_key; | |
| 85 if (!key_parser.ReadTag(der::kOctetString, &responder_key)) | |
| 86 return false; | |
| 87 if (key_parser.HasMore()) | |
| 88 return false; | |
| 89 | |
| 90 SHA1HashValue key_hash; | |
| 91 if (responder_key.Length() != sizeof(key_hash.data)) | |
| 92 return false; | |
| 93 memcpy(key_hash.data, responder_key.UnsafeData(), base::kSHA1Length); | |
|
eroman
2016/02/13 00:56:49
can you use sizeof(key_hash.data) instead of base:
svaldez
2016/02/16 17:25:11
Done.
| |
| 94 responder_id.type = OCSPResponseData::ResponderType::KEY_HASH; | |
| 95 responder_id.key_hash = HashValue(key_hash); | |
| 96 } else { | |
| 97 return false; | |
| 98 } | |
| 99 *out = responder_id; | |
| 100 return true; | |
| 101 } | |
| 102 | |
| 103 // Continues reading from |parser| to extract a BasicOCSPResponse (RFC 6960) | |
| 104 // and stores the result in OCSPResponse |out|. Returns whether the parsing | |
| 105 // was successful. | |
| 106 bool ParseBasicOCSPResponse(der::Parser* parser, OCSPResponse* out) { | |
| 107 der::Input sigalg_tlv; | |
| 108 if (!parser->ReadRawTLV(&(out->data))) | |
| 109 return false; | |
| 110 if (!parser->ReadRawTLV(&sigalg_tlv)) | |
| 111 return false; | |
| 112 out->signature_algorithm = SignatureAlgorithm::CreateFromDer(sigalg_tlv); | |
| 113 if (!out->signature_algorithm) | |
| 114 return false; | |
| 115 | |
| 116 if (!parser->ReadBitString(&(out->signature))) | |
| 117 return false; | |
| 118 der::Input certs_input; | |
| 119 bool certs_present; | |
| 120 if (!parser->ReadOptionalTag(der::ContextSpecificConstructed(0), &certs_input, | |
| 121 &certs_present)) { | |
| 122 return false; | |
| 123 } | |
| 124 | |
| 125 if (parser->HasMore()) | |
|
eroman
2016/02/13 00:56:50
I think this would be more appropriate in the call
svaldez
2016/02/16 17:25:10
Done.
| |
| 126 return false; | |
| 127 | |
| 128 if (!certs_present) | |
| 129 return true; | |
|
eroman
2016/02/13 00:56:49
Same comment as earlier - "return true" short cuic
svaldez
2016/02/16 17:25:10
Done.
| |
| 130 der::Parser certs_input_parser(certs_input); | |
| 131 der::Parser certs_parser; | |
| 132 if (!certs_input_parser.ReadSequence(&certs_parser)) | |
| 133 return false; | |
| 134 if (certs_input_parser.HasMore()) | |
| 135 return false; | |
| 136 while (certs_parser.HasMore()) { | |
| 137 der::Input cert_tlv; | |
| 138 if (!certs_parser.ReadRawTLV(&cert_tlv)) | |
| 139 return false; | |
| 140 out->certs.push_back(cert_tlv); | |
|
eroman
2016/02/13 00:56:50
Where is the array first initialized?
In other wo
svaldez
2016/02/16 17:25:10
Done.
| |
| 141 } | |
| 142 | |
| 143 return true; | |
| 144 } | |
| 145 | |
| 146 } // namespace | |
| 147 | |
| 148 OCSPCertID::OCSPCertID() {} | |
| 149 OCSPCertID::~OCSPCertID() {} | |
| 150 | |
| 151 OCSPSingleResponse::OCSPSingleResponse() {} | |
| 152 OCSPSingleResponse::~OCSPSingleResponse() {} | |
| 153 | |
| 154 OCSPResponseData::OCSPResponseData() {} | |
| 155 OCSPResponseData::~OCSPResponseData() {} | |
| 156 | |
| 157 OCSPResponse::OCSPResponse() {} | |
| 158 OCSPResponse::~OCSPResponse() {} | |
| 159 | |
| 160 der::Input BasicOCSPResponseOid() { | |
| 161 // From RFC 6960: | |
| 162 // | |
| 163 // id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp } | |
| 164 // id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } | |
| 165 // | |
| 166 // In dotted notation: 1.3.6.1.5.5.7.48.1.1 | |
| 167 static const uint8_t oid[] = {0x2b, 0x06, 0x01, 0x05, 0x05, | |
| 168 0x07, 0x30, 0x01, 0x01}; | |
| 169 return der::Input(oid); | |
| 170 } | |
| 171 | |
| 172 bool ParseOCSPCertID(der::Input raw_tlv, OCSPCertID* out) { | |
| 173 der::Parser outer_parser(raw_tlv); | |
| 174 der::Parser parser; | |
| 175 if (!outer_parser.ReadSequence(&parser)) | |
| 176 return false; | |
| 177 der::Input sigalg_tlv; | |
| 178 if (!parser.ReadRawTLV(&sigalg_tlv)) | |
| 179 return false; | |
| 180 if (!ParseHashAlgorithm(sigalg_tlv, &(out->hash_algorithm))) | |
| 181 return false; | |
| 182 if (!parser.ReadTag(der::kOctetString, &(out->issuer_name_hash))) | |
| 183 return false; | |
| 184 if (!parser.ReadTag(der::kOctetString, &(out->issuer_key_hash))) | |
| 185 return false; | |
| 186 if (!parser.ReadTag(der::kInteger, &(out->serial_number))) | |
|
eroman
2016/02/13 00:56:50
This is more lenient then the certificate serial n
svaldez
2016/02/16 17:25:11
Done.
| |
| 187 return false; | |
| 188 return !parser.HasMore(); | |
| 189 } | |
| 190 | |
| 191 bool ParseOCSPSingleResponse(der::Input raw_tlv, OCSPSingleResponse* out) { | |
| 192 der::Parser response_parser(raw_tlv); | |
| 193 der::Parser parser; | |
| 194 if (!response_parser.ReadSequence(&parser)) | |
| 195 return false; | |
| 196 if (response_parser.HasMore()) | |
| 197 return false; | |
| 198 if (!parser.ReadRawTLV(&(out->cert_id_tlv))) | |
| 199 return false; | |
| 200 if (!ParseOCSPStatus(&parser, &(out->cert_status))) | |
| 201 return false; | |
| 202 der::Input this_update; | |
| 203 if (!parser.ReadGeneralizedTime(&(out->this_update))) | |
| 204 return false; | |
| 205 der::Input next_update_input; | |
| 206 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), | |
| 207 &next_update_input, &(out->has_next_update))) { | |
| 208 return false; | |
| 209 } | |
| 210 | |
| 211 if (out->has_next_update) { | |
| 212 der::Parser next_update_parser(next_update_input); | |
| 213 der::Input next_update; | |
| 214 if (!next_update_parser.ReadGeneralizedTime(&(out->next_update))) | |
| 215 return false; | |
| 216 if (next_update_parser.HasMore()) | |
| 217 return false; | |
| 218 } | |
| 219 | |
| 220 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(1), | |
| 221 &(out->extensions), &(out->has_extensions))) { | |
| 222 return false; | |
| 223 } | |
| 224 | |
| 225 return !parser.HasMore(); | |
| 226 } | |
| 227 | |
| 228 bool ParseOCSPResponseData(der::Input raw_tlv, OCSPResponseData* out) { | |
| 229 der::Parser outer_parser(raw_tlv); | |
| 230 der::Parser parser; | |
| 231 if (!outer_parser.ReadSequence(&parser)) | |
| 232 return false; | |
| 233 if (outer_parser.HasMore()) | |
| 234 return false; | |
| 235 | |
| 236 der::Input version_input; | |
| 237 bool version_present; | |
| 238 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), | |
| 239 &version_input, &version_present)) { | |
| 240 return false; | |
| 241 } | |
| 242 | |
| 243 // We ignore the restriction that the DEFAULT Version v1 shouldn't be | |
|
eroman
2016/02/13 00:56:49
Per previous comment, try to avoid "We" when possi
svaldez
2016/02/16 17:25:10
Done.
| |
| 244 // specified due to many implementations including it regardless of the DER | |
| 245 // spec. | |
| 246 if (version_present) { | |
| 247 der::Parser version_parser(version_input); | |
| 248 der::Input version; | |
| 249 if (!version_parser.ReadTag(der::kInteger, &version)) | |
| 250 return false; | |
| 251 if (version_parser.HasMore()) | |
| 252 return false; | |
| 253 if (!der::ParseUint8(version, &(out->version))) | |
| 254 return false; | |
| 255 } else { | |
| 256 out->version = 0; | |
| 257 } | |
| 258 | |
| 259 if (!ParseOCSPResponder(&parser, &(out->responder_id))) | |
| 260 return false; | |
| 261 | |
| 262 der::Input produced_at; | |
| 263 if (!parser.ReadGeneralizedTime(&(out->produced_at))) | |
| 264 return false; | |
| 265 | |
| 266 der::Parser responses_parser; | |
| 267 if (!parser.ReadSequence(&responses_parser)) | |
| 268 return false; | |
| 269 out->responses.clear(); | |
| 270 while (responses_parser.HasMore()) { | |
| 271 der::Input single_response; | |
| 272 if (!responses_parser.ReadRawTLV(&single_response)) | |
| 273 return false; | |
| 274 out->responses.push_back(single_response); | |
| 275 } | |
| 276 | |
| 277 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(1), | |
| 278 &(out->extensions), &(out->has_extensions))) { | |
| 279 return false; | |
| 280 } | |
| 281 | |
| 282 return !parser.HasMore(); | |
| 283 } | |
| 284 | |
| 285 bool ParseOCSPResponse(der::Input ocsp_response, OCSPResponse* out) { | |
|
eroman
2016/02/13 00:56:49
Would be useful to see the ASN.1 structure duplica
svaldez
2016/02/16 17:25:11
Done.
| |
| 286 der::Parser parser(ocsp_response); | |
| 287 der::Input response_status; | |
| 288 der::Parser ocsp_response_parser; | |
| 289 if (!parser.ReadSequence(&ocsp_response_parser)) | |
| 290 return false; | |
| 291 if (parser.HasMore()) | |
| 292 return false; | |
| 293 if (!ocsp_response_parser.ReadTag(der::kEnumerated, &response_status)) | |
| 294 return false; | |
| 295 uint8_t response_status_value; | |
| 296 if (!der::ParseUint8(response_status, &response_status_value)) | |
| 297 return false; | |
| 298 if (response_status_value >= | |
| 299 (uint8_t)OCSPResponse::ResponseStatus::RESPONSE_STATUS_MAX) { | |
|
eroman
2016/02/13 00:56:49
static_cast
svaldez
2016/02/16 17:25:10
Done.
| |
| 300 return false; | |
| 301 } | |
| 302 out->status = | |
| 303 static_cast<OCSPResponse::ResponseStatus>(response_status_value); | |
| 304 if (out->status != OCSPResponse::ResponseStatus::SUCCESSFUL) | |
| 305 return true; | |
|
eroman
2016/02/13 00:56:50
Same comment as earlier regarding "return true;" s
svaldez
2016/02/16 17:25:11
Done.
| |
| 306 | |
| 307 der::Input response_type_oid; | |
| 308 der::Input response_string; | |
| 309 der::Parser response_bytes_input_parser; | |
| 310 der::Parser response_bytes_parser; | |
| 311 if (!ocsp_response_parser.ReadConstructed(der::ContextSpecificConstructed(0), | |
|
eroman
2016/02/13 00:56:50
Is this allowed to be omitted in the case of succe
svaldez
2016/02/16 17:25:10
responseBytes must be set if the status is SUCCESS
| |
| 312 &response_bytes_input_parser)) { | |
| 313 return false; | |
| 314 } | |
| 315 if (ocsp_response_parser.HasMore()) | |
| 316 return false; | |
| 317 if (!response_bytes_input_parser.ReadSequence(&response_bytes_parser)) | |
|
eroman
2016/02/13 00:56:49
I would find it easier to read if each sequence is
svaldez
2016/02/16 17:25:10
Moved the sequence parsing into BasicResponse pars
| |
| 318 return false; | |
| 319 if (response_bytes_input_parser.HasMore()) | |
| 320 return false; | |
| 321 if (!response_bytes_parser.ReadTag(der::kOid, &response_type_oid)) | |
| 322 return false; | |
| 323 if (response_type_oid != BasicOCSPResponseOid()) | |
|
eroman
2016/02/13 00:56:50
(Note: Not familiar enough if this is the only OID
svaldez
2016/02/16 17:25:10
Its the only defined OID currently.
| |
| 324 return false; | |
| 325 if (!response_bytes_parser.ReadTag(der::kOctetString, &response_string)) | |
|
eroman
2016/02/13 00:56:50
Please provide documentation here that the octet s
svaldez
2016/02/16 17:25:11
Done.
| |
| 326 return false; | |
| 327 if (response_bytes_parser.HasMore()) | |
| 328 return false; | |
| 329 der::Parser response_parser(response_string); | |
| 330 der::Parser basic_response_parser; | |
| 331 if (!response_parser.ReadSequence(&basic_response_parser)) | |
| 332 return false; | |
| 333 if (response_parser.HasMore()) | |
| 334 return false; | |
| 335 return ParseBasicOCSPResponse(&basic_response_parser, out); | |
| 336 } | |
| 337 | |
| 338 namespace { | |
| 339 | |
| 340 bool CheckResponder(OCSPResponseData::ResponderID id, | |
|
eroman
2016/02/13 00:56:50
The non-parsing functions feel like they belong in
svaldez
2016/02/16 17:25:11
I'll split out the non-parsing bits after finishin
| |
| 341 ParsedTbsCertificate cert) { | |
| 342 if (id.type == OCSPResponseData::ResponderType::NAME) { | |
| 343 der::Input name_rdn; | |
| 344 der::Input cert_rdn; | |
| 345 if (!der::Parser(id.name).ReadTag(der::kSequence, &name_rdn) || | |
| 346 !der::Parser(cert.subject_tlv).ReadTag(der::kSequence, &cert_rdn)) | |
| 347 return false; | |
| 348 return VerifyNameMatch(name_rdn, cert_rdn); | |
| 349 } else { | |
| 350 der::Parser parser(cert.spki_tlv); | |
| 351 der::Parser spki_parser; | |
| 352 der::BitString key_bits; | |
| 353 if (!parser.ReadSequence(&spki_parser)) | |
| 354 return false; | |
| 355 if (!spki_parser.SkipTag(der::kSequence)) | |
| 356 return false; | |
| 357 if (!spki_parser.ReadBitString(&key_bits)) | |
| 358 return false; | |
| 359 | |
| 360 der::Input key = key_bits.bytes(); | |
| 361 HashValue key_hash(HASH_VALUE_SHA1); | |
| 362 base::SHA1HashBytes(key.UnsafeData(), key.Length(), key_hash.data()); | |
| 363 return key_hash.Equals(id.key_hash); | |
| 364 } | |
| 365 } | |
| 366 | |
| 367 bool CheckCertID(der::Input id_tlv, | |
| 368 ParsedTbsCertificate issuer, | |
| 369 der::Input serial_number) { | |
| 370 OCSPCertID id; | |
| 371 if (!ParseOCSPCertID(id_tlv, &id)) | |
| 372 return false; | |
| 373 | |
| 374 HashValueTag type; | |
| 375 switch (id.hash_algorithm) { | |
| 376 case DigestAlgorithm::Sha1: | |
| 377 type = HASH_VALUE_SHA1; | |
| 378 break; | |
| 379 case DigestAlgorithm::Sha256: | |
| 380 type = HASH_VALUE_SHA256; | |
| 381 break; | |
| 382 default: | |
| 383 NOTIMPLEMENTED(); | |
| 384 return false; | |
| 385 } | |
| 386 | |
| 387 HashValue id_name_hash(type); | |
| 388 if (id.issuer_name_hash.Length() != id_name_hash.size()) | |
| 389 return false; | |
| 390 memcpy(id_name_hash.data(), id.issuer_name_hash.UnsafeData(), | |
| 391 id_name_hash.size()); | |
| 392 HashValue issuer_name_hash(type); | |
| 393 der::Input name = issuer.subject_tlv; | |
| 394 if (type == HASH_VALUE_SHA1) | |
| 395 base::SHA1HashBytes(name.UnsafeData(), name.Length(), | |
| 396 issuer_name_hash.data()); | |
| 397 else { | |
| 398 std::string hash = crypto::SHA256HashString(name.AsString()); | |
| 399 memcpy(issuer_name_hash.data(), hash.data(), issuer_name_hash.size()); | |
| 400 } | |
| 401 if (!id_name_hash.Equals(issuer_name_hash)) | |
| 402 return false; | |
| 403 | |
| 404 HashValue id_key_hash(type); | |
| 405 if (id.issuer_key_hash.Length() != id_key_hash.size()) | |
| 406 return false; | |
| 407 memcpy(id_key_hash.data(), id.issuer_key_hash.UnsafeData(), | |
| 408 id_key_hash.size()); | |
| 409 HashValue issuer_key_hash(type); | |
| 410 der::Parser parser(issuer.spki_tlv); | |
| 411 der::Parser spki_parser; | |
| 412 der::BitString key_bits; | |
| 413 if (!parser.ReadSequence(&spki_parser)) | |
| 414 return false; | |
| 415 if (!spki_parser.SkipTag(der::kSequence)) | |
| 416 return false; | |
| 417 if (!spki_parser.ReadBitString(&key_bits)) | |
| 418 return false; | |
| 419 der::Input key = key_bits.bytes(); | |
| 420 if (type == HASH_VALUE_SHA1) | |
| 421 base::SHA1HashBytes(key.UnsafeData(), key.Length(), issuer_key_hash.data()); | |
| 422 else { | |
| 423 std::string hash = crypto::SHA256HashString(key.AsString()); | |
| 424 memcpy(issuer_key_hash.data(), hash.data(), issuer_key_hash.size()); | |
| 425 } | |
| 426 | |
| 427 if (!id_key_hash.Equals(issuer_key_hash)) | |
| 428 return false; | |
| 429 | |
| 430 return id.serial_number == serial_number; | |
| 431 } | |
| 432 | |
| 433 } // namespace | |
| 434 | |
| 435 bool VerifyOCSPResponse(const OCSPResponse* response, | |
| 436 const ParsedCertificate* issuer_cert) { | |
| 437 SimpleSignaturePolicy signature_policy(1024); | |
| 438 | |
| 439 OCSPResponseData response_data; | |
| 440 if (!ParseOCSPResponseData(response->data, &response_data)) | |
| 441 return false; | |
| 442 | |
| 443 ParsedTbsCertificate issuer; | |
| 444 ParsedTbsCertificate responder; | |
| 445 if (!issuer_cert || | |
| 446 !ParseTbsCertificate(issuer_cert->tbs_certificate_tlv, &issuer)) | |
| 447 return false; | |
| 448 | |
| 449 if (CheckResponder(response_data.responder_id, issuer)) { | |
| 450 responder = issuer; | |
| 451 } else { | |
| 452 bool found = false; | |
| 453 for (const auto& responder_cert_tlv : response->certs) { | |
| 454 ParsedCertificate responder_cert; | |
| 455 ParsedTbsCertificate tbs_cert; | |
| 456 if (!ParseCertificate(responder_cert_tlv, &responder_cert)) | |
| 457 return false; | |
| 458 if (!ParseTbsCertificate(responder_cert.tbs_certificate_tlv, &tbs_cert)) | |
| 459 return false; | |
| 460 | |
| 461 if (CheckResponder(response_data.responder_id, tbs_cert)) { | |
| 462 found = true; | |
| 463 responder = tbs_cert; | |
| 464 | |
| 465 scoped_ptr<SignatureAlgorithm> signature_algorithm = | |
| 466 SignatureAlgorithm::CreateFromDer( | |
| 467 responder_cert.signature_algorithm_tlv); | |
| 468 der::Input issuer_spki = issuer.spki_tlv; | |
| 469 if (!VerifySignedData(*signature_algorithm, | |
| 470 responder_cert.tbs_certificate_tlv, | |
| 471 responder_cert.signature_value, issuer_spki, | |
| 472 &signature_policy)) { | |
| 473 return false; | |
| 474 } | |
| 475 | |
| 476 std::map<der::Input, ParsedExtension> extensions; | |
| 477 std::vector<der::Input> eku; | |
| 478 if (!ParseExtensions(responder.extensions_tlv, &extensions)) | |
| 479 return false; | |
| 480 if (!ParseEKUExtension(extensions[ExtKeyUsageOid()].value, &eku)) | |
| 481 return false; | |
| 482 if (std::find(eku.begin(), eku.end(), OCSPSigning()) == eku.end()) | |
| 483 return false; | |
| 484 break; | |
| 485 } | |
| 486 } | |
| 487 if (!found) | |
| 488 return false; | |
| 489 } | |
| 490 return VerifySignedData(*(response->signature_algorithm), response->data, | |
| 491 response->signature, responder.spki_tlv, | |
| 492 &signature_policy); | |
| 493 } | |
| 494 | |
| 495 bool GetOCSPCertStatus(const OCSPResponseData* response_data, | |
| 496 const ParsedCertificate* issuer, | |
| 497 const ParsedCertificate* cert, | |
| 498 OCSPCertStatus* out) { | |
| 499 out->status = OCSPCertStatus::Status::UNKNOWN; | |
| 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 for (const auto& response : response_data->responses) { | |
| 509 OCSPSingleResponse single_response; | |
| 510 if (!ParseOCSPSingleResponse(response, &single_response)) | |
| 511 return false; | |
| 512 if (CheckCertID(single_response.cert_id_tlv, issuer_tbs_cert, | |
| 513 tbs_cert.serial_number)) { | |
| 514 *out = single_response.cert_status; | |
| 515 if (single_response.cert_status.status != OCSPCertStatus::Status::GOOD) | |
| 516 return true; | |
| 517 } | |
| 518 } | |
| 519 | |
| 520 return true; | |
| 521 } | |
| 522 | |
| 523 } // namespace net | |
| OLD | NEW |