OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/cert/internal/verify_name_match.h" | 5 #include "net/cert/internal/verify_name_match.h" |
6 | 6 |
7 #include "base/base_paths.h" | |
8 #include "base/files/file_path.h" | |
9 #include "base/files/file_util.h" | |
10 #include "base/path_service.h" | |
11 #include "base/strings/string_number_conversions.h" | |
12 #include "base/strings/string_util.h" | |
13 #include "net/cert/pem_tokenizer.h" | |
7 #include "net/der/input.h" | 14 #include "net/der/input.h" |
15 #include "net/der/parser.h" | |
8 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
9 | 17 |
10 namespace net { | 18 namespace net { |
11 | 19 namespace { |
12 TEST(VerifyNameMatchTest, Simple) { | 20 |
13 // TODO(mattm): Use valid Names. | 21 der::Input SequenceValueFromString(const std::string& s) { |
14 const uint8_t hello[] = {'h', 'e', 'l', 'l', 'o'}; | 22 der::Parser parser( |
15 const uint8_t aello[] = {'a', 'e', 'l', 'l', 'o'}; | 23 der::Input(reinterpret_cast<const uint8_t*>(s.data()), s.size())); |
16 const uint8_t hello1[] = {'h', 'e', 'l', 'l', 'o', '1'}; | 24 der::Input data; |
17 EXPECT_TRUE(VerifyNameMatch(der::Input(hello), der::Input(hello))); | 25 if (!parser.ReadTag(der::kSequence, &data)) { |
18 EXPECT_FALSE(VerifyNameMatch(der::Input(aello), der::Input(hello))); | 26 ADD_FAILURE(); |
mattm
2015/08/04 05:02:06
I know this isn't the best way.. but doing an Asse
| |
19 EXPECT_FALSE(VerifyNameMatch(der::Input(hello), der::Input(hello1))); | 27 return der::Input(); |
20 EXPECT_FALSE(VerifyNameMatch(der::Input(hello1), der::Input(hello))); | 28 } |
29 if (parser.HasMore()) { | |
30 ADD_FAILURE(); | |
31 return der::Input(); | |
32 } | |
33 return data; | |
34 } | |
35 | |
36 // Loads test data from file. The filename is constructed from the parameters: | |
37 // |prefix| describes the type of data being tested, e.g. "ascii", | |
38 // "unicode_bmp", "unicode_supplementary", and "invalid". | |
39 // |value_type| indicates what ASN.1 type is used to encode the data. | |
40 // |suffix| indicates any additional modifications, such as caseswapping, | |
41 // whitespace adding, etc. | |
42 ::testing::AssertionResult LoadTestData(const std::string& prefix, | |
43 const std::string& value_type, | |
44 const std::string& suffix, | |
45 std::string* result) { | |
46 base::FilePath src_root; | |
47 PathService::Get(base::DIR_SOURCE_ROOT, &src_root); | |
48 std::string filename = prefix + "-" + value_type + "-" + suffix + ".pem"; | |
49 base::FilePath filepath = | |
50 src_root.Append(FILE_PATH_LITERAL( | |
51 "net/data/verify_name_match_unittest/names")) | |
52 .AppendASCII(filename); | |
53 std::string file_data; | |
54 if (!base::ReadFileToString(filepath, &file_data)) { | |
55 return ::testing::AssertionFailure() | |
56 << "ReadFileToString returned false on " << filename; | |
57 } | |
58 | |
59 std::vector<std::string> pem_headers; | |
60 pem_headers.push_back("NAME"); | |
61 PEMTokenizer pem_tokenizer(file_data, pem_headers); | |
62 if (!pem_tokenizer.GetNext()) { | |
63 return ::testing::AssertionFailure() << "PEM.GetNext returned false on " | |
64 << filename; | |
65 } | |
66 | |
67 result->assign(pem_tokenizer.data()); | |
68 return ::testing::AssertionSuccess(); | |
69 } | |
70 | |
71 bool TypesAreComparable(const std::string& type_1, const std::string& type_2) { | |
72 if (type_1 == type_2) | |
73 return true; | |
74 if ((type_1 == "PRINTABLESTRING" || type_1 == "UTF8" || | |
75 type_1 == "BMPSTRING" || type_1 == "UNIVERSALSTRING") && | |
76 (type_2 == "PRINTABLESTRING" || type_2 == "UTF8" || | |
77 type_2 == "BMPSTRING" || type_2 == "UNIVERSALSTRING")) { | |
78 return true; | |
79 } | |
80 return false; | |
81 } | |
82 | |
83 // All string types. | |
84 static const char* kValueTypes[] = {"PRINTABLESTRING", "T61STRING", "UTF8", | |
85 "BMPSTRING", "UNIVERSALSTRING"}; | |
86 // String types that can encode the Unicode Basic Multilingual Plane. | |
87 static const char* kUnicodeBMPValueTypes[] = {"UTF8", "BMPSTRING", | |
88 "UNIVERSALSTRING"}; | |
89 // String types that can encode the Unicode Supplementary Planes. | |
90 static const char* kUnicodeSupplementaryValueTypes[] = {"UTF8", | |
91 "UNIVERSALSTRING"}; | |
92 | |
93 static const char* kMangleTypes[] = {"unmangled", "case_swap", | |
94 "extra_whitespace"}; | |
95 | |
96 } // namespace | |
97 | |
98 class VerifyNameMatchSimpleTest | |
99 : public ::testing::TestWithParam< | |
100 ::testing::tuple<const char*, const char*>> { | |
101 public: | |
102 std::string value_type() const { return ::testing::get<0>(GetParam()); } | |
103 std::string suffix() const { return ::testing::get<1>(GetParam()); } | |
104 }; | |
105 | |
106 // Compare each input against itself, verifies that all input data is parsed | |
107 // successfully. | |
108 TEST_P(VerifyNameMatchSimpleTest, ExactEquality) { | |
109 std::string der; | |
110 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix(), &der)); | |
111 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(der), | |
112 SequenceValueFromString(der))); | |
113 | |
114 std::string der_extra_attr; | |
115 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix() + "-extra_attr", | |
116 &der_extra_attr)); | |
117 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(der_extra_attr), | |
118 SequenceValueFromString(der_extra_attr))); | |
119 | |
120 std::string der_extra_rdn; | |
121 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix() + "-extra_rdn", | |
122 &der_extra_rdn)); | |
123 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(der_extra_rdn), | |
124 SequenceValueFromString(der_extra_rdn))); | |
125 } | |
126 | |
127 // Ensure that a Name does not match another Name which is exactly the same but | |
128 // with an extra attribute in one Relative Distinguished Name. | |
129 TEST_P(VerifyNameMatchSimpleTest, ExtraAttrDoesNotMatch) { | |
130 std::string der; | |
131 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix(), &der)); | |
132 std::string der_extra_attr; | |
133 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix() + "-extra_attr", | |
134 &der_extra_attr)); | |
135 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(der), | |
136 SequenceValueFromString(der_extra_attr))); | |
137 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(der_extra_attr), | |
138 SequenceValueFromString(der))); | |
139 } | |
140 | |
141 // Ensure that a Name does not match another Name which is exactly the same but | |
142 // with an extra Relative Distinguished Name. | |
143 TEST_P(VerifyNameMatchSimpleTest, ExtraRdnDoesNotMatch) { | |
144 std::string der; | |
145 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix(), &der)); | |
146 std::string der_extra_rdn; | |
147 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix() + "-extra_rdn", | |
148 &der_extra_rdn)); | |
149 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(der), | |
150 SequenceValueFromString(der_extra_rdn))); | |
151 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(der_extra_rdn), | |
152 SequenceValueFromString(der))); | |
153 } | |
154 | |
155 // Runs VerifyNameMatchSimpleTest for all combinations of value_type and and | |
156 // suffix. | |
157 INSTANTIATE_TEST_CASE_P(InstantiationName, | |
158 VerifyNameMatchSimpleTest, | |
159 ::testing::Combine(::testing::ValuesIn(kValueTypes), | |
160 ::testing::ValuesIn(kMangleTypes))); | |
161 | |
162 class VerifyNameMatchNormalizationTest | |
163 : public ::testing::TestWithParam<::testing::tuple<bool, const char*>> { | |
164 public: | |
165 bool expected_result() const { return ::testing::get<0>(GetParam()); } | |
166 std::string value_type() const { return ::testing::get<1>(GetParam()); } | |
167 }; | |
168 | |
169 // Verify matching is case insensitive (for the types which currently support | |
170 // normalization). | |
171 TEST_P(VerifyNameMatchNormalizationTest, CaseInsensitivity) { | |
172 std::string normal; | |
173 ASSERT_TRUE(LoadTestData("ascii", value_type(), "unmangled", &normal)); | |
174 std::string case_swap; | |
175 ASSERT_TRUE(LoadTestData("ascii", value_type(), "case_swap", &case_swap)); | |
176 EXPECT_EQ(expected_result(), | |
177 VerifyNameMatch(SequenceValueFromString(normal), | |
178 SequenceValueFromString(case_swap))); | |
179 EXPECT_EQ(expected_result(), | |
180 VerifyNameMatch(SequenceValueFromString(case_swap), | |
181 SequenceValueFromString(normal))); | |
182 } | |
183 | |
184 // Verify matching folds whitespace (for the types which currently support | |
185 // normalization). | |
186 TEST_P(VerifyNameMatchNormalizationTest, CollapseWhitespace) { | |
187 std::string normal; | |
188 ASSERT_TRUE(LoadTestData("ascii", value_type(), "unmangled", &normal)); | |
189 std::string whitespace; | |
190 ASSERT_TRUE( | |
191 LoadTestData("ascii", value_type(), "extra_whitespace", &whitespace)); | |
192 EXPECT_EQ(expected_result(), | |
193 VerifyNameMatch(SequenceValueFromString(normal), | |
194 SequenceValueFromString(whitespace))); | |
195 EXPECT_EQ(expected_result(), | |
196 VerifyNameMatch(SequenceValueFromString(whitespace), | |
197 SequenceValueFromString(normal))); | |
198 } | |
199 | |
200 // Runs VerifyNameMatchNormalizationTest for each (expected_result, value_type) | |
201 // tuple. | |
202 INSTANTIATE_TEST_CASE_P( | |
203 InstantiationName, | |
204 VerifyNameMatchNormalizationTest, | |
205 ::testing::Values( | |
206 ::testing::make_tuple(true, | |
207 static_cast<const char*>("PRINTABLESTRING")), | |
208 ::testing::make_tuple(false, static_cast<const char*>("T61STRING")), | |
209 ::testing::make_tuple(true, static_cast<const char*>("UTF8")), | |
210 ::testing::make_tuple(true, static_cast<const char*>("BMPSTRING")), | |
211 ::testing::make_tuple(true, | |
212 static_cast<const char*>("UNIVERSALSTRING")))); | |
213 | |
214 class VerifyNameMatchDifferingTypesTest | |
215 : public ::testing::TestWithParam< | |
216 ::testing::tuple<const char*, const char*>> { | |
217 public: | |
218 std::string value_type_1() const { return ::testing::get<0>(GetParam()); } | |
219 std::string value_type_2() const { return ::testing::get<1>(GetParam()); } | |
220 }; | |
221 | |
222 TEST_P(VerifyNameMatchDifferingTypesTest, NormalizableTypesAreEqual) { | |
223 std::string der_1; | |
224 ASSERT_TRUE(LoadTestData("ascii", value_type_1(), "unmangled", &der_1)); | |
225 std::string der_2; | |
226 ASSERT_TRUE(LoadTestData("ascii", value_type_2(), "unmangled", &der_2)); | |
227 if (TypesAreComparable(value_type_1(), value_type_2())) { | |
228 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(der_1), | |
229 SequenceValueFromString(der_2))); | |
230 } else { | |
231 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(der_1), | |
232 SequenceValueFromString(der_2))); | |
233 } | |
234 } | |
235 | |
236 // Runs VerifyNameMatchDifferingTypesTest for all combinations of value types in | |
237 // value_type1 and value_type_2. | |
238 INSTANTIATE_TEST_CASE_P(InstantiationName, | |
239 VerifyNameMatchDifferingTypesTest, | |
240 ::testing::Combine(::testing::ValuesIn(kValueTypes), | |
241 ::testing::ValuesIn(kValueTypes))); | |
242 | |
243 class VerifyNameMatchUnicodeConversionTest | |
244 : public ::testing::TestWithParam< | |
245 ::testing::tuple<const char*, | |
246 ::testing::tuple<const char*, const char*>>> { | |
247 public: | |
248 std::string prefix() const { return ::testing::get<0>(GetParam()); } | |
249 std::string value_type_1() const { | |
250 return ::testing::get<0>(::testing::get<1>(GetParam())); | |
251 } | |
252 std::string value_type_2() const { | |
253 return ::testing::get<1>(::testing::get<1>(GetParam())); | |
254 } | |
255 }; | |
256 | |
257 TEST_P(VerifyNameMatchUnicodeConversionTest, UnicodeConversionsAreEqual) { | |
258 std::string der_1; | |
259 ASSERT_TRUE(LoadTestData(prefix(), value_type_1(), "unmangled", &der_1)); | |
260 std::string der_2; | |
261 ASSERT_TRUE(LoadTestData(prefix(), value_type_2(), "unmangled", &der_2)); | |
262 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(der_1), | |
263 SequenceValueFromString(der_2))); | |
264 } | |
265 | |
266 // Runs VerifyNameMatchUnicodeConversionTest with prefix="unicode_bmp" for all | |
267 // combinations of Basic Multilingual Plane-capable value types in value_type1 | |
268 // and value_type_2. | |
269 INSTANTIATE_TEST_CASE_P( | |
270 BMPConversion, | |
271 VerifyNameMatchUnicodeConversionTest, | |
272 ::testing::Combine( | |
273 ::testing::Values("unicode_bmp"), | |
274 ::testing::Combine(::testing::ValuesIn(kUnicodeBMPValueTypes), | |
275 ::testing::ValuesIn(kUnicodeBMPValueTypes)))); | |
276 | |
277 // Runs VerifyNameMatchUnicodeConversionTest with prefix="unicode_supplementary" | |
278 // for all combinations of Unicode Supplementary Plane-capable value types in | |
279 // value_type1 and value_type_2. | |
280 INSTANTIATE_TEST_CASE_P( | |
281 SMPConversion, | |
282 VerifyNameMatchUnicodeConversionTest, | |
283 ::testing::Combine( | |
284 ::testing::Values("unicode_supplementary"), | |
285 ::testing::Combine( | |
286 ::testing::ValuesIn(kUnicodeSupplementaryValueTypes), | |
287 ::testing::ValuesIn(kUnicodeSupplementaryValueTypes)))); | |
288 | |
289 // Matching should fail if a PrintableString contains invalid characters. | |
290 TEST(VerifyNameMatchInvalidDataTest, FailOnInvalidPrintableStringChars) { | |
291 std::string der; | |
292 ASSERT_TRUE(LoadTestData("ascii", "PRINTABLESTRING", "unmangled", &der)); | |
293 // Find a known location inside a PrintableString in the DER-encoded data. | |
294 size_t replace_location = der.find("0123456789"); | |
295 ASSERT_NE(std::string::npos, replace_location); | |
296 for (int c = 0; c < 256; ++c) { | |
297 SCOPED_TRACE(base::IntToString(c)); | |
298 if (base::IsAsciiAlpha(c) || base::IsAsciiDigit(c)) | |
299 continue; | |
300 switch (c) { | |
301 case ' ': | |
302 case '\'': | |
303 case '(': | |
304 case ')': | |
305 case '*': | |
306 case '+': | |
307 case ',': | |
308 case '-': | |
309 case '.': | |
310 case '/': | |
311 case ':': | |
312 case '=': | |
313 case '?': | |
314 continue; | |
315 } | |
316 der.replace(replace_location, 1, 1, c); | |
317 // Verification should fail due to the invalid character. | |
318 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(der), | |
319 SequenceValueFromString(der))); | |
320 } | |
321 } | |
322 | |
323 // Matching should fail if an IA5String contains invalid characters. | |
324 TEST(VerifyNameMatchInvalidDataTest, FailOnInvalidIA5StringChars) { | |
325 std::string der; | |
326 ASSERT_TRUE(LoadTestData("ascii", "mixed", "rdn_dupetype_sorting_1", &der)); | |
327 // Find a known location inside an IA5String in the DER-encoded data. | |
328 size_t replace_location = der.find("eXaMple"); | |
329 ASSERT_NE(std::string::npos, replace_location); | |
330 for (int c = 0; c < 256; ++c) { | |
331 SCOPED_TRACE(base::IntToString(c)); | |
332 der.replace(replace_location, 1, 1, c); | |
333 bool expected_result = (c <= 127); | |
334 EXPECT_EQ(expected_result, VerifyNameMatch(SequenceValueFromString(der), | |
335 SequenceValueFromString(der))); | |
336 } | |
337 } | |
338 | |
339 TEST(VerifyNameMatchInvalidDataTest, FailOnAttributeTypeAndValueExtraData) { | |
340 std::string invalid; | |
341 ASSERT_TRUE( | |
342 LoadTestData("invalid", "AttributeTypeAndValue", "extradata", &invalid)); | |
343 // Verification should fail due to extra element in AttributeTypeAndValue | |
344 // sequence. | |
345 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(invalid), | |
346 SequenceValueFromString(invalid))); | |
347 } | |
348 | |
349 TEST(VerifyNameMatchInvalidDataTest, FailOnAttributeTypeAndValueShort) { | |
350 std::string invalid; | |
351 ASSERT_TRUE(LoadTestData("invalid", "AttributeTypeAndValue", "onlyOneElement", | |
352 &invalid)); | |
353 // Verification should fail due to AttributeTypeAndValue sequence having only | |
354 // one element. | |
355 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(invalid), | |
356 SequenceValueFromString(invalid))); | |
357 } | |
358 | |
359 TEST(VerifyNameMatchInvalidDataTest, FailOnAttributeTypeAndValueEmpty) { | |
360 std::string invalid; | |
361 ASSERT_TRUE( | |
362 LoadTestData("invalid", "AttributeTypeAndValue", "empty", &invalid)); | |
363 // Verification should fail due to empty AttributeTypeAndValue sequence. | |
364 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(invalid), | |
365 SequenceValueFromString(invalid))); | |
366 } | |
367 | |
368 TEST(VerifyNameMatchInvalidDataTest, FailOnBadAttributeType) { | |
369 std::string invalid; | |
370 ASSERT_TRUE(LoadTestData("invalid", "AttributeTypeAndValue", | |
371 "badAttributeType", &invalid)); | |
372 // Verification should fail due to Attribute Type not being an OID. | |
373 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(invalid), | |
374 SequenceValueFromString(invalid))); | |
375 } | |
376 | |
377 TEST(VerifyNameMatchInvalidDataTest, FailOnAttributeTypeAndValueNotSequence) { | |
378 std::string invalid; | |
379 ASSERT_TRUE(LoadTestData("invalid", "AttributeTypeAndValue", "setNotSequence", | |
380 &invalid)); | |
381 // Verification should fail due to AttributeTypeAndValue being a Set instead | |
382 // of a Sequence. | |
383 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(invalid), | |
384 SequenceValueFromString(invalid))); | |
385 } | |
386 | |
387 TEST(VerifyNameMatchInvalidDataTest, FailOnRdnNotSet) { | |
388 std::string invalid; | |
389 ASSERT_TRUE(LoadTestData("invalid", "RDN", "sequenceInsteadOfSet", &invalid)); | |
390 // Verification should fail due to RDN being a Sequence instead of a Set. | |
391 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(invalid), | |
392 SequenceValueFromString(invalid))); | |
393 } | |
394 | |
395 TEST(VerifyNameMatchInvalidDataTest, FailOnEmptyRdn) { | |
396 std::string invalid; | |
397 ASSERT_TRUE(LoadTestData("invalid", "RDN", "empty", &invalid)); | |
398 // Verification should fail due to RDN having zero AttributeTypeAndValues. | |
399 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(invalid), | |
400 SequenceValueFromString(invalid))); | |
401 } | |
402 | |
403 // Matching should fail if a BMPString contains surrogates. | |
404 TEST(VerifyNameMatchInvalidDataTest, FailOnBmpStringSurrogates) { | |
405 std::string normal; | |
406 ASSERT_TRUE(LoadTestData("unicode_bmp", "BMPSTRING", "unmangled", &normal)); | |
407 // Find a known location inside a BMPSTRING in the DER-encoded data. | |
408 size_t replace_location = normal.find("\x67\x71\x4e\xac"); | |
409 ASSERT_NE(std::string::npos, replace_location); | |
410 // Replace with U+1D400 MATHEMATICAL BOLD CAPITAL A, which requires surrogates | |
411 // to represent. | |
412 std::string invalid = | |
413 normal.replace(replace_location, 4, std::string("\xd8\x35\xdc\x00", 4)); | |
414 // Verification should fail due to the invalid codepoints. | |
415 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(invalid), | |
416 SequenceValueFromString(invalid))); | |
417 } | |
418 | |
419 TEST(VerifyNameMatchTest, EmptyNameMatching) { | |
420 std::string empty; | |
421 ASSERT_TRUE(LoadTestData("valid", "Name", "empty", &empty)); | |
422 // Empty names are equal. | |
423 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(empty), | |
424 SequenceValueFromString(empty))); | |
425 | |
426 // An empty name is not equal to non-empty name. | |
427 std::string non_empty; | |
428 ASSERT_TRUE( | |
429 LoadTestData("ascii", "PRINTABLESTRING", "unmangled", &non_empty)); | |
430 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(empty), | |
431 SequenceValueFromString(non_empty))); | |
432 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(non_empty), | |
433 SequenceValueFromString(empty))); | |
434 } | |
435 | |
436 // Matching should succeed when the RDNs are sorted differently but are still | |
437 // equal after normalizing. | |
438 TEST(VerifyNameMatchRDNSorting, Simple) { | |
439 std::string a; | |
440 ASSERT_TRUE(LoadTestData("ascii", "PRINTABLESTRING", "rdn_sorting_1", &a)); | |
441 std::string b; | |
442 ASSERT_TRUE(LoadTestData("ascii", "PRINTABLESTRING", "rdn_sorting_2", &b)); | |
443 EXPECT_TRUE( | |
444 VerifyNameMatch(SequenceValueFromString(a), SequenceValueFromString(b))); | |
445 EXPECT_TRUE( | |
446 VerifyNameMatch(SequenceValueFromString(b), SequenceValueFromString(a))); | |
447 } | |
448 | |
449 // Matching should succeed when the RDNs are sorted differently but are still | |
450 // equal after normalizing, even in malformed RDNs that contain multiple | |
451 // elements with the same type. | |
452 TEST(VerifyNameMatchRDNSorting, DuplicateTypes) { | |
453 std::string a; | |
454 ASSERT_TRUE(LoadTestData("ascii", "mixed", "rdn_dupetype_sorting_1", &a)); | |
455 std::string b; | |
456 ASSERT_TRUE(LoadTestData("ascii", "mixed", "rdn_dupetype_sorting_2", &b)); | |
457 EXPECT_TRUE( | |
458 VerifyNameMatch(SequenceValueFromString(a), SequenceValueFromString(b))); | |
459 EXPECT_TRUE( | |
460 VerifyNameMatch(SequenceValueFromString(b), SequenceValueFromString(a))); | |
21 } | 461 } |
22 | 462 |
23 } // namespace net | 463 } // namespace net |
OLD | NEW |