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 |