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 |