This source file includes following definitions.
- DataToString
- Latin1DataToUTF8String
- UTF16BigEndianToUTF8
- UTF32BigEndianToUTF8
- AddTypeValuePair
- SetSingle
- match
- match
- ParseDistinguishedName
- Matches
#include "net/cert/x509_cert_types.h"
#include <stdint.h>
#include <CoreServices/CoreServices.h>
#include <Security/SecAsn1Coder.h>
#include <Security/Security.h>
#include "base/i18n/icu_string_conversions.h"
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "base/strings/utf_string_conversions.h"
namespace net {
namespace {
const uint8 kDomainComponentData[] = {
0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19
};
const CSSM_OID kDomainComponentOID = {
arraysize(kDomainComponentData),
const_cast<uint8*>(kDomainComponentData)
};
const CSSM_OID* kOIDs[] = {
&CSSMOID_CommonName,
&CSSMOID_LocalityName,
&CSSMOID_StateProvinceName,
&CSSMOID_CountryName,
&CSSMOID_StreetAddress,
&CSSMOID_OrganizationName,
&CSSMOID_OrganizationalUnitName,
&kDomainComponentOID,
};
const SecAsn1Template kStringValueTemplate[] = {
{ SEC_ASN1_CHOICE, offsetof(CSSM_X509_TYPE_VALUE_PAIR, valueType), },
{ SEC_ASN1_PRINTABLE_STRING,
offsetof(CSSM_X509_TYPE_VALUE_PAIR, value), 0,
BER_TAG_PRINTABLE_STRING },
{ SEC_ASN1_IA5_STRING,
offsetof(CSSM_X509_TYPE_VALUE_PAIR, value), 0,
BER_TAG_IA5_STRING },
{ SEC_ASN1_T61_STRING,
offsetof(CSSM_X509_TYPE_VALUE_PAIR, value), 0,
BER_TAG_T61_STRING },
{ SEC_ASN1_UTF8_STRING,
offsetof(CSSM_X509_TYPE_VALUE_PAIR, value), 0,
BER_TAG_PKIX_UTF8_STRING },
{ SEC_ASN1_BMP_STRING,
offsetof(CSSM_X509_TYPE_VALUE_PAIR, value), 0,
BER_TAG_PKIX_BMP_STRING },
{ SEC_ASN1_UNIVERSAL_STRING,
offsetof(CSSM_X509_TYPE_VALUE_PAIR, value), 0,
BER_TAG_PKIX_UNIVERSAL_STRING },
{ 0, }
};
const SecAsn1Template kKeyValuePairTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CSSM_X509_TYPE_VALUE_PAIR) },
{ SEC_ASN1_OBJECT_ID, offsetof(CSSM_X509_TYPE_VALUE_PAIR, type), },
{ SEC_ASN1_INLINE, 0, &kStringValueTemplate, },
{ 0, }
};
struct KeyValuePairs {
CSSM_X509_TYPE_VALUE_PAIR* pairs;
};
const SecAsn1Template kKeyValuePairSetTemplate[] = {
{ SEC_ASN1_SET_OF, offsetof(KeyValuePairs, pairs),
kKeyValuePairTemplate, sizeof(KeyValuePairs) }
};
struct X509Name {
KeyValuePairs** pairs_list;
};
const SecAsn1Template kNameTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF, offsetof(X509Name, pairs_list),
kKeyValuePairSetTemplate, sizeof(X509Name) }
};
std::string DataToString(CSSM_DATA data) {
return std::string(
reinterpret_cast<std::string::value_type*>(data.Data),
data.Length);
}
std::string Latin1DataToUTF8String(CSSM_DATA data) {
base::string16 utf16;
if (!CodepageToUTF16(DataToString(data), base::kCodepageLatin1,
base::OnStringConversionError::FAIL, &utf16))
return "";
return base::UTF16ToUTF8(utf16);
}
bool UTF16BigEndianToUTF8(base::char16* chars, size_t length,
std::string* out_string) {
for (size_t i = 0; i < length; i++)
chars[i] = EndianU16_BtoN(chars[i]);
return base::UTF16ToUTF8(chars, length, out_string);
}
bool UTF32BigEndianToUTF8(int32_t* chars, size_t length,
std::string* out_string) {
for (size_t i = 0; i < length; ++i)
chars[i] = EndianS32_BtoN(chars[i]);
#if defined(WCHAR_T_IS_UTF32)
return base::WideToUTF8(reinterpret_cast<const wchar_t*>(chars),
length, out_string);
#else
#error This code doesn't handle 16-bit wchar_t.
#endif
}
void AddTypeValuePair(const CSSM_OID type,
const std::string& value,
std::vector<std::string>* values[]) {
for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) {
if (CSSMOIDEqual(&type, kOIDs[oid])) {
values[oid]->push_back(value);
break;
}
}
}
void SetSingle(const std::vector<std::string>& values,
std::string* single_value) {
LOG_IF(WARNING, values.size() > 1) << "Didn't expect multiple values";
if (!values.empty())
*single_value = values[0];
}
bool match(const std::string& str, const std::string& against) {
return against == str;
}
bool match(const std::vector<std::string>& rdn1,
const std::vector<std::string>& rdn2) {
if (rdn1.size() != rdn2.size())
return false;
for (unsigned i1 = 0; i1 < rdn1.size(); ++i1) {
unsigned i2;
for (i2 = 0; i2 < rdn2.size(); ++i2) {
if (match(rdn1[i1], rdn2[i2]))
break;
}
if (i2 == rdn2.size())
return false;
}
return true;
}
}
bool CertPrincipal::ParseDistinguishedName(const void* ber_name_data,
size_t length) {
DCHECK(ber_name_data);
SecAsn1CoderRef coder = NULL;
SecAsn1CoderCreate(&coder);
DCHECK(coder);
X509Name* name = NULL;
OSStatus err = SecAsn1Decode(coder, ber_name_data, length, kNameTemplate,
&name);
if (err) {
OSSTATUS_LOG(ERROR, err) << "SecAsn1Decode";
SecAsn1CoderRelease(coder);
return false;
}
std::vector<std::string> common_names, locality_names, state_names,
country_names;
std::vector<std::string>* values[] = {
&common_names, &locality_names,
&state_names, &country_names,
&this->street_addresses,
&this->organization_names,
&this->organization_unit_names,
&this->domain_components
};
DCHECK(arraysize(kOIDs) == arraysize(values));
for (int rdn = 0; name[rdn].pairs_list; ++rdn) {
CSSM_X509_TYPE_VALUE_PAIR* pair;
for (int pair_index = 0;
NULL != (pair = name[rdn].pairs_list[0][pair_index].pairs);
++pair_index) {
switch (pair->valueType) {
case BER_TAG_IA5_STRING:
case BER_TAG_PRINTABLE_STRING:
case BER_TAG_PKIX_UTF8_STRING:
AddTypeValuePair(pair->type, DataToString(pair->value), values);
break;
case BER_TAG_T61_STRING:
AddTypeValuePair(pair->type,
Latin1DataToUTF8String(pair->value),
values);
break;
case BER_TAG_PKIX_BMP_STRING: {
std::string value;
UTF16BigEndianToUTF8(
reinterpret_cast<base::char16*>(pair->value.Data),
pair->value.Length / sizeof(base::char16),
&value);
AddTypeValuePair(pair->type, value, values);
break;
}
case BER_TAG_PKIX_UNIVERSAL_STRING: {
std::string value;
UTF32BigEndianToUTF8(reinterpret_cast<int32_t*>(pair->value.Data),
pair->value.Length / sizeof(int32_t),
&value);
AddTypeValuePair(pair->type, value, values);
break;
}
default:
DCHECK_EQ(pair->valueType, BER_TAG_UNKNOWN);
AddTypeValuePair(pair->type, DataToString(pair->value), values);
break;
}
}
}
SetSingle(common_names, &this->common_name);
SetSingle(locality_names, &this->locality_name);
SetSingle(state_names, &this->state_or_province_name);
SetSingle(country_names, &this->country_name);
SecAsn1CoderRelease(coder);
return true;
}
bool CertPrincipal::Matches(const CertPrincipal& against) const {
return match(common_name, against.common_name) &&
match(locality_name, against.locality_name) &&
match(state_or_province_name, against.state_or_province_name) &&
match(country_name, against.country_name) &&
match(street_addresses, against.street_addresses) &&
match(organization_names, against.organization_names) &&
match(organization_unit_names, against.organization_unit_names) &&
match(domain_components, against.domain_components);
}
}