Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/base/x509_certificate.h" | 5 #include "net/base/x509_certificate.h" |
| 6 | 6 |
| 7 #define PRArenaPool PLArenaPool // Required by <blapi.h>. | 7 #define PRArenaPool PLArenaPool // Required by <blapi.h>. |
| 8 #include <blapi.h> // Implement CalculateChainFingerprint() with NSS. | 8 #include <blapi.h> // Implement CalculateChainFingerprint() with NSS. |
| 9 | 9 |
| 10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 401 extension->Value.pbData, | 401 extension->Value.pbData, |
| 402 extension->Value.cbData, | 402 extension->Value.cbData, |
| 403 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, | 403 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, |
| 404 &decode_para, | 404 &decode_para, |
| 405 &policies_info, | 405 &policies_info, |
| 406 &policies_info_size); | 406 &policies_info_size); |
| 407 if (rv) | 407 if (rv) |
| 408 output->reset(policies_info); | 408 output->reset(policies_info); |
| 409 } | 409 } |
| 410 | 410 |
| 411 // Helper function to parse a principal from a WinInet description of that | |
| 412 // principal. | |
| 413 void ParsePrincipal(const std::string& description, | |
| 414 CertPrincipal* principal) { | |
| 415 // The description of the principal is a string with each LDAP value on | |
| 416 // a separate line. | |
| 417 const std::string kDelimiters("\r\n"); | |
| 418 | |
| 419 std::vector<std::string> common_names, locality_names, state_names, | |
| 420 country_names; | |
| 421 | |
| 422 // TODO(jcampan): add business_category and serial_number. | |
| 423 const std::string kPrefixes[] = { std::string("CN="), | |
| 424 std::string("L="), | |
| 425 std::string("S="), | |
| 426 std::string("C="), | |
| 427 std::string("STREET="), | |
| 428 std::string("O="), | |
| 429 std::string("OU="), | |
| 430 std::string("DC=") }; | |
| 431 | |
| 432 std::vector<std::string>* values[] = { | |
| 433 &common_names, &locality_names, | |
| 434 &state_names, &country_names, | |
| 435 &(principal->street_addresses), | |
| 436 &(principal->organization_names), | |
| 437 &(principal->organization_unit_names), | |
| 438 &(principal->domain_components) }; | |
| 439 DCHECK(arraysize(kPrefixes) == arraysize(values)); | |
| 440 | |
| 441 StringTokenizer str_tok(description, kDelimiters); | |
| 442 while (str_tok.GetNext()) { | |
| 443 std::string entry = str_tok.token(); | |
| 444 for (int i = 0; i < arraysize(kPrefixes); i++) { | |
| 445 if (!entry.compare(0, kPrefixes[i].length(), kPrefixes[i])) { | |
| 446 std::string value = entry.substr(kPrefixes[i].length()); | |
| 447 // Remove enclosing double-quotes if any. | |
| 448 if (value.size() >= 2 && | |
| 449 value[0] == '"' && value[value.size() - 1] == '"') | |
| 450 value = value.substr(1, value.size() - 2); | |
| 451 values[i]->push_back(value); | |
| 452 break; | |
| 453 } | |
| 454 } | |
| 455 } | |
| 456 | |
| 457 // We don't expect to have more than one CN, L, S, and C. If there is more | |
| 458 // than one entry for CN, L, S, and C, we will use the first entry. Although | |
| 459 // RFC 2818 Section 3.1 says the "most specific" CN should be used, that term | |
| 460 // has been removed in draft-saintandre-tls-server-id-check, which requires | |
| 461 // that the Subject field contains only one CN. So it is fine for us to just | |
| 462 // use the first CN. | |
| 463 std::vector<std::string>* single_value_lists[4] = { | |
| 464 &common_names, &locality_names, &state_names, &country_names }; | |
| 465 std::string* single_values[4] = { | |
| 466 &principal->common_name, &principal->locality_name, | |
| 467 &principal->state_or_province_name, &principal->country_name }; | |
| 468 for (int i = 0; i < arraysize(single_value_lists); ++i) { | |
| 469 int length = static_cast<int>(single_value_lists[i]->size()); | |
| 470 if (!single_value_lists[i]->empty()) | |
| 471 *(single_values[i]) = (*(single_value_lists[i]))[0]; | |
| 472 } | |
| 473 } | |
| 474 | |
| 475 void AddCertsFromStore(HCERTSTORE store, | 411 void AddCertsFromStore(HCERTSTORE store, |
| 476 X509Certificate::OSCertHandles* results) { | 412 X509Certificate::OSCertHandles* results) { |
| 477 PCCERT_CONTEXT cert = NULL; | 413 PCCERT_CONTEXT cert = NULL; |
| 478 | 414 |
| 479 while ((cert = CertEnumCertificatesInStore(store, cert)) != NULL) { | 415 while ((cert = CertEnumCertificatesInStore(store, cert)) != NULL) { |
| 480 PCCERT_CONTEXT to_add = NULL; | 416 PCCERT_CONTEXT to_add = NULL; |
| 481 if (CertAddCertificateContextToStore( | 417 if (CertAddCertificateContextToStore( |
| 482 NULL, // The cert won't be persisted in any cert store. This breaks | 418 NULL, // The cert won't be persisted in any cert store. This breaks |
| 483 // any association the context currently has to |store|, which | 419 // any association the context currently has to |store|, which |
| 484 // allows us, the caller, to safely close |store| without | 420 // allows us, the caller, to safely close |store| without |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 539 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) | 475 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) |
| 540 continue; | 476 continue; |
| 541 | 477 |
| 542 SHA1Fingerprint hash; | 478 SHA1Fingerprint hash; |
| 543 base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), | 479 base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), |
| 544 spki_bytes.size(), hash.data); | 480 spki_bytes.size(), hash.data); |
| 545 hashes->push_back(hash); | 481 hashes->push_back(hash); |
| 546 } | 482 } |
| 547 } | 483 } |
| 548 | 484 |
| 485 // A list of OIDs to decode. Any OID not on this list will be ignored for | |
| 486 // purposes of parsing. | |
| 487 const char* kOIDs[] = { | |
| 488 szOID_COMMON_NAME, | |
| 489 szOID_LOCALITY_NAME, | |
| 490 szOID_STATE_OR_PROVINCE_NAME, | |
| 491 szOID_COUNTRY_NAME, | |
| 492 szOID_STREET_ADDRESS, | |
| 493 szOID_ORGANIZATION_NAME, | |
| 494 szOID_ORGANIZATIONAL_UNIT_NAME, | |
| 495 szOID_DOMAIN_COMPONENT | |
| 496 }; | |
| 497 | |
| 498 // Converts the value for |attribute| to an ASCII string, storing the result | |
| 499 // in |value|. Returns false if the string cannot be converted. | |
| 500 bool GetAttributeValue(PCERT_RDN_ATTR attribute, | |
| 501 std::string* value) { | |
| 502 DWORD bytes_needed = CertRDNValueToStrA(attribute->dwValueType, | |
| 503 &attribute->Value, NULL, 0); | |
| 504 if (bytes_needed == 0) | |
| 505 return false; | |
| 506 if (bytes_needed == 1) { | |
| 507 // The value is actually an empty string (bytes_needed includes a single | |
| 508 // byte for a NULL value). Don't bother converting - just clear the | |
| 509 // string. | |
| 510 value->clear(); | |
| 511 return true; | |
| 512 } | |
| 513 DWORD bytes_written = CertRDNValueToStrA( | |
| 514 attribute->dwValueType, &attribute->Value, | |
| 515 WriteInto(value, bytes_needed), bytes_needed); | |
| 516 if (bytes_written <= 1) | |
| 517 return false; | |
| 518 return true; | |
| 519 } | |
| 520 | |
| 521 // Adds a type+value pair to the appropriate vector from a C array. | |
| 522 // The array is keyed by the matching OIDs from kOIDS[]. | |
| 523 bool AddTypeValuePair(PCERT_RDN_ATTR attribute, | |
| 524 std::vector<std::string>* values[]) { | |
| 525 for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { | |
| 526 if (strcmp(attribute->pszObjId, kOIDs[oid]) == 0) { | |
| 527 std::string value; | |
| 528 if (!GetAttributeValue(attribute, &value)) | |
| 529 return false; | |
| 530 values[oid]->push_back(value); | |
| 531 break; | |
| 532 } | |
| 533 } | |
| 534 return true; | |
| 535 } | |
| 536 | |
| 537 // Stores the first string of the vector, if any, to *single_value. | |
| 538 void SetSingle(const std::vector<std::string>& values, | |
| 539 std::string* single_value) { | |
| 540 // We don't expect to have more than one CN, L, S, and C. | |
| 541 LOG_IF(WARNING, values.size() > 1) << "Didn't expect multiple values"; | |
| 542 if (!values.empty()) | |
| 543 *single_value = values[0]; | |
| 544 } | |
| 545 | |
| 546 bool ParsePrincipal(const void* ber_name_data, | |
| 547 size_t length, | |
|
wtc
2011/12/01 23:59:41
Nit: perhaps this can take CERT_NAME_BLOB* as inpu
| |
| 548 CertPrincipal* principal) { | |
| 549 CRYPT_DECODE_PARA decode_para; | |
| 550 decode_para.cbSize = sizeof(decode_para); | |
| 551 decode_para.pfnAlloc = MyCryptAlloc; | |
| 552 decode_para.pfnFree = MyCryptFree; | |
| 553 CERT_NAME_INFO* name_info = NULL; | |
| 554 DWORD name_info_size = 0; | |
| 555 BOOL rv; | |
| 556 rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, | |
| 557 X509_NAME, | |
| 558 reinterpret_cast<const BYTE*>(ber_name_data), | |
| 559 length, | |
| 560 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, | |
| 561 &decode_para, | |
| 562 &name_info, &name_info_size); | |
| 563 if (!rv) | |
| 564 return false; | |
| 565 scoped_ptr_malloc<CERT_NAME_INFO> scoped_name_info(name_info); | |
| 566 | |
| 567 std::vector<std::string> common_names, locality_names, state_names, | |
| 568 country_names; | |
| 569 | |
| 570 std::vector<std::string>* values[] = { | |
| 571 &common_names, &locality_names, | |
| 572 &state_names, &country_names, | |
| 573 &(principal->street_addresses), | |
| 574 &(principal->organization_names), | |
| 575 &(principal->organization_unit_names), | |
| 576 &(principal->domain_components) | |
| 577 }; | |
| 578 DCHECK(arraysize(kOIDs) == arraysize(values)); | |
| 579 | |
| 580 for (DWORD cur_rdn = 0; cur_rdn < name_info->cRDN; ++cur_rdn) { | |
| 581 PCERT_RDN rdn = &name_info->rgRDN[cur_rdn]; | |
| 582 for (DWORD cur_ava = 0; cur_ava < rdn->cRDNAttr; ++cur_ava) { | |
| 583 PCERT_RDN_ATTR ava = &rdn->rgRDNAttr[cur_ava]; | |
| 584 if (!AddTypeValuePair(ava, values)) | |
| 585 return false; | |
| 586 } | |
| 587 } | |
| 588 | |
| 589 SetSingle(common_names, &principal->common_name); | |
| 590 SetSingle(locality_names, &principal->locality_name); | |
| 591 SetSingle(state_names, &principal->state_or_province_name); | |
| 592 SetSingle(country_names, &principal->country_name); | |
| 593 return true; | |
| 594 } | |
| 595 | |
| 549 } // namespace | 596 } // namespace |
| 550 | 597 |
| 551 void X509Certificate::Initialize() { | 598 void X509Certificate::Initialize() { |
| 552 std::wstring subject_info; | |
| 553 std::wstring issuer_info; | |
| 554 DWORD name_size; | |
| 555 DCHECK(cert_handle_); | 599 DCHECK(cert_handle_); |
| 556 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, | 600 ParsePrincipal(cert_handle_->pCertInfo->Subject.pbData, |
| 557 &cert_handle_->pCertInfo->Subject, | 601 cert_handle_->pCertInfo->Subject.cbData, |
| 558 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, | 602 &subject_); |
| 559 NULL, 0); | 603 ParsePrincipal(cert_handle_->pCertInfo->Issuer.pbData, |
| 560 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, | 604 cert_handle_->pCertInfo->Issuer.cbData, |
| 561 &cert_handle_->pCertInfo->Subject, | 605 &issuer_); |
| 562 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, | |
| 563 WriteInto(&subject_info, name_size), name_size); | |
| 564 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, | |
| 565 &cert_handle_->pCertInfo->Issuer, | |
| 566 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, | |
| 567 NULL, 0); | |
| 568 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, | |
| 569 &cert_handle_->pCertInfo->Issuer, | |
| 570 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, | |
| 571 WriteInto(&issuer_info, name_size), name_size); | |
| 572 ParsePrincipal(WideToUTF8(subject_info), &subject_); | |
| 573 ParsePrincipal(WideToUTF8(issuer_info), &issuer_); | |
| 574 | 606 |
| 575 valid_start_ = Time::FromFileTime(cert_handle_->pCertInfo->NotBefore); | 607 valid_start_ = Time::FromFileTime(cert_handle_->pCertInfo->NotBefore); |
| 576 valid_expiry_ = Time::FromFileTime(cert_handle_->pCertInfo->NotAfter); | 608 valid_expiry_ = Time::FromFileTime(cert_handle_->pCertInfo->NotAfter); |
| 577 | 609 |
| 578 fingerprint_ = CalculateFingerprint(cert_handle_); | 610 fingerprint_ = CalculateFingerprint(cert_handle_); |
| 579 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); | 611 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); |
| 580 | 612 |
| 581 const CRYPT_INTEGER_BLOB* serial = &cert_handle_->pCertInfo->SerialNumber; | 613 const CRYPT_INTEGER_BLOB* serial = &cert_handle_->pCertInfo->SerialNumber; |
| 582 scoped_array<uint8> serial_bytes(new uint8[serial->cbData]); | 614 scoped_array<uint8> serial_bytes(new uint8[serial->cbData]); |
| 583 for (unsigned i = 0; i < serial->cbData; i++) | 615 for (unsigned i = 0; i < serial->cbData; i++) |
| (...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1147 if (!CertSerializeCertificateStoreElement(cert_handle, 0, &buffer[0], | 1179 if (!CertSerializeCertificateStoreElement(cert_handle, 0, &buffer[0], |
| 1148 &length)) { | 1180 &length)) { |
| 1149 return false; | 1181 return false; |
| 1150 } | 1182 } |
| 1151 | 1183 |
| 1152 return pickle->WriteData(reinterpret_cast<const char*>(&buffer[0]), | 1184 return pickle->WriteData(reinterpret_cast<const char*>(&buffer[0]), |
| 1153 length); | 1185 length); |
| 1154 } | 1186 } |
| 1155 | 1187 |
| 1156 } // namespace net | 1188 } // namespace net |
| OLD | NEW |