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" | |
7 #include "net/der/input.h" | 13 #include "net/der/input.h" |
8 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
9 | 15 |
10 namespace net { | 16 namespace net { |
17 namespace { | |
11 | 18 |
12 TEST(VerifyNameMatchTest, Simple) { | 19 std::string LoadTestData(const std::string& prefix, |
13 // TODO(mattm): Use valid Names. | 20 const std::string& value_type, |
14 EXPECT_TRUE(VerifyNameMatch(der::Input("hello"), der::Input("hello"))); | 21 const std::string& suffix) { |
15 EXPECT_FALSE(VerifyNameMatch(der::Input("aello"), der::Input("hello"))); | 22 base::FilePath src_root; |
16 EXPECT_FALSE(VerifyNameMatch(der::Input("hello"), der::Input("hello1"))); | 23 PathService::Get(base::DIR_SOURCE_ROOT, &src_root); |
17 EXPECT_FALSE(VerifyNameMatch(der::Input("hello1"), der::Input("hello"))); | 24 std::string filename = prefix + "-" + value_type + "-" + suffix + ".der"; |
25 base::FilePath filepath = | |
26 src_root.Append("net/data/verify_name_match_unittest/names") | |
27 .Append(filename); | |
28 std::string result; | |
29 bool success = base::ReadFileToString(filepath, &result); | |
30 EXPECT_TRUE(success); | |
31 return result; | |
32 } | |
33 | |
34 static const char* kValueTypes[] = {"PRINTABLESTRING", | |
35 "T61STRING", | |
36 "UTF8", | |
37 "BMPSTRING", | |
38 "UNIVERSALSTRING"}; | |
39 static const char* kMangleTypes[] = {"unmangled", | |
40 "case_swap", | |
41 "extra_whitespace"}; | |
42 | |
43 } // namespace | |
44 | |
45 class VerifyNameMatchSimpleTest | |
46 : public ::testing::TestWithParam< | |
47 ::testing::tuple<const char*, const char*>> { | |
48 public: | |
49 std::string value_type() const { return ::testing::get<0>(GetParam()); } | |
50 std::string suffix() const { return ::testing::get<1>(GetParam()); } | |
51 }; | |
52 | |
53 // Compare each input against itself, verifies that all input data is parsed | |
54 // successfully. | |
55 TEST_P(VerifyNameMatchSimpleTest, ExactEquality) { | |
56 std::string der = LoadTestData("ascii", value_type(), suffix()); | |
57 EXPECT_TRUE(VerifyNameMatch(der::Input(der), der::Input(der))); | |
58 | |
59 std::string der_extra_attr = | |
60 LoadTestData("ascii", value_type(), suffix() + "-extra_attr"); | |
61 EXPECT_TRUE( | |
62 VerifyNameMatch(der::Input(der_extra_attr), der::Input(der_extra_attr))); | |
63 | |
64 std::string der_extra_rdn = | |
65 LoadTestData("ascii", value_type(), suffix() + "-extra_rdn"); | |
66 EXPECT_TRUE( | |
67 VerifyNameMatch(der::Input(der_extra_rdn), der::Input(der_extra_rdn))); | |
68 } | |
69 | |
70 // Ensure that a Name does not match another Name which is exactly the same but | |
71 // with an extra attribute in one Relative Distinguished Name. | |
72 TEST_P(VerifyNameMatchSimpleTest, ExtraAttrDoesNotMatch) { | |
73 std::string der = LoadTestData("ascii", value_type(), suffix()); | |
74 std::string der_extra_attr = | |
75 LoadTestData("ascii", value_type(), suffix() + "-extra_attr"); | |
76 EXPECT_FALSE(VerifyNameMatch(der::Input(der), der::Input(der_extra_attr))); | |
77 EXPECT_FALSE(VerifyNameMatch(der::Input(der_extra_attr), der::Input(der))); | |
78 } | |
79 | |
80 // Ensure that a Name does not match another Name which is exactly the same but | |
81 // with an extra Relative Distinguished Name. | |
82 TEST_P(VerifyNameMatchSimpleTest, ExtraRdnDoesNotMatch) { | |
83 std::string der = LoadTestData("ascii", value_type(), suffix()); | |
84 std::string der_extra_rdn = | |
85 LoadTestData("ascii", value_type(), suffix() + "-extra_rdn"); | |
86 EXPECT_FALSE(VerifyNameMatch(der::Input(der), der::Input(der_extra_rdn))); | |
87 EXPECT_FALSE(VerifyNameMatch(der::Input(der_extra_rdn), der::Input(der))); | |
88 } | |
89 | |
90 INSTANTIATE_TEST_CASE_P(InstantiationName, | |
91 VerifyNameMatchSimpleTest, | |
92 ::testing::Combine(::testing::ValuesIn(kValueTypes), | |
93 ::testing::ValuesIn(kMangleTypes))); | |
94 | |
95 class VerifyNameMatchNormalizationTest | |
96 : public ::testing::TestWithParam<::testing::tuple<bool, const char*>> { | |
97 public: | |
98 bool expected_result() const { return ::testing::get<0>(GetParam()); } | |
99 std::string value_type() const { return ::testing::get<1>(GetParam()); } | |
100 }; | |
101 | |
102 // Verify matching is case insensitive (for the types which currently support | |
103 // normalization). | |
104 TEST_P(VerifyNameMatchNormalizationTest, CaseInsensitivity) { | |
105 std::string normal = LoadTestData("ascii", value_type(), "unmangled"); | |
106 std::string case_swap = LoadTestData("ascii", value_type(), "case_swap"); | |
107 EXPECT_EQ(expected_result(), | |
108 VerifyNameMatch(der::Input(normal), der::Input(case_swap))); | |
109 EXPECT_EQ(expected_result(), | |
110 VerifyNameMatch(der::Input(case_swap), der::Input(normal))); | |
111 } | |
112 | |
113 // Verify matching folds whitespace (for the types which currently support | |
114 // normalization). | |
115 TEST_P(VerifyNameMatchNormalizationTest, CollapseWhitespace) { | |
116 std::string normal = LoadTestData("ascii", value_type(), "unmangled"); | |
117 std::string whitespace = | |
118 LoadTestData("ascii", value_type(), "extra_whitespace"); | |
119 EXPECT_EQ(expected_result(), | |
120 VerifyNameMatch(der::Input(normal), der::Input(whitespace))); | |
121 EXPECT_EQ(expected_result(), | |
122 VerifyNameMatch(der::Input(whitespace), der::Input(normal))); | |
123 } | |
124 | |
125 // TODO(mattm): Current implementation uses RFC 2459 rules, where only | |
126 // PRINTABLESTRING is normalized. Change the false values below to true when | |
127 // updating to RFC 5280 (at least for UTF8, handling the others is optional). | |
128 INSTANTIATE_TEST_CASE_P( | |
129 InstantiationName, | |
130 VerifyNameMatchNormalizationTest, | |
131 ::testing::Values(std::tr1::make_tuple(true, "PRINTABLESTRING"), | |
132 std::tr1::make_tuple(false, "T61STRING"), | |
133 std::tr1::make_tuple(false, "UTF8"), | |
134 std::tr1::make_tuple(false, "BMPSTRING"), | |
135 std::tr1::make_tuple(false, "UNIVERSALSTRING"))); | |
nharper
2015/05/14 19:21:44
Should these be ::testing::make_tuple?
mattm
2015/05/14 21:38:57
oops, done.
| |
136 | |
137 class VerifyNameMatchDifferingTypesTest | |
138 : public ::testing::TestWithParam< | |
139 ::testing::tuple<const char*, const char*>> { | |
140 public: | |
141 std::string value_type_1() const { return ::testing::get<0>(GetParam()); } | |
142 std::string value_type_2() const { return ::testing::get<1>(GetParam()); } | |
143 }; | |
144 | |
145 // TODO(mattm): in RFC 2459, different value types are assumed unequal. In RFC | |
146 // 5280, different types are transcoded to Unicode, so this will need to be | |
147 // updated. | |
148 TEST_P(VerifyNameMatchDifferingTypesTest, DifferentTypesAreNonEqual) { | |
149 std::string der_1 = LoadTestData("ascii", value_type_1(), "unmangled"); | |
150 std::string der_2 = LoadTestData("ascii", value_type_2(), "unmangled"); | |
151 if (value_type_1() == value_type_2()) | |
152 EXPECT_TRUE(VerifyNameMatch(der::Input(der_1), der::Input(der_2))); | |
153 else | |
154 EXPECT_FALSE(VerifyNameMatch(der::Input(der_1), der::Input(der_2))); | |
155 } | |
156 | |
157 INSTANTIATE_TEST_CASE_P(InstantiationName, | |
158 VerifyNameMatchDifferingTypesTest, | |
159 ::testing::Combine(::testing::ValuesIn(kValueTypes), | |
160 ::testing::ValuesIn(kValueTypes))); | |
161 | |
162 // Matching should fail if a PrintableString contains invalid characters. | |
163 TEST(VerifyNameMatchPrintableStringValidity, FailOnInvalidChars) { | |
164 std::string normal = LoadTestData("ascii", "PRINTABLESTRING", "unmangled"); | |
165 // Find a known location inside a PrintableString in the DER-encoded data. | |
166 size_t replace_location = normal.find("0123456789"); | |
167 ASSERT_NE(std::string::npos, replace_location); | |
168 for (int c = 0; c < 256; ++c) { | |
169 SCOPED_TRACE(base::IntToString(c)); | |
170 if (IsAsciiAlpha(c) || IsAsciiDigit(c)) | |
171 continue; | |
172 switch (c) { | |
173 case ' ': | |
174 case '\'': | |
175 case '(': | |
176 case ')': | |
177 case '+': | |
178 case ',': | |
179 case '-': | |
180 case '.': | |
181 case '/': | |
182 case ':': | |
183 case '=': | |
184 case '?': | |
185 continue; | |
186 } | |
187 std::string invalid = normal.replace(replace_location, 1, 1, c); | |
188 // Verification should fail due to the invalid character. | |
189 EXPECT_FALSE(VerifyNameMatch(der::Input(invalid), der::Input(invalid))); | |
190 } | |
18 } | 191 } |
nharper
2015/05/14 19:21:44
All of these test cases assume a valid ASN.1 struc
mattm
2015/05/14 21:38:57
Good idea, done. (And fixed some cases allowing em
| |
19 | 192 |
20 } // namespace net | 193 } // namespace net |
OLD | NEW |