Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2010 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/base/x509_cert_types.h"
      6 
      7 #include <CoreServices/CoreServices.h>
      8 #include <Security/Security.h>
      9 #include <Security/SecAsn1Coder.h>
     10 
     11 #include "base/logging.h"
     12 #include "base/i18n/icu_string_conversions.h"
     13 #include "base/utf_string_conversions.h"
     14 
     15 namespace net {
     16 
     17 namespace {
     18 
     19 const CSSM_OID* kOIDs[] = {
     20     &CSSMOID_CommonName,
     21     &CSSMOID_LocalityName,
     22     &CSSMOID_StateProvinceName,
     23     &CSSMOID_CountryName,
     24     &CSSMOID_StreetAddress,
     25     &CSSMOID_OrganizationName,
     26     &CSSMOID_OrganizationalUnitName,
     27     &CSSMOID_DNQualifier      // This should be "DC" but is undoubtedly wrong.
     28 };                            // TODO(avi): Find the right OID.
     29 
     30 // The following structs and templates work with Apple's very arcane and under-
     31 // documented SecAsn1Parser API, which is apparently the same as NSS's ASN.1
     32 // decoder:
     33 // http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn1.html
     34 
     35 // These are used to parse the contents of a raw
     36 // BER DistinguishedName structure.
     37 
     38 struct KeyValuePair {
     39   CSSM_OID key;
     40   int value_type;
     41   CSSM_DATA value;
     42 
     43   enum {
     44     kTypeOther = 0,
     45     kTypePrintableString,
     46     kTypeIA5String,
     47     kTypeT61String,
     48     kTypeUTF8String,
     49     kTypeBMPString,
     50     kTypeUniversalString,
     51   };
     52 };
     53 
     54 const SecAsn1Template kStringValueTemplate[] = {
     55   { SEC_ASN1_CHOICE, offsetof(KeyValuePair, value_type), },
     56   { SEC_ASN1_PRINTABLE_STRING,
     57     offsetof(KeyValuePair, value), 0, KeyValuePair::kTypePrintableString },
     58   { SEC_ASN1_IA5_STRING,
     59     offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeIA5String },
     60   { SEC_ASN1_T61_STRING,
     61     offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeT61String },
     62   { SEC_ASN1_UTF8_STRING,
     63     offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeUTF8String },
     64   { SEC_ASN1_BMP_STRING,
     65     offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeBMPString },
     66   { SEC_ASN1_UNIVERSAL_STRING,
     67     offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeUniversalString },
     68   { 0, }
     69 };
     70 
     71 const SecAsn1Template kKeyValuePairTemplate[] = {
     72   { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KeyValuePair) },
     73   { SEC_ASN1_OBJECT_ID, offsetof(KeyValuePair, key), },
     74   { SEC_ASN1_INLINE, 0, &kStringValueTemplate, },
     75   { 0, }
     76 };
     77 
     78 struct KeyValuePairs {
     79   KeyValuePair* pairs;
     80 };
     81 
     82 const SecAsn1Template kKeyValuePairSetTemplate[] = {
     83   { SEC_ASN1_SET_OF, offsetof(KeyValuePairs, pairs),
     84       kKeyValuePairTemplate, sizeof(KeyValuePairs) }
     85 };
     86 
     87 struct X509Name {
     88   KeyValuePairs** pairs_list;
     89 };
     90 
     91 const SecAsn1Template kNameTemplate[] = {
     92   { SEC_ASN1_SEQUENCE_OF, offsetof(X509Name, pairs_list),
     93       kKeyValuePairSetTemplate, sizeof(X509Name) }
     94 };
     95 
     96 // Converts raw CSSM_DATA to a std::string. (Char encoding is unaltered.)
     97 std::string DataToString(CSSM_DATA data) {
     98   return std::string(
     99       reinterpret_cast<std::string::value_type*>(data.Data),
    100       data.Length);
    101 }
    102 
    103 // Converts raw CSSM_DATA in ISO-8859-1 to a std::string in UTF-8.
    104 std::string Latin1DataToUTF8String(CSSM_DATA data) {
    105   string16 utf16;
    106   if (!CodepageToUTF16(DataToString(data), base::kCodepageLatin1,
    107                        base::OnStringConversionError::FAIL, &utf16))
    108     return "";
    109   return UTF16ToUTF8(utf16);
    110 }
    111 
    112 // Converts big-endian UTF-16 to UTF-8 in a std::string.
    113 // Note: The byte-order flipping is done in place on the input buffer!
    114 bool UTF16BigEndianToUTF8(char16* chars, size_t length,
    115                           std::string* out_string) {
    116   for (size_t i = 0; i < length; i++)
    117     chars[i] = EndianU16_BtoN(chars[i]);
    118   return UTF16ToUTF8(chars, length, out_string);
    119 }
    120 
    121 // Converts big-endian UTF-32 to UTF-8 in a std::string.
    122 // Note: The byte-order flipping is done in place on the input buffer!
    123 bool UTF32BigEndianToUTF8(char32* chars, size_t length,
    124                           std::string* out_string) {
    125   for (size_t i = 0; i < length; ++i)
    126     chars[i] = EndianS32_BtoN(chars[i]);
    127 #if defined(WCHAR_T_IS_UTF32)
    128   return WideToUTF8(reinterpret_cast<const wchar_t*>(chars),
    129                     length, out_string);
    130 #else
    131 #error This code doesn't handle 16-bit wchar_t.
    132 #endif
    133 }
    134 
    135 // Adds a type+value pair to the appropriate vector from a C array.
    136 // The array is keyed by the matching OIDs from kOIDS[].
    137 void AddTypeValuePair(const CSSM_OID type,
    138                       const std::string& value,
    139                       std::vector<std::string>* values[]) {
    140   for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) {
    141     if (CSSMOIDEqual(&type, kOIDs[oid])) {
    142       values[oid]->push_back(value);
    143       break;
    144     }
    145   }
    146 }
    147 
    148 // Stores the first string of the vector, if any, to *single_value.
    149 void SetSingle(const std::vector<std::string>& values,
    150                std::string* single_value) {
    151   // We don't expect to have more than one CN, L, S, and C.
    152   LOG_IF(WARNING, values.size() > 1) << "Didn't expect multiple values";
    153   if (!values.empty())
    154     *single_value = values[0];
    155 }
    156 
    157 bool match(const std::string& str, const std::string& against) {
    158   // TODO(snej): Use the full matching rules specified in RFC 5280 sec. 7.1
    159   // including trimming and case-folding: <http://www.ietf.org/rfc/rfc5280.txt>.
    160   return against == str;
    161 }
    162 
    163 bool match(const std::vector<std::string>& rdn1,
    164            const std::vector<std::string>& rdn2) {
    165   // "Two relative distinguished names RDN1 and RDN2 match if they have the
    166   // same number of naming attributes and for each naming attribute in RDN1
    167   // there is a matching naming attribute in RDN2." --RFC 5280 sec. 7.1.
    168   if (rdn1.size() != rdn2.size())
    169     return false;
    170   for (unsigned i1 = 0; i1 < rdn1.size(); ++i1) {
    171     unsigned i2;
    172     for (i2 = 0; i2 < rdn2.size(); ++i2) {
    173       if (match(rdn1[i1], rdn2[i2]))
    174           break;
    175     }
    176     if (i2 == rdn2.size())
    177       return false;
    178   }
    179   return true;
    180 }
    181 
    182 }  // namespace
    183 
    184 bool CertPrincipal::ParseDistinguishedName(const void* ber_name_data,
    185                                            size_t length) {
    186   DCHECK(ber_name_data);
    187 
    188   // First parse the BER |name_data| into the above structs.
    189   SecAsn1CoderRef coder = NULL;
    190   SecAsn1CoderCreate(&coder);
    191   DCHECK(coder);
    192   X509Name* name = NULL;
    193   OSStatus err = SecAsn1Decode(coder, ber_name_data, length, kNameTemplate,
    194                                &name);
    195   if (err) {
    196     LOG(ERROR) << "SecAsn1Decode returned " << err << "; name=" << name;
    197     SecAsn1CoderRelease(coder);
    198     return false;
    199   }
    200 
    201   // Now scan the structs and add the values to my string vectors.
    202   // I don't store multiple common/locality/state/country names, so use
    203   // temporary vectors for those.
    204   std::vector<std::string> common_names, locality_names, state_names,
    205       country_names;
    206   std::vector<std::string>* values[] = {
    207       &common_names, &locality_names,
    208       &state_names, &country_names,
    209       &this->street_addresses,
    210       &this->organization_names,
    211       &this->organization_unit_names,
    212       &this->domain_components
    213   };
    214   DCHECK(arraysize(kOIDs) == arraysize(values));
    215 
    216   for (int rdn = 0; name[rdn].pairs_list; ++rdn) {
    217     KeyValuePair *pair;
    218     for (int pair_index = 0;
    219          NULL != (pair = name[rdn].pairs_list[0][pair_index].pairs);
    220          ++pair_index) {
    221       switch (pair->value_type) {
    222         case KeyValuePair::kTypeIA5String:          // ASCII (that means 7-bit!)
    223         case KeyValuePair::kTypePrintableString:    // a subset of ASCII
    224         case KeyValuePair::kTypeUTF8String:         // UTF-8
    225           AddTypeValuePair(pair->key, DataToString(pair->value), values);
    226           break;
    227         case KeyValuePair::kTypeT61String:          // T61, pretend it's Latin-1
    228           AddTypeValuePair(pair->key,
    229                            Latin1DataToUTF8String(pair->value),
    230                            values);
    231           break;
    232         case KeyValuePair::kTypeBMPString: {        // UTF-16, big-endian
    233           std::string value;
    234           UTF16BigEndianToUTF8(reinterpret_cast<char16*>(pair->value.Data),
    235                                pair->value.Length / sizeof(char16),
    236                                &value);
    237           AddTypeValuePair(pair->key, value, values);
    238           break;
    239         }
    240         case KeyValuePair::kTypeUniversalString: {  // UTF-32, big-endian
    241           std::string value;
    242           UTF32BigEndianToUTF8(reinterpret_cast<char32*>(pair->value.Data),
    243                                pair->value.Length / sizeof(char32),
    244                                &value);
    245           AddTypeValuePair(pair->key, value, values);
    246           break;
    247         }
    248         default:
    249           DCHECK_EQ(pair->value_type, KeyValuePair::kTypeOther);
    250           // We don't know what data type this is, but we'll store it as a blob.
    251           // Displaying the string may not work, but at least it can be compared
    252           // byte-for-byte by a Matches() call.
    253           AddTypeValuePair(pair->key, DataToString(pair->value), values);
    254           break;
    255       }
    256     }
    257   }
    258 
    259   SetSingle(common_names, &this->common_name);
    260   SetSingle(locality_names, &this->locality_name);
    261   SetSingle(state_names, &this->state_or_province_name);
    262   SetSingle(country_names, &this->country_name);
    263 
    264   // Releasing |coder| frees all the memory pointed to via |name|.
    265   SecAsn1CoderRelease(coder);
    266   return true;
    267 }
    268 
    269 void CertPrincipal::Parse(const CSSM_X509_NAME* name) {
    270   std::vector<std::string> common_names, locality_names, state_names,
    271       country_names;
    272 
    273   std::vector<std::string>* values[] = {
    274       &common_names, &locality_names,
    275       &state_names, &country_names,
    276       &(this->street_addresses),
    277       &(this->organization_names),
    278       &(this->organization_unit_names),
    279       &(this->domain_components)
    280   };
    281   DCHECK(arraysize(kOIDs) == arraysize(values));
    282 
    283   for (size_t rdn = 0; rdn < name->numberOfRDNs; ++rdn) {
    284     CSSM_X509_RDN rdn_struct = name->RelativeDistinguishedName[rdn];
    285     for (size_t pair = 0; pair < rdn_struct.numberOfPairs; ++pair) {
    286       CSSM_X509_TYPE_VALUE_PAIR pair_struct =
    287           rdn_struct.AttributeTypeAndValue[pair];
    288       AddTypeValuePair(pair_struct.type,
    289                        DataToString(pair_struct.value),
    290                        values);
    291     }
    292   }
    293 
    294   SetSingle(common_names, &this->common_name);
    295   SetSingle(locality_names, &this->locality_name);
    296   SetSingle(state_names, &this->state_or_province_name);
    297   SetSingle(country_names, &this->country_name);
    298 }
    299 
    300 bool CertPrincipal::Matches(const CertPrincipal& against) const {
    301   return match(common_name, against.common_name) &&
    302       match(locality_name, against.locality_name) &&
    303       match(state_or_province_name, against.state_or_province_name) &&
    304       match(country_name, against.country_name) &&
    305       match(street_addresses, against.street_addresses) &&
    306       match(organization_names, against.organization_names) &&
    307       match(organization_unit_names, against.organization_unit_names) &&
    308       match(domain_components, against.domain_components);
    309 }
    310 
    311 }  // namespace net
    312