Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Side by Side Diff: net/base/x509_certificate_win.cc

Issue 8608003: Parse individual X.509 name components on Windows, rather than their stringified form (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Anonymized certs Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/x509_certificate_unittest.cc ('k') | net/data/ssl/certificates/README » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « net/base/x509_certificate_unittest.cc ('k') | net/data/ssl/certificates/README » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698