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
3 // found in the LICENSE file.
5 #include "net/cert/internal/verify_name_match.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/string_util.h"
9 #include "net/cert/internal/test_helpers.h"
10 #include "net/der/input.h"
11 #include "net/der/parser.h"
12 #include "testing/gtest/include/gtest/gtest.h"
17 der::Input
SequenceValueFromString(const std::string
* s
) {
18 der::Parser
parser(InputFromString(s
));
20 if (!parser
.ReadTag(der::kSequence
, &data
)) {
24 if (parser
.HasMore()) {
31 // Loads test data from file. The filename is constructed from the parameters:
32 // |prefix| describes the type of data being tested, e.g. "ascii",
33 // "unicode_bmp", "unicode_supplementary", and "invalid".
34 // |value_type| indicates what ASN.1 type is used to encode the data.
35 // |suffix| indicates any additional modifications, such as caseswapping,
36 // whitespace adding, etc.
37 ::testing::AssertionResult
LoadTestData(const std::string
& prefix
,
38 const std::string
& value_type
,
39 const std::string
& suffix
,
40 std::string
* result
) {
41 std::string path
= "net/data/verify_name_match_unittest/names/" + prefix
+
42 "-" + value_type
+ "-" + suffix
+ ".pem";
44 const PemBlockMapping mappings
[] = {
48 return ReadTestDataFromPemFile(path
, mappings
);
51 bool TypesAreComparable(const std::string
& type_1
, const std::string
& type_2
) {
54 if ((type_1
== "PRINTABLESTRING" || type_1
== "UTF8" ||
55 type_1
== "BMPSTRING" || type_1
== "UNIVERSALSTRING") &&
56 (type_2
== "PRINTABLESTRING" || type_2
== "UTF8" ||
57 type_2
== "BMPSTRING" || type_2
== "UNIVERSALSTRING")) {
64 static const char* kValueTypes
[] = {"PRINTABLESTRING", "T61STRING", "UTF8",
65 "BMPSTRING", "UNIVERSALSTRING"};
66 // String types that can encode the Unicode Basic Multilingual Plane.
67 static const char* kUnicodeBMPValueTypes
[] = {"UTF8", "BMPSTRING",
69 // String types that can encode the Unicode Supplementary Planes.
70 static const char* kUnicodeSupplementaryValueTypes
[] = {"UTF8",
73 static const char* kMangleTypes
[] = {"unmangled", "case_swap",
78 class VerifyNameMatchSimpleTest
79 : public ::testing::TestWithParam
<
80 ::testing::tuple
<const char*, const char*>> {
82 std::string
value_type() const { return ::testing::get
<0>(GetParam()); }
83 std::string
suffix() const { return ::testing::get
<1>(GetParam()); }
86 // Compare each input against itself, verifies that all input data is parsed
88 TEST_P(VerifyNameMatchSimpleTest
, ExactEquality
) {
90 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix(), &der
));
91 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&der
),
92 SequenceValueFromString(&der
)));
94 std::string der_extra_attr
;
95 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix() + "-extra_attr",
97 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&der_extra_attr
),
98 SequenceValueFromString(&der_extra_attr
)));
100 std::string der_extra_rdn
;
101 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix() + "-extra_rdn",
103 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&der_extra_rdn
),
104 SequenceValueFromString(&der_extra_rdn
)));
107 // Ensure that a Name does not match another Name which is exactly the same but
108 // with an extra attribute in one Relative Distinguished Name.
109 TEST_P(VerifyNameMatchSimpleTest
, ExtraAttrDoesNotMatch
) {
111 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix(), &der
));
112 std::string der_extra_attr
;
113 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix() + "-extra_attr",
115 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&der
),
116 SequenceValueFromString(&der_extra_attr
)));
117 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&der_extra_attr
),
118 SequenceValueFromString(&der
)));
121 // Ensure that a Name does not match another Name which is exactly the same but
122 // with an extra Relative Distinguished Name.
123 TEST_P(VerifyNameMatchSimpleTest
, ExtraRdnDoesNotMatch
) {
125 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix(), &der
));
126 std::string der_extra_rdn
;
127 ASSERT_TRUE(LoadTestData("ascii", value_type(), suffix() + "-extra_rdn",
129 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&der
),
130 SequenceValueFromString(&der_extra_rdn
)));
131 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&der_extra_rdn
),
132 SequenceValueFromString(&der
)));
135 // Runs VerifyNameMatchSimpleTest for all combinations of value_type and and
137 INSTANTIATE_TEST_CASE_P(InstantiationName
,
138 VerifyNameMatchSimpleTest
,
139 ::testing::Combine(::testing::ValuesIn(kValueTypes
),
140 ::testing::ValuesIn(kMangleTypes
)));
142 class VerifyNameMatchNormalizationTest
143 : public ::testing::TestWithParam
<::testing::tuple
<bool, const char*>> {
145 bool expected_result() const { return ::testing::get
<0>(GetParam()); }
146 std::string
value_type() const { return ::testing::get
<1>(GetParam()); }
149 // Verify matching is case insensitive (for the types which currently support
151 TEST_P(VerifyNameMatchNormalizationTest
, CaseInsensitivity
) {
153 ASSERT_TRUE(LoadTestData("ascii", value_type(), "unmangled", &normal
));
154 std::string case_swap
;
155 ASSERT_TRUE(LoadTestData("ascii", value_type(), "case_swap", &case_swap
));
156 EXPECT_EQ(expected_result(),
157 VerifyNameMatch(SequenceValueFromString(&normal
),
158 SequenceValueFromString(&case_swap
)));
159 EXPECT_EQ(expected_result(),
160 VerifyNameMatch(SequenceValueFromString(&case_swap
),
161 SequenceValueFromString(&normal
)));
164 // Verify matching folds whitespace (for the types which currently support
166 TEST_P(VerifyNameMatchNormalizationTest
, CollapseWhitespace
) {
168 ASSERT_TRUE(LoadTestData("ascii", value_type(), "unmangled", &normal
));
169 std::string whitespace
;
171 LoadTestData("ascii", value_type(), "extra_whitespace", &whitespace
));
172 EXPECT_EQ(expected_result(),
173 VerifyNameMatch(SequenceValueFromString(&normal
),
174 SequenceValueFromString(&whitespace
)));
175 EXPECT_EQ(expected_result(),
176 VerifyNameMatch(SequenceValueFromString(&whitespace
),
177 SequenceValueFromString(&normal
)));
180 // Runs VerifyNameMatchNormalizationTest for each (expected_result, value_type)
182 INSTANTIATE_TEST_CASE_P(
184 VerifyNameMatchNormalizationTest
,
186 ::testing::make_tuple(true,
187 static_cast<const char*>("PRINTABLESTRING")),
188 ::testing::make_tuple(false, static_cast<const char*>("T61STRING")),
189 ::testing::make_tuple(true, static_cast<const char*>("UTF8")),
190 ::testing::make_tuple(true, static_cast<const char*>("BMPSTRING")),
191 ::testing::make_tuple(true,
192 static_cast<const char*>("UNIVERSALSTRING"))));
194 class VerifyNameMatchDifferingTypesTest
195 : public ::testing::TestWithParam
<
196 ::testing::tuple
<const char*, const char*>> {
198 std::string
value_type_1() const { return ::testing::get
<0>(GetParam()); }
199 std::string
value_type_2() const { return ::testing::get
<1>(GetParam()); }
202 TEST_P(VerifyNameMatchDifferingTypesTest
, NormalizableTypesAreEqual
) {
204 ASSERT_TRUE(LoadTestData("ascii", value_type_1(), "unmangled", &der_1
));
206 ASSERT_TRUE(LoadTestData("ascii", value_type_2(), "unmangled", &der_2
));
207 if (TypesAreComparable(value_type_1(), value_type_2())) {
208 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&der_1
),
209 SequenceValueFromString(&der_2
)));
211 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&der_1
),
212 SequenceValueFromString(&der_2
)));
216 // Runs VerifyNameMatchDifferingTypesTest for all combinations of value types in
217 // value_type1 and value_type_2.
218 INSTANTIATE_TEST_CASE_P(InstantiationName
,
219 VerifyNameMatchDifferingTypesTest
,
220 ::testing::Combine(::testing::ValuesIn(kValueTypes
),
221 ::testing::ValuesIn(kValueTypes
)));
223 class VerifyNameMatchUnicodeConversionTest
224 : public ::testing::TestWithParam
<
225 ::testing::tuple
<const char*,
226 ::testing::tuple
<const char*, const char*>>> {
228 std::string
prefix() const { return ::testing::get
<0>(GetParam()); }
229 std::string
value_type_1() const {
230 return ::testing::get
<0>(::testing::get
<1>(GetParam()));
232 std::string
value_type_2() const {
233 return ::testing::get
<1>(::testing::get
<1>(GetParam()));
237 TEST_P(VerifyNameMatchUnicodeConversionTest
, UnicodeConversionsAreEqual
) {
239 ASSERT_TRUE(LoadTestData(prefix(), value_type_1(), "unmangled", &der_1
));
241 ASSERT_TRUE(LoadTestData(prefix(), value_type_2(), "unmangled", &der_2
));
242 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&der_1
),
243 SequenceValueFromString(&der_2
)));
246 // Runs VerifyNameMatchUnicodeConversionTest with prefix="unicode_bmp" for all
247 // combinations of Basic Multilingual Plane-capable value types in value_type1
249 INSTANTIATE_TEST_CASE_P(
251 VerifyNameMatchUnicodeConversionTest
,
253 ::testing::Values("unicode_bmp"),
254 ::testing::Combine(::testing::ValuesIn(kUnicodeBMPValueTypes
),
255 ::testing::ValuesIn(kUnicodeBMPValueTypes
))));
257 // Runs VerifyNameMatchUnicodeConversionTest with prefix="unicode_supplementary"
258 // for all combinations of Unicode Supplementary Plane-capable value types in
259 // value_type1 and value_type_2.
260 INSTANTIATE_TEST_CASE_P(
262 VerifyNameMatchUnicodeConversionTest
,
264 ::testing::Values("unicode_supplementary"),
266 ::testing::ValuesIn(kUnicodeSupplementaryValueTypes
),
267 ::testing::ValuesIn(kUnicodeSupplementaryValueTypes
))));
269 // Matching should fail if a PrintableString contains invalid characters.
270 TEST(VerifyNameMatchInvalidDataTest
, FailOnInvalidPrintableStringChars
) {
272 ASSERT_TRUE(LoadTestData("ascii", "PRINTABLESTRING", "unmangled", &der
));
273 // Find a known location inside a PrintableString in the DER-encoded data.
274 size_t replace_location
= der
.find("0123456789");
275 ASSERT_NE(std::string::npos
, replace_location
);
276 for (int c
= 0; c
< 256; ++c
) {
277 SCOPED_TRACE(base::IntToString(c
));
278 if (base::IsAsciiAlpha(c
) || base::IsAsciiDigit(c
))
296 der
.replace(replace_location
, 1, 1, c
);
297 // Verification should fail due to the invalid character.
298 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&der
),
299 SequenceValueFromString(&der
)));
303 // Matching should fail if an IA5String contains invalid characters.
304 TEST(VerifyNameMatchInvalidDataTest
, FailOnInvalidIA5StringChars
) {
306 ASSERT_TRUE(LoadTestData("ascii", "mixed", "rdn_dupetype_sorting_1", &der
));
307 // Find a known location inside an IA5String in the DER-encoded data.
308 size_t replace_location
= der
.find("eXaMple");
309 ASSERT_NE(std::string::npos
, replace_location
);
310 for (int c
= 0; c
< 256; ++c
) {
311 SCOPED_TRACE(base::IntToString(c
));
312 der
.replace(replace_location
, 1, 1, c
);
313 bool expected_result
= (c
<= 127);
314 EXPECT_EQ(expected_result
, VerifyNameMatch(SequenceValueFromString(&der
),
315 SequenceValueFromString(&der
)));
319 TEST(VerifyNameMatchInvalidDataTest
, FailOnAttributeTypeAndValueExtraData
) {
322 LoadTestData("invalid", "AttributeTypeAndValue", "extradata", &invalid
));
323 // Verification should fail due to extra element in AttributeTypeAndValue
325 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&invalid
),
326 SequenceValueFromString(&invalid
)));
329 TEST(VerifyNameMatchInvalidDataTest
, FailOnAttributeTypeAndValueShort
) {
331 ASSERT_TRUE(LoadTestData("invalid", "AttributeTypeAndValue", "onlyOneElement",
333 // Verification should fail due to AttributeTypeAndValue sequence having only
335 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&invalid
),
336 SequenceValueFromString(&invalid
)));
339 TEST(VerifyNameMatchInvalidDataTest
, FailOnAttributeTypeAndValueEmpty
) {
342 LoadTestData("invalid", "AttributeTypeAndValue", "empty", &invalid
));
343 // Verification should fail due to empty AttributeTypeAndValue sequence.
344 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&invalid
),
345 SequenceValueFromString(&invalid
)));
348 TEST(VerifyNameMatchInvalidDataTest
, FailOnBadAttributeType
) {
350 ASSERT_TRUE(LoadTestData("invalid", "AttributeTypeAndValue",
351 "badAttributeType", &invalid
));
352 // Verification should fail due to Attribute Type not being an OID.
353 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&invalid
),
354 SequenceValueFromString(&invalid
)));
357 TEST(VerifyNameMatchInvalidDataTest
, FailOnAttributeTypeAndValueNotSequence
) {
359 ASSERT_TRUE(LoadTestData("invalid", "AttributeTypeAndValue", "setNotSequence",
361 // Verification should fail due to AttributeTypeAndValue being a Set instead
363 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&invalid
),
364 SequenceValueFromString(&invalid
)));
367 TEST(VerifyNameMatchInvalidDataTest
, FailOnRdnNotSet
) {
369 ASSERT_TRUE(LoadTestData("invalid", "RDN", "sequenceInsteadOfSet", &invalid
));
370 // Verification should fail due to RDN being a Sequence instead of a Set.
371 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&invalid
),
372 SequenceValueFromString(&invalid
)));
375 TEST(VerifyNameMatchInvalidDataTest
, FailOnEmptyRdn
) {
377 ASSERT_TRUE(LoadTestData("invalid", "RDN", "empty", &invalid
));
378 // Verification should fail due to RDN having zero AttributeTypeAndValues.
379 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&invalid
),
380 SequenceValueFromString(&invalid
)));
383 // Matching should fail if a BMPString contains surrogates.
384 TEST(VerifyNameMatchInvalidDataTest
, FailOnBmpStringSurrogates
) {
386 ASSERT_TRUE(LoadTestData("unicode_bmp", "BMPSTRING", "unmangled", &normal
));
387 // Find a known location inside a BMPSTRING in the DER-encoded data.
388 size_t replace_location
= normal
.find("\x67\x71\x4e\xac");
389 ASSERT_NE(std::string::npos
, replace_location
);
390 // Replace with U+1D400 MATHEMATICAL BOLD CAPITAL A, which requires surrogates
392 std::string invalid
=
393 normal
.replace(replace_location
, 4, std::string("\xd8\x35\xdc\x00", 4));
394 // Verification should fail due to the invalid codepoints.
395 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&invalid
),
396 SequenceValueFromString(&invalid
)));
399 TEST(VerifyNameMatchTest
, EmptyNameMatching
) {
401 ASSERT_TRUE(LoadTestData("valid", "Name", "empty", &empty
));
402 // Empty names are equal.
403 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&empty
),
404 SequenceValueFromString(&empty
)));
406 // An empty name is not equal to non-empty name.
407 std::string non_empty
;
409 LoadTestData("ascii", "PRINTABLESTRING", "unmangled", &non_empty
));
410 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&empty
),
411 SequenceValueFromString(&non_empty
)));
412 EXPECT_FALSE(VerifyNameMatch(SequenceValueFromString(&non_empty
),
413 SequenceValueFromString(&empty
)));
416 // Matching should succeed when the RDNs are sorted differently but are still
417 // equal after normalizing.
418 TEST(VerifyNameMatchRDNSorting
, Simple
) {
420 ASSERT_TRUE(LoadTestData("ascii", "PRINTABLESTRING", "rdn_sorting_1", &a
));
422 ASSERT_TRUE(LoadTestData("ascii", "PRINTABLESTRING", "rdn_sorting_2", &b
));
423 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&a
),
424 SequenceValueFromString(&b
)));
425 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&b
),
426 SequenceValueFromString(&a
)));
429 // Matching should succeed when the RDNs are sorted differently but are still
430 // equal after normalizing, even in malformed RDNs that contain multiple
431 // elements with the same type.
432 TEST(VerifyNameMatchRDNSorting
, DuplicateTypes
) {
434 ASSERT_TRUE(LoadTestData("ascii", "mixed", "rdn_dupetype_sorting_1", &a
));
436 ASSERT_TRUE(LoadTestData("ascii", "mixed", "rdn_dupetype_sorting_2", &b
));
437 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&a
),
438 SequenceValueFromString(&b
)));
439 EXPECT_TRUE(VerifyNameMatch(SequenceValueFromString(&b
),
440 SequenceValueFromString(&a
)));