1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/cert/x509_cert_types.h" 6 7 #include <windows.h> 8 #include <wincrypt.h> 9 10 #include "base/logging.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/strings/string_util.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "crypto/capi_util.h" 15 16 #pragma comment(lib, "crypt32.lib") 17 18 namespace net { 19 20 namespace { 21 22 // A list of OIDs to decode. Any OID not on this list will be ignored for 23 // purposes of parsing. 24 const char* kOIDs[] = { 25 szOID_COMMON_NAME, 26 szOID_LOCALITY_NAME, 27 szOID_STATE_OR_PROVINCE_NAME, 28 szOID_COUNTRY_NAME, 29 szOID_STREET_ADDRESS, 30 szOID_ORGANIZATION_NAME, 31 szOID_ORGANIZATIONAL_UNIT_NAME, 32 szOID_DOMAIN_COMPONENT 33 }; 34 35 // Converts the value for |attribute| to an UTF-8 string, storing the result 36 // in |value|. Returns false if the string cannot be converted. 37 bool GetAttributeValue(PCERT_RDN_ATTR attribute, 38 std::string* value) { 39 DWORD chars_needed = CertRDNValueToStrW(attribute->dwValueType, 40 &attribute->Value, NULL, 0); 41 if (chars_needed == 0) 42 return false; 43 if (chars_needed == 1) { 44 // The value is actually an empty string (chars_needed includes a single 45 // char for a NULL value). Don't bother converting - just clear the 46 // string. 47 value->clear(); 48 return true; 49 } 50 std::wstring wide_name; 51 DWORD chars_written = CertRDNValueToStrW( 52 attribute->dwValueType, &attribute->Value, 53 WriteInto(&wide_name, chars_needed), chars_needed); 54 if (chars_written <= 1) 55 return false; 56 wide_name.resize(chars_written - 1); 57 *value = WideToUTF8(wide_name); 58 return true; 59 } 60 61 // Adds a type+value pair to the appropriate vector from a C array. 62 // The array is keyed by the matching OIDs from kOIDS[]. 63 bool AddTypeValuePair(PCERT_RDN_ATTR attribute, 64 std::vector<std::string>* values[]) { 65 for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { 66 if (strcmp(attribute->pszObjId, kOIDs[oid]) == 0) { 67 std::string value; 68 if (!GetAttributeValue(attribute, &value)) 69 return false; 70 values[oid]->push_back(value); 71 break; 72 } 73 } 74 return true; 75 } 76 77 // Stores the first string of the vector, if any, to *single_value. 78 void SetSingle(const std::vector<std::string>& values, 79 std::string* single_value) { 80 // We don't expect to have more than one CN, L, S, and C. 81 LOG_IF(WARNING, values.size() > 1) << "Didn't expect multiple values"; 82 if (!values.empty()) 83 *single_value = values[0]; 84 } 85 86 } // namespace 87 88 bool CertPrincipal::ParseDistinguishedName(const void* ber_name_data, 89 size_t length) { 90 DCHECK(ber_name_data); 91 92 CRYPT_DECODE_PARA decode_para; 93 decode_para.cbSize = sizeof(decode_para); 94 decode_para.pfnAlloc = crypto::CryptAlloc; 95 decode_para.pfnFree = crypto::CryptFree; 96 CERT_NAME_INFO* name_info = NULL; 97 DWORD name_info_size = 0; 98 BOOL rv; 99 rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 100 X509_NAME, 101 reinterpret_cast<const BYTE*>(ber_name_data), 102 length, 103 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, 104 &decode_para, 105 &name_info, &name_info_size); 106 if (!rv) 107 return false; 108 scoped_ptr_malloc<CERT_NAME_INFO> scoped_name_info(name_info); 109 110 std::vector<std::string> common_names, locality_names, state_names, 111 country_names; 112 113 std::vector<std::string>* values[] = { 114 &common_names, &locality_names, 115 &state_names, &country_names, 116 &this->street_addresses, 117 &this->organization_names, 118 &this->organization_unit_names, 119 &this->domain_components 120 }; 121 DCHECK(arraysize(kOIDs) == arraysize(values)); 122 123 for (DWORD cur_rdn = 0; cur_rdn < name_info->cRDN; ++cur_rdn) { 124 PCERT_RDN rdn = &name_info->rgRDN[cur_rdn]; 125 for (DWORD cur_ava = 0; cur_ava < rdn->cRDNAttr; ++cur_ava) { 126 PCERT_RDN_ATTR ava = &rdn->rgRDNAttr[cur_ava]; 127 if (!AddTypeValuePair(ava, values)) 128 return false; 129 } 130 } 131 132 SetSingle(common_names, &this->common_name); 133 SetSingle(locality_names, &this->locality_name); 134 SetSingle(state_names, &this->state_or_province_name); 135 SetSingle(country_names, &this->country_name); 136 return true; 137 } 138 139 } // namespace net 140