| 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(CERT_NAME_BLOB* name, CertPrincipal* principal) { |
| 547 CRYPT_DECODE_PARA decode_para; |
| 548 decode_para.cbSize = sizeof(decode_para); |
| 549 decode_para.pfnAlloc = MyCryptAlloc; |
| 550 decode_para.pfnFree = MyCryptFree; |
| 551 CERT_NAME_INFO* name_info = NULL; |
| 552 DWORD name_info_size = 0; |
| 553 BOOL rv; |
| 554 rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, |
| 555 X509_NAME, name->pbData, name->cbData, |
| 556 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, |
| 557 &decode_para, |
| 558 &name_info, &name_info_size); |
| 559 if (!rv) |
| 560 return false; |
| 561 scoped_ptr_malloc<CERT_NAME_INFO> scoped_name_info(name_info); |
| 562 |
| 563 std::vector<std::string> common_names, locality_names, state_names, |
| 564 country_names; |
| 565 |
| 566 std::vector<std::string>* values[] = { |
| 567 &common_names, &locality_names, |
| 568 &state_names, &country_names, |
| 569 &(principal->street_addresses), |
| 570 &(principal->organization_names), |
| 571 &(principal->organization_unit_names), |
| 572 &(principal->domain_components) |
| 573 }; |
| 574 DCHECK(arraysize(kOIDs) == arraysize(values)); |
| 575 |
| 576 for (DWORD cur_rdn = 0; cur_rdn < name_info->cRDN; ++cur_rdn) { |
| 577 PCERT_RDN rdn = &name_info->rgRDN[cur_rdn]; |
| 578 for (DWORD cur_ava = 0; cur_ava < rdn->cRDNAttr; ++cur_ava) { |
| 579 PCERT_RDN_ATTR ava = &rdn->rgRDNAttr[cur_ava]; |
| 580 if (!AddTypeValuePair(ava, values)) |
| 581 return false; |
| 582 } |
| 583 } |
| 584 |
| 585 SetSingle(common_names, &principal->common_name); |
| 586 SetSingle(locality_names, &principal->locality_name); |
| 587 SetSingle(state_names, &principal->state_or_province_name); |
| 588 SetSingle(country_names, &principal->country_name); |
| 589 return true; |
| 590 } |
| 591 |
| 549 } // namespace | 592 } // namespace |
| 550 | 593 |
| 551 void X509Certificate::Initialize() { | 594 void X509Certificate::Initialize() { |
| 552 std::wstring subject_info; | |
| 553 std::wstring issuer_info; | |
| 554 DWORD name_size; | |
| 555 DCHECK(cert_handle_); | 595 DCHECK(cert_handle_); |
| 556 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, | 596 ParsePrincipal(&cert_handle_->pCertInfo->Subject, &subject_); |
| 557 &cert_handle_->pCertInfo->Subject, | 597 ParsePrincipal(&cert_handle_->pCertInfo->Issuer, &issuer_); |
| 558 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, | |
| 559 NULL, 0); | |
| 560 if (name_size > 1) { | |
| 561 CertNameToStr(cert_handle_->dwCertEncodingType, | |
| 562 &cert_handle_->pCertInfo->Subject, | |
| 563 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, | |
| 564 WriteInto(&subject_info, name_size), name_size); | |
| 565 } | |
| 566 name_size = CertNameToStr(cert_handle_->dwCertEncodingType, | |
| 567 &cert_handle_->pCertInfo->Issuer, | |
| 568 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, | |
| 569 NULL, 0); | |
| 570 if (name_size > 1) { | |
| 571 CertNameToStr(cert_handle_->dwCertEncodingType, | |
| 572 &cert_handle_->pCertInfo->Issuer, | |
| 573 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, | |
| 574 WriteInto(&issuer_info, name_size), name_size); | |
| 575 } | |
| 576 ParsePrincipal(WideToUTF8(subject_info), &subject_); | |
| 577 ParsePrincipal(WideToUTF8(issuer_info), &issuer_); | |
| 578 | 598 |
| 579 valid_start_ = Time::FromFileTime(cert_handle_->pCertInfo->NotBefore); | 599 valid_start_ = Time::FromFileTime(cert_handle_->pCertInfo->NotBefore); |
| 580 valid_expiry_ = Time::FromFileTime(cert_handle_->pCertInfo->NotAfter); | 600 valid_expiry_ = Time::FromFileTime(cert_handle_->pCertInfo->NotAfter); |
| 581 | 601 |
| 582 fingerprint_ = CalculateFingerprint(cert_handle_); | 602 fingerprint_ = CalculateFingerprint(cert_handle_); |
| 583 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); | 603 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); |
| 584 | 604 |
| 585 const CRYPT_INTEGER_BLOB* serial = &cert_handle_->pCertInfo->SerialNumber; | 605 const CRYPT_INTEGER_BLOB* serial = &cert_handle_->pCertInfo->SerialNumber; |
| 586 scoped_array<uint8> serial_bytes(new uint8[serial->cbData]); | 606 scoped_array<uint8> serial_bytes(new uint8[serial->cbData]); |
| 587 for (unsigned i = 0; i < serial->cbData; i++) | 607 for (unsigned i = 0; i < serial->cbData; i++) |
| (...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1151 if (!CertSerializeCertificateStoreElement(cert_handle, 0, &buffer[0], | 1171 if (!CertSerializeCertificateStoreElement(cert_handle, 0, &buffer[0], |
| 1152 &length)) { | 1172 &length)) { |
| 1153 return false; | 1173 return false; |
| 1154 } | 1174 } |
| 1155 | 1175 |
| 1156 return pickle->WriteData(reinterpret_cast<const char*>(&buffer[0]), | 1176 return pickle->WriteData(reinterpret_cast<const char*>(&buffer[0]), |
| 1157 length); | 1177 length); |
| 1158 } | 1178 } |
| 1159 | 1179 |
| 1160 } // namespace net | 1180 } // namespace net |
| OLD | NEW |