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

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

Issue 5162001: X.509-related cleanup (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More files broke Created 10 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_cert_types.cc ('k') | net/base/x509_cert_types_mac_unittest.cc » ('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) 2010 The Chromium Authors. All rights reserved. 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 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_cert_types.h" 5 #include "net/base/x509_cert_types.h"
6 6
7 #include <CoreServices/CoreServices.h> 7 #include <CoreServices/CoreServices.h>
8 #include <Security/Security.h> 8 #include <Security/Security.h>
9 #include <Security/SecAsn1Coder.h> 9 #include <Security/SecAsn1Coder.h>
10 10
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/i18n/icu_string_conversions.h" 12 #include "base/i18n/icu_string_conversions.h"
13 #include "base/utf_string_conversions.h" 13 #include "base/utf_string_conversions.h"
14 14
15 namespace net { 15 namespace net {
16 16
17 static const CSSM_OID* kOIDs[] = { 17 namespace {
18
19 const CSSM_OID* kOIDs[] = {
18 &CSSMOID_CommonName, 20 &CSSMOID_CommonName,
19 &CSSMOID_LocalityName, 21 &CSSMOID_LocalityName,
20 &CSSMOID_StateProvinceName, 22 &CSSMOID_StateProvinceName,
21 &CSSMOID_CountryName, 23 &CSSMOID_CountryName,
22 &CSSMOID_StreetAddress, 24 &CSSMOID_StreetAddress,
23 &CSSMOID_OrganizationName, 25 &CSSMOID_OrganizationName,
24 &CSSMOID_OrganizationalUnitName, 26 &CSSMOID_OrganizationalUnitName,
25 &CSSMOID_DNQualifier // This should be "DC" but is undoubtedly wrong. 27 &CSSMOID_DNQualifier // This should be "DC" but is undoubtedly wrong.
26 }; // TODO(avi): Find the right OID. 28 }; // TODO(avi): Find the right OID.
27 29
28 // Converts raw CSSM_DATA to a std::string. (Char encoding is unaltered.)
29 static std::string DataToString(CSSM_DATA data);
30
31 // Converts raw CSSM_DATA in ISO-8859-1 to a std::string in UTF-8.
32 static std::string Latin1DataToUTF8String(CSSM_DATA data);
33
34 // Converts big-endian UTF-16 to UTF-8 in a std::string.
35 // Note: The byte-order flipping is done in place on the input buffer!
36 static bool UTF16BigEndianToUTF8(char16* chars, size_t length,
37 std::string* out_string);
38
39 // Converts big-endian UTF-32 to UTF-8 in a std::string.
40 // Note: The byte-order flipping is done in place on the input buffer!
41 static bool UTF32BigEndianToUTF8(char32* chars, size_t length,
42 std::string* out_string);
43
44 // Adds a type+value pair to the appropriate vector from a C array.
45 // The array is keyed by the matching OIDs from kOIDS[].
46 static void AddTypeValuePair(const CSSM_OID type,
47 const std::string& value,
48 std::vector<std::string>* values[]);
49
50 // Stores the first string of the vector, if any, to *single_value.
51 static void SetSingle(const std::vector<std::string> &values,
52 std::string* single_value);
53
54
55 void CertPrincipal::Parse(const CSSM_X509_NAME* name) {
56 std::vector<std::string> common_names, locality_names, state_names,
57 country_names;
58
59 std::vector<std::string>* values[] = {
60 &common_names, &locality_names,
61 &state_names, &country_names,
62 &(this->street_addresses),
63 &(this->organization_names),
64 &(this->organization_unit_names),
65 &(this->domain_components)
66 };
67 DCHECK(arraysize(kOIDs) == arraysize(values));
68
69 for (size_t rdn = 0; rdn < name->numberOfRDNs; ++rdn) {
70 CSSM_X509_RDN rdn_struct = name->RelativeDistinguishedName[rdn];
71 for (size_t pair = 0; pair < rdn_struct.numberOfPairs; ++pair) {
72 CSSM_X509_TYPE_VALUE_PAIR pair_struct =
73 rdn_struct.AttributeTypeAndValue[pair];
74 AddTypeValuePair(pair_struct.type,
75 DataToString(pair_struct.value),
76 values);
77 }
78 }
79
80 SetSingle(common_names, &this->common_name);
81 SetSingle(locality_names, &this->locality_name);
82 SetSingle(state_names, &this->state_or_province_name);
83 SetSingle(country_names, &this->country_name);
84 }
85
86
87 // The following structs and templates work with Apple's very arcane and under- 30 // The following structs and templates work with Apple's very arcane and under-
88 // documented SecAsn1Parser API, which is apparently the same as NSS's ASN.1 31 // documented SecAsn1Parser API, which is apparently the same as NSS's ASN.1
89 // decoder: 32 // decoder:
90 // http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn1.html 33 // http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn1.html
91 34
92 // These are used to parse the contents of a raw 35 // These are used to parse the contents of a raw
93 // BER DistinguishedName structure. 36 // BER DistinguishedName structure.
94 37
95 struct KeyValuePair { 38 struct KeyValuePair {
96 CSSM_OID key; 39 CSSM_OID key;
97 int value_type; 40 int value_type;
98 CSSM_DATA value; 41 CSSM_DATA value;
99 42
100 enum { 43 enum {
101 kTypeOther = 0, 44 kTypeOther = 0,
102 kTypePrintableString, 45 kTypePrintableString,
103 kTypeIA5String, 46 kTypeIA5String,
104 kTypeT61String, 47 kTypeT61String,
105 kTypeUTF8String, 48 kTypeUTF8String,
106 kTypeBMPString, 49 kTypeBMPString,
107 kTypeUniversalString, 50 kTypeUniversalString,
108 }; 51 };
109 }; 52 };
110 53
111 static const SecAsn1Template kStringValueTemplate[] = { 54 const SecAsn1Template kStringValueTemplate[] = {
112 { SEC_ASN1_CHOICE, offsetof(KeyValuePair, value_type), }, 55 { SEC_ASN1_CHOICE, offsetof(KeyValuePair, value_type), },
113 { SEC_ASN1_PRINTABLE_STRING, 56 { SEC_ASN1_PRINTABLE_STRING,
114 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypePrintableString }, 57 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypePrintableString },
115 { SEC_ASN1_IA5_STRING, 58 { SEC_ASN1_IA5_STRING,
116 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeIA5String }, 59 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeIA5String },
117 { SEC_ASN1_T61_STRING, 60 { SEC_ASN1_T61_STRING,
118 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeT61String }, 61 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeT61String },
119 { SEC_ASN1_UTF8_STRING, 62 { SEC_ASN1_UTF8_STRING,
120 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeUTF8String }, 63 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeUTF8String },
121 { SEC_ASN1_BMP_STRING, 64 { SEC_ASN1_BMP_STRING,
122 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeBMPString }, 65 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeBMPString },
123 { SEC_ASN1_UNIVERSAL_STRING, 66 { SEC_ASN1_UNIVERSAL_STRING,
124 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeUniversalString }, 67 offsetof(KeyValuePair, value), 0, KeyValuePair::kTypeUniversalString },
125 { 0, } 68 { 0, }
126 }; 69 };
127 70
128 static const SecAsn1Template kKeyValuePairTemplate[] = { 71 const SecAsn1Template kKeyValuePairTemplate[] = {
129 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KeyValuePair) }, 72 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KeyValuePair) },
130 { SEC_ASN1_OBJECT_ID, offsetof(KeyValuePair, key), }, 73 { SEC_ASN1_OBJECT_ID, offsetof(KeyValuePair, key), },
131 { SEC_ASN1_INLINE, 0, &kStringValueTemplate, }, 74 { SEC_ASN1_INLINE, 0, &kStringValueTemplate, },
132 { 0, } 75 { 0, }
133 }; 76 };
134 77
135 struct KeyValuePairs { 78 struct KeyValuePairs {
136 KeyValuePair* pairs; 79 KeyValuePair* pairs;
137 }; 80 };
138 81
139 static const SecAsn1Template kKeyValuePairSetTemplate[] = { 82 const SecAsn1Template kKeyValuePairSetTemplate[] = {
140 { SEC_ASN1_SET_OF, offsetof(KeyValuePairs,pairs), 83 { SEC_ASN1_SET_OF, offsetof(KeyValuePairs, pairs),
141 kKeyValuePairTemplate, sizeof(KeyValuePairs) } 84 kKeyValuePairTemplate, sizeof(KeyValuePairs) }
142 }; 85 };
143 86
144 struct X509Name { 87 struct X509Name {
145 KeyValuePairs** pairs_list; 88 KeyValuePairs** pairs_list;
146 }; 89 };
147 90
148 static const SecAsn1Template kNameTemplate[] = { 91 const SecAsn1Template kNameTemplate[] = {
149 { SEC_ASN1_SEQUENCE_OF, offsetof(X509Name,pairs_list), 92 { SEC_ASN1_SEQUENCE_OF, offsetof(X509Name, pairs_list),
150 kKeyValuePairSetTemplate, sizeof(X509Name) } 93 kKeyValuePairSetTemplate, sizeof(X509Name) }
151 }; 94 };
152 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.size() > 0)
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
153 bool CertPrincipal::ParseDistinguishedName(const void* ber_name_data, 184 bool CertPrincipal::ParseDistinguishedName(const void* ber_name_data,
154 size_t length) { 185 size_t length) {
155 DCHECK(ber_name_data); 186 DCHECK(ber_name_data);
156 187
157 // First parse the BER |name_data| into the above structs. 188 // First parse the BER |name_data| into the above structs.
158 SecAsn1CoderRef coder = NULL; 189 SecAsn1CoderRef coder = NULL;
159 SecAsn1CoderCreate(&coder); 190 SecAsn1CoderCreate(&coder);
160 DCHECK(coder); 191 DCHECK(coder);
161 X509Name* name = NULL; 192 X509Name* name = NULL;
162 OSStatus err = SecAsn1Decode(coder, ber_name_data, length, kNameTemplate, 193 OSStatus err = SecAsn1Decode(coder, ber_name_data, length, kNameTemplate,
(...skipping 12 matching lines...) Expand all
175 std::vector<std::string>* values[] = { 206 std::vector<std::string>* values[] = {
176 &common_names, &locality_names, 207 &common_names, &locality_names,
177 &state_names, &country_names, 208 &state_names, &country_names,
178 &this->street_addresses, 209 &this->street_addresses,
179 &this->organization_names, 210 &this->organization_names,
180 &this->organization_unit_names, 211 &this->organization_unit_names,
181 &this->domain_components 212 &this->domain_components
182 }; 213 };
183 DCHECK(arraysize(kOIDs) == arraysize(values)); 214 DCHECK(arraysize(kOIDs) == arraysize(values));
184 215
185 for (int rdn=0; name[rdn].pairs_list; ++rdn) { 216 for (int rdn = 0; name[rdn].pairs_list; ++rdn) {
186 KeyValuePair *pair; 217 KeyValuePair *pair;
187 for (int pair_index = 0; 218 for (int pair_index = 0;
188 NULL != (pair = name[rdn].pairs_list[0][pair_index].pairs); 219 NULL != (pair = name[rdn].pairs_list[0][pair_index].pairs);
189 ++pair_index) { 220 ++pair_index) {
190 switch (pair->value_type) { 221 switch (pair->value_type) {
191 case KeyValuePair::kTypeIA5String: // ASCII (that means 7-bit!) 222 case KeyValuePair::kTypeIA5String: // ASCII (that means 7-bit!)
192 case KeyValuePair::kTypePrintableString: // a subset of ASCII 223 case KeyValuePair::kTypePrintableString: // a subset of ASCII
193 case KeyValuePair::kTypeUTF8String: // UTF-8 224 case KeyValuePair::kTypeUTF8String: // UTF-8
194 AddTypeValuePair(pair->key, DataToString(pair->value), values); 225 AddTypeValuePair(pair->key, DataToString(pair->value), values);
195 break; 226 break;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 SetSingle(common_names, &this->common_name); 259 SetSingle(common_names, &this->common_name);
229 SetSingle(locality_names, &this->locality_name); 260 SetSingle(locality_names, &this->locality_name);
230 SetSingle(state_names, &this->state_or_province_name); 261 SetSingle(state_names, &this->state_or_province_name);
231 SetSingle(country_names, &this->country_name); 262 SetSingle(country_names, &this->country_name);
232 263
233 // Releasing |coder| frees all the memory pointed to via |name|. 264 // Releasing |coder| frees all the memory pointed to via |name|.
234 SecAsn1CoderRelease(coder); 265 SecAsn1CoderRelease(coder);
235 return true; 266 return true;
236 } 267 }
237 268
269 void CertPrincipal::Parse(const CSSM_X509_NAME* name) {
270 std::vector<std::string> common_names, locality_names, state_names,
271 country_names;
238 272
239 // SUBROUTINES: 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));
240 282
241 static std::string DataToString(CSSM_DATA data) { 283 for (size_t rdn = 0; rdn < name->numberOfRDNs; ++rdn) {
242 return std::string( 284 CSSM_X509_RDN rdn_struct = name->RelativeDistinguishedName[rdn];
243 reinterpret_cast<std::string::value_type*>(data.Data), 285 for (size_t pair = 0; pair < rdn_struct.numberOfPairs; ++pair) {
244 data.Length); 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);
245 } 298 }
246 299
247 static std::string Latin1DataToUTF8String(CSSM_DATA data) { 300 bool CertPrincipal::Matches(const CertPrincipal& against) const {
248 string16 utf16; 301 return match(common_name, against.common_name) &&
249 if (!CodepageToUTF16(DataToString(data), base::kCodepageLatin1, 302 match(locality_name, against.locality_name) &&
250 base::OnStringConversionError::FAIL, &utf16)) 303 match(state_or_province_name, against.state_or_province_name) &&
251 return ""; 304 match(country_name, against.country_name) &&
252 return UTF16ToUTF8(utf16); 305 match(street_addresses, against.street_addresses) &&
253 } 306 match(organization_names, against.organization_names) &&
254 307 match(organization_unit_names, against.organization_unit_names) &&
255 bool UTF16BigEndianToUTF8(char16* chars, size_t length, 308 match(domain_components, against.domain_components);
256 std::string* out_string) {
257 for (size_t i = 0; i < length; i++)
258 chars[i] = EndianU16_BtoN(chars[i]);
259 return UTF16ToUTF8(chars, length, out_string);
260 }
261
262 bool UTF32BigEndianToUTF8(char32* chars, size_t length,
263 std::string* out_string) {
264 for (size_t i = 0; i < length; i++)
265 chars[i] = EndianS32_BtoN(chars[i]);
266 #if defined(WCHAR_T_IS_UTF32)
267 return WideToUTF8(reinterpret_cast<const wchar_t*>(chars),
268 length, out_string);
269 #else
270 #error This code doesn't handle 16-bit wchar_t.
271 #endif
272 }
273
274 static void AddTypeValuePair(const CSSM_OID type,
275 const std::string& value,
276 std::vector<std::string>* values[]) {
277 for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) {
278 if (CSSMOIDEqual(&type, kOIDs[oid])) {
279 values[oid]->push_back(value);
280 break;
281 }
282 }
283 }
284
285 static void SetSingle(const std::vector<std::string> &values,
286 std::string* single_value) {
287 // We don't expect to have more than one CN, L, S, and C.
288 LOG_IF(WARNING, values.size() > 1) << "Didn't expect multiple values";
289 if (values.size() > 0)
290 *single_value = values[0];
291 } 309 }
292 310
293 } // namespace net 311 } // namespace net
OLDNEW
« no previous file with comments | « net/base/x509_cert_types.cc ('k') | net/base/x509_cert_types_mac_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698