/src/mozilla-central/security/pkix/test/gtest/pkixnames_tests.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This code is made available to you under your choice of the following sets |
4 | | * of licensing terms: |
5 | | */ |
6 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
7 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
8 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
9 | | */ |
10 | | /* Copyright 2014 Mozilla Contributors |
11 | | * |
12 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
13 | | * you may not use this file except in compliance with the License. |
14 | | * You may obtain a copy of the License at |
15 | | * |
16 | | * http://www.apache.org/licenses/LICENSE-2.0 |
17 | | * |
18 | | * Unless required by applicable law or agreed to in writing, software |
19 | | * distributed under the License is distributed on an "AS IS" BASIS, |
20 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
21 | | * See the License for the specific language governing permissions and |
22 | | * limitations under the License. |
23 | | */ |
24 | | #include "pkixcheck.h" |
25 | | #include "pkixder.h" |
26 | | #include "pkixgtest.h" |
27 | | #include "pkixutil.h" |
28 | | |
29 | | namespace mozilla { namespace pkix { |
30 | | |
31 | | Result MatchPresentedDNSIDWithReferenceDNSID(Input presentedDNSID, |
32 | | Input referenceDNSID, |
33 | | /*out*/ bool& matches); |
34 | | |
35 | | bool IsValidReferenceDNSID(Input hostname); |
36 | | bool IsValidPresentedDNSID(Input hostname); |
37 | | bool ParseIPv4Address(Input hostname, /*out*/ uint8_t (&out)[4]); |
38 | | bool ParseIPv6Address(Input hostname, /*out*/ uint8_t (&out)[16]); |
39 | | |
40 | | } } // namespace mozilla::pkix |
41 | | |
42 | | using namespace mozilla::pkix; |
43 | | using namespace mozilla::pkix::test; |
44 | | |
45 | | struct PresentedMatchesReference |
46 | | { |
47 | | ByteString presentedDNSID; |
48 | | ByteString referenceDNSID; |
49 | | Result expectedResult; |
50 | | bool expectedMatches; // only valid when expectedResult == Success |
51 | | }; |
52 | | |
53 | | ::std::ostream& operator<<(::std::ostream& os, const PresentedMatchesReference&) |
54 | 0 | { |
55 | 0 | return os << "TODO (bug 1318770)"; |
56 | 0 | } |
57 | | |
58 | | #define DNS_ID_MATCH(a, b) \ |
59 | | { \ |
60 | | ByteString(reinterpret_cast<const uint8_t*>(a), sizeof(a) - 1), \ |
61 | | ByteString(reinterpret_cast<const uint8_t*>(b), sizeof(b) - 1), \ |
62 | | Success, \ |
63 | | true \ |
64 | | } |
65 | | |
66 | | #define DNS_ID_MISMATCH(a, b) \ |
67 | | { \ |
68 | | ByteString(reinterpret_cast<const uint8_t*>(a), sizeof(a) - 1), \ |
69 | | ByteString(reinterpret_cast<const uint8_t*>(b), sizeof(b) - 1), \ |
70 | | Success, \ |
71 | | false \ |
72 | | } |
73 | | |
74 | | #define DNS_ID_BAD_DER(a, b) \ |
75 | | { \ |
76 | | ByteString(reinterpret_cast<const uint8_t*>(a), sizeof(a) - 1), \ |
77 | | ByteString(reinterpret_cast<const uint8_t*>(b), sizeof(b) - 1), \ |
78 | | Result::ERROR_BAD_DER, \ |
79 | | false \ |
80 | | } |
81 | | |
82 | | static const PresentedMatchesReference DNSID_MATCH_PARAMS[] = |
83 | | { |
84 | | DNS_ID_BAD_DER("", "a"), |
85 | | |
86 | | DNS_ID_MATCH("a", "a"), |
87 | | DNS_ID_MISMATCH("b", "a"), |
88 | | |
89 | | DNS_ID_MATCH("*.b.a", "c.b.a"), |
90 | | DNS_ID_MISMATCH("*.b.a", "b.a"), |
91 | | DNS_ID_MISMATCH("*.b.a", "b.a."), |
92 | | |
93 | | // We allow underscores for compatibility with existing practices. |
94 | | DNS_ID_MATCH("a_b", "a_b"), |
95 | | DNS_ID_MATCH("*.example.com", "uses_underscore.example.com"), |
96 | | DNS_ID_MATCH("*.uses_underscore.example.com", "a.uses_underscore.example.com"), |
97 | | |
98 | | // See bug 1139039 |
99 | | DNS_ID_MATCH("_.example.com", "_.example.com"), |
100 | | DNS_ID_MATCH("*.example.com", "_.example.com"), |
101 | | DNS_ID_MATCH("_", "_"), |
102 | | DNS_ID_MATCH("___", "___"), |
103 | | DNS_ID_MATCH("example_", "example_"), |
104 | | DNS_ID_MATCH("_example", "_example"), |
105 | | DNS_ID_MATCH("*._._", "x._._"), |
106 | | |
107 | | // See bug 1139039 |
108 | | // A DNS-ID must not end in an all-numeric label. We don't consider |
109 | | // underscores to be numeric. |
110 | | DNS_ID_MATCH("_1", "_1"), |
111 | | DNS_ID_MATCH("example._1", "example._1"), |
112 | | DNS_ID_MATCH("example.1_", "example.1_"), |
113 | | |
114 | | // Wildcard not in leftmost label |
115 | | DNS_ID_MATCH("d.c.b.a", "d.c.b.a"), |
116 | | DNS_ID_BAD_DER("d.*.b.a", "d.c.b.a"), |
117 | | DNS_ID_BAD_DER("d.c*.b.a", "d.c.b.a"), |
118 | | DNS_ID_BAD_DER("d.c*.b.a", "d.cc.b.a"), |
119 | | |
120 | | // case sensitivity |
121 | | DNS_ID_MATCH("abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), |
122 | | DNS_ID_MATCH("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"), |
123 | | DNS_ID_MATCH("aBc", "Abc"), |
124 | | |
125 | | // digits |
126 | | DNS_ID_MATCH("a1", "a1"), |
127 | | |
128 | | // A trailing dot indicates an absolute name. Absolute presented names are |
129 | | // not allowed, but absolute reference names are allowed. |
130 | | DNS_ID_MATCH("example", "example"), |
131 | | DNS_ID_BAD_DER("example.", "example."), |
132 | | DNS_ID_MATCH("example", "example."), |
133 | | DNS_ID_BAD_DER("example.", "example"), |
134 | | DNS_ID_MATCH("example.com", "example.com"), |
135 | | DNS_ID_BAD_DER("example.com.", "example.com."), |
136 | | DNS_ID_MATCH("example.com", "example.com."), |
137 | | DNS_ID_BAD_DER("example.com.", "example.com"), |
138 | | DNS_ID_BAD_DER("example.com..", "example.com."), |
139 | | DNS_ID_BAD_DER("example.com..", "example.com"), |
140 | | DNS_ID_BAD_DER("example.com...", "example.com."), |
141 | | |
142 | | // xn-- IDN prefix |
143 | | DNS_ID_BAD_DER("x*.b.a", "xa.b.a"), |
144 | | DNS_ID_BAD_DER("x*.b.a", "xna.b.a"), |
145 | | DNS_ID_BAD_DER("x*.b.a", "xn-a.b.a"), |
146 | | DNS_ID_BAD_DER("x*.b.a", "xn--a.b.a"), |
147 | | DNS_ID_BAD_DER("xn*.b.a", "xn--a.b.a"), |
148 | | DNS_ID_BAD_DER("xn-*.b.a", "xn--a.b.a"), |
149 | | DNS_ID_BAD_DER("xn--*.b.a", "xn--a.b.a"), |
150 | | DNS_ID_BAD_DER("xn*.b.a", "xn--a.b.a"), |
151 | | DNS_ID_BAD_DER("xn-*.b.a", "xn--a.b.a"), |
152 | | DNS_ID_BAD_DER("xn--*.b.a", "xn--a.b.a"), |
153 | | DNS_ID_BAD_DER("xn---*.b.a", "xn--a.b.a"), |
154 | | |
155 | | // "*" cannot expand to nothing. |
156 | | DNS_ID_BAD_DER("c*.b.a", "c.b.a"), |
157 | | |
158 | | ///////////////////////////////////////////////////////////////////////////// |
159 | | // These are test cases adapted from Chromium's x509_certificate_unittest.cc. |
160 | | // The parameter order is the opposite in Chromium's tests. Also, some tests |
161 | | // were modified to fit into this framework or due to intentional differences |
162 | | // between mozilla::pkix and Chromium. |
163 | | |
164 | | DNS_ID_MATCH("foo.com", "foo.com"), |
165 | | DNS_ID_MATCH("f", "f"), |
166 | | DNS_ID_MISMATCH("i", "h"), |
167 | | DNS_ID_MATCH("*.foo.com", "bar.foo.com"), |
168 | | DNS_ID_MATCH("*.test.fr", "www.test.fr"), |
169 | | DNS_ID_MATCH("*.test.FR", "wwW.tESt.fr"), |
170 | | DNS_ID_BAD_DER(".uk", "f.uk"), |
171 | | DNS_ID_BAD_DER("?.bar.foo.com", "w.bar.foo.com"), |
172 | | DNS_ID_BAD_DER("(www|ftp).foo.com", "www.foo.com"), // regex! |
173 | | DNS_ID_BAD_DER("www.foo.com\0", "www.foo.com"), |
174 | | DNS_ID_BAD_DER("www.foo.com\0*.foo.com", "www.foo.com"), |
175 | | DNS_ID_MISMATCH("ww.house.example", "www.house.example"), |
176 | | DNS_ID_MISMATCH("www.test.org", "test.org"), |
177 | | DNS_ID_MISMATCH("*.test.org", "test.org"), |
178 | | DNS_ID_BAD_DER("*.org", "test.org"), |
179 | | DNS_ID_BAD_DER("w*.bar.foo.com", "w.bar.foo.com"), |
180 | | DNS_ID_BAD_DER("ww*ww.bar.foo.com", "www.bar.foo.com"), |
181 | | DNS_ID_BAD_DER("ww*ww.bar.foo.com", "wwww.bar.foo.com"), |
182 | | |
183 | | // Different than Chromium, matches NSS. |
184 | | DNS_ID_BAD_DER("w*w.bar.foo.com", "wwww.bar.foo.com"), |
185 | | |
186 | | DNS_ID_BAD_DER("w*w.bar.foo.c0m", "wwww.bar.foo.com"), |
187 | | |
188 | | // '*' must be the only character in the wildcard label |
189 | | DNS_ID_BAD_DER("wa*.bar.foo.com", "WALLY.bar.foo.com"), |
190 | | |
191 | | // We require "*" to be the last character in a wildcard label, but |
192 | | // Chromium does not. |
193 | | DNS_ID_BAD_DER("*Ly.bar.foo.com", "wally.bar.foo.com"), |
194 | | |
195 | | // Chromium does URL decoding of the reference ID, but we don't, and we also |
196 | | // require that the reference ID is valid, so we can't test these two. |
197 | | // DNS_ID_MATCH("www.foo.com", "ww%57.foo.com"), |
198 | | // DNS_ID_MATCH("www&.foo.com", "www%26.foo.com"), |
199 | | |
200 | | DNS_ID_MISMATCH("*.test.de", "www.test.co.jp"), |
201 | | DNS_ID_BAD_DER("*.jp", "www.test.co.jp"), |
202 | | DNS_ID_MISMATCH("www.test.co.uk", "www.test.co.jp"), |
203 | | DNS_ID_BAD_DER("www.*.co.jp", "www.test.co.jp"), |
204 | | DNS_ID_MATCH("www.bar.foo.com", "www.bar.foo.com"), |
205 | | DNS_ID_MISMATCH("*.foo.com", "www.bar.foo.com"), |
206 | | DNS_ID_BAD_DER("*.*.foo.com", "www.bar.foo.com"), |
207 | | DNS_ID_BAD_DER("*.*.foo.com", "www.bar.foo.com"), |
208 | | |
209 | | // Our matcher requires the reference ID to be a valid DNS name, so we cannot |
210 | | // test this case. |
211 | | //DNS_ID_BAD_DER("*.*.bar.foo.com", "*..bar.foo.com"), |
212 | | |
213 | | DNS_ID_MATCH("www.bath.org", "www.bath.org"), |
214 | | |
215 | | // Our matcher requires the reference ID to be a valid DNS name, so we cannot |
216 | | // test these cases. |
217 | | // DNS_ID_BAD_DER("www.bath.org", ""), |
218 | | // DNS_ID_BAD_DER("www.bath.org", "20.30.40.50"), |
219 | | // DNS_ID_BAD_DER("www.bath.org", "66.77.88.99"), |
220 | | |
221 | | // IDN tests |
222 | | DNS_ID_MATCH("xn--poema-9qae5a.com.br", "xn--poema-9qae5a.com.br"), |
223 | | DNS_ID_MATCH("*.xn--poema-9qae5a.com.br", "www.xn--poema-9qae5a.com.br"), |
224 | | DNS_ID_MISMATCH("*.xn--poema-9qae5a.com.br", "xn--poema-9qae5a.com.br"), |
225 | | DNS_ID_BAD_DER("xn--poema-*.com.br", "xn--poema-9qae5a.com.br"), |
226 | | DNS_ID_BAD_DER("xn--*-9qae5a.com.br", "xn--poema-9qae5a.com.br"), |
227 | | DNS_ID_BAD_DER("*--poema-9qae5a.com.br", "xn--poema-9qae5a.com.br"), |
228 | | |
229 | | // The following are adapted from the examples quoted from |
230 | | // http://tools.ietf.org/html/rfc6125#section-6.4.3 |
231 | | // (e.g., *.example.com would match foo.example.com but |
232 | | // not bar.foo.example.com or example.com). |
233 | | DNS_ID_MATCH("*.example.com", "foo.example.com"), |
234 | | DNS_ID_MISMATCH("*.example.com", "bar.foo.example.com"), |
235 | | DNS_ID_MISMATCH("*.example.com", "example.com"), |
236 | | // (e.g., baz*.example.net and *baz.example.net and b*z.example.net would |
237 | | // be taken to match baz1.example.net and foobaz.example.net and |
238 | | // buzz.example.net, respectively. However, we don't allow any characters |
239 | | // other than '*' in the wildcard label. |
240 | | DNS_ID_BAD_DER("baz*.example.net", "baz1.example.net"), |
241 | | |
242 | | // Both of these are different from Chromium, but match NSS, becaues the |
243 | | // wildcard character "*" is not the last character of the label. |
244 | | DNS_ID_BAD_DER("*baz.example.net", "foobaz.example.net"), |
245 | | DNS_ID_BAD_DER("b*z.example.net", "buzz.example.net"), |
246 | | |
247 | | // Wildcards should not be valid for public registry controlled domains, |
248 | | // and unknown/unrecognized domains, at least three domain components must |
249 | | // be present. For mozilla::pkix and NSS, there must always be at least two |
250 | | // labels after the wildcard label. |
251 | | DNS_ID_MATCH("*.test.example", "www.test.example"), |
252 | | DNS_ID_MATCH("*.example.co.uk", "test.example.co.uk"), |
253 | | DNS_ID_BAD_DER("*.exmaple", "test.example"), |
254 | | |
255 | | // The result is different than Chromium, because Chromium takes into account |
256 | | // the additional knowledge it has that "co.uk" is a TLD. mozilla::pkix does |
257 | | // not know that. |
258 | | DNS_ID_MATCH("*.co.uk", "example.co.uk"), |
259 | | |
260 | | DNS_ID_BAD_DER("*.com", "foo.com"), |
261 | | DNS_ID_BAD_DER("*.us", "foo.us"), |
262 | | DNS_ID_BAD_DER("*", "foo"), |
263 | | |
264 | | // IDN variants of wildcards and registry controlled domains. |
265 | | DNS_ID_MATCH("*.xn--poema-9qae5a.com.br", "www.xn--poema-9qae5a.com.br"), |
266 | | DNS_ID_MATCH("*.example.xn--mgbaam7a8h", "test.example.xn--mgbaam7a8h"), |
267 | | |
268 | | // RFC6126 allows this, and NSS accepts it, but Chromium disallows it. |
269 | | // TODO: File bug against Chromium. |
270 | | DNS_ID_MATCH("*.com.br", "xn--poema-9qae5a.com.br"), |
271 | | |
272 | | DNS_ID_BAD_DER("*.xn--mgbaam7a8h", "example.xn--mgbaam7a8h"), |
273 | | // Wildcards should be permissible for 'private' registry-controlled |
274 | | // domains. (In mozilla::pkix, we do not know if it is a private registry- |
275 | | // controlled domain or not.) |
276 | | DNS_ID_MATCH("*.appspot.com", "www.appspot.com"), |
277 | | DNS_ID_MATCH("*.s3.amazonaws.com", "foo.s3.amazonaws.com"), |
278 | | |
279 | | // Multiple wildcards are not valid. |
280 | | DNS_ID_BAD_DER("*.*.com", "foo.example.com"), |
281 | | DNS_ID_BAD_DER("*.bar.*.com", "foo.bar.example.com"), |
282 | | |
283 | | // Absolute vs relative DNS name tests. Although not explicitly specified |
284 | | // in RFC 6125, absolute reference names (those ending in a .) should |
285 | | // match either absolute or relative presented names. We don't allow |
286 | | // absolute presented names. |
287 | | // TODO: File errata against RFC 6125 about this. |
288 | | DNS_ID_BAD_DER("foo.com.", "foo.com"), |
289 | | DNS_ID_MATCH("foo.com", "foo.com."), |
290 | | DNS_ID_BAD_DER("foo.com.", "foo.com."), |
291 | | DNS_ID_BAD_DER("f.", "f"), |
292 | | DNS_ID_MATCH("f", "f."), |
293 | | DNS_ID_BAD_DER("f.", "f."), |
294 | | DNS_ID_BAD_DER("*.bar.foo.com.", "www-3.bar.foo.com"), |
295 | | DNS_ID_MATCH("*.bar.foo.com", "www-3.bar.foo.com."), |
296 | | DNS_ID_BAD_DER("*.bar.foo.com.", "www-3.bar.foo.com."), |
297 | | |
298 | | // We require the reference ID to be a valid DNS name, so we cannot test this |
299 | | // case. |
300 | | // DNS_ID_MISMATCH(".", "."), |
301 | | |
302 | | DNS_ID_BAD_DER("*.com.", "example.com"), |
303 | | DNS_ID_BAD_DER("*.com", "example.com."), |
304 | | DNS_ID_BAD_DER("*.com.", "example.com."), |
305 | | DNS_ID_BAD_DER("*.", "foo."), |
306 | | DNS_ID_BAD_DER("*.", "foo"), |
307 | | |
308 | | // The result is different than Chromium because we don't know that co.uk is |
309 | | // a TLD. |
310 | | DNS_ID_MATCH("*.co.uk", "foo.co.uk"), |
311 | | DNS_ID_MATCH("*.co.uk", "foo.co.uk."), |
312 | | DNS_ID_BAD_DER("*.co.uk.", "foo.co.uk"), |
313 | | DNS_ID_BAD_DER("*.co.uk.", "foo.co.uk."), |
314 | | |
315 | | DNS_ID_MISMATCH("*.example.com", "localhost"), |
316 | | DNS_ID_MISMATCH("*.example.com", "localhost."), |
317 | | // Note that we already have the testcase DNS_ID_BAD_DER("*", "foo") above |
318 | | }; |
319 | | |
320 | | struct InputValidity |
321 | | { |
322 | | ByteString input; |
323 | | bool isValidReferenceID; |
324 | | bool isValidPresentedID; |
325 | | }; |
326 | | |
327 | | ::std::ostream& operator<<(::std::ostream& os, const InputValidity&) |
328 | 0 | { |
329 | 0 | return os << "TODO (bug 1318770)"; |
330 | 0 | } |
331 | | |
332 | | // str is null-terminated, which is why we subtract 1. str may contain embedded |
333 | | // nulls (including at the end) preceding the null terminator though. |
334 | | #define I(str, validReferenceID, validPresentedID) \ |
335 | | { \ |
336 | | ByteString(reinterpret_cast<const uint8_t*>(str), sizeof(str) - 1), \ |
337 | | validReferenceID, \ |
338 | | validPresentedID, \ |
339 | | } |
340 | | |
341 | | static const InputValidity DNSNAMES_VALIDITY[] = |
342 | | { |
343 | | I("a", true, true), |
344 | | I("a.b", true, true), |
345 | | I("a.b.c", true, true), |
346 | | I("a.b.c.d", true, true), |
347 | | |
348 | | // empty labels |
349 | | I("", false, false), |
350 | | I(".", false, false), |
351 | | I("a", true, true), |
352 | | I(".a", false, false), |
353 | | I(".a.b", false, false), |
354 | | I("..a", false, false), |
355 | | I("a..b", false, false), |
356 | | I("a...b", false, false), |
357 | | I("a..b.c", false, false), |
358 | | I("a.b..c", false, false), |
359 | | I(".a.b.c.", false, false), |
360 | | |
361 | | // absolute names (only allowed for reference names) |
362 | | I("a.", true, false), |
363 | | I("a.b.", true, false), |
364 | | I("a.b.c.", true, false), |
365 | | |
366 | | // absolute names with empty label at end |
367 | | I("a..", false, false), |
368 | | I("a.b..", false, false), |
369 | | I("a.b.c..", false, false), |
370 | | I("a...", false, false), |
371 | | |
372 | | // Punycode |
373 | | I("xn--", false, false), |
374 | | I("xn--.", false, false), |
375 | | I("xn--.a", false, false), |
376 | | I("a.xn--", false, false), |
377 | | I("a.xn--.", false, false), |
378 | | I("a.xn--.b", false, false), |
379 | | I("a.xn--.b", false, false), |
380 | | I("a.xn--\0.b", false, false), |
381 | | I("a.xn--a.b", true, true), |
382 | | I("xn--a", true, true), |
383 | | I("a.xn--a", true, true), |
384 | | I("a.xn--a.a", true, true), |
385 | | I("\xc4\x95.com", false, false), // UTF-8 ĕ |
386 | | I("xn--jea.com", true, true), // punycode ĕ |
387 | | I("xn--\xc4\x95.com", false, false), // UTF-8 ĕ, malformed punycode + UTF-8 mashup |
388 | | |
389 | | // Surprising punycode |
390 | | I("xn--google.com", true, true), // 䕮䕵䕶䕱.com |
391 | | I("xn--citibank.com", true, true), // 岍岊岊岅岉岎.com |
392 | | I("xn--cnn.com", true, true), // 䁾.com |
393 | | I("a.xn--cnn", true, true), // a.䁾 |
394 | | I("a.xn--cnn.com", true, true), // a.䁾.com |
395 | | |
396 | | I("1.2.3.4", false, false), // IPv4 address |
397 | | I("1::2", false, false), // IPV6 address |
398 | | |
399 | | // whitespace not allowed anywhere. |
400 | | I(" ", false, false), |
401 | | I(" a", false, false), |
402 | | I("a ", false, false), |
403 | | I("a b", false, false), |
404 | | I("a.b 1", false, false), |
405 | | I("a\t", false, false), |
406 | | |
407 | | // Nulls not allowed |
408 | | I("\0", false, false), |
409 | | I("a\0", false, false), |
410 | | I("example.org\0.example.com", false, false), // Hi Moxie! |
411 | | I("\0a", false, false), |
412 | | I("xn--\0", false, false), |
413 | | |
414 | | // Allowed character set |
415 | | I("a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z", true, true), |
416 | | I("A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z", true, true), |
417 | | I("0.1.2.3.4.5.6.7.8.9.a", true, true), // "a" needed to avoid numeric last label |
418 | | I("a-b", true, true), // hyphen (a label cannot start or end with a hyphen) |
419 | | |
420 | | // Underscores |
421 | | I("a_b", true, true), |
422 | | // See bug 1139039 |
423 | | I("_", true, true), |
424 | | I("a_", true, true), |
425 | | I("_a", true, true), |
426 | | I("_1", true, true), |
427 | | I("1_", true, true), |
428 | | I("___", true, true), |
429 | | |
430 | | // An invalid character in various positions |
431 | | I("!", false, false), |
432 | | I("!a", false, false), |
433 | | I("a!", false, false), |
434 | | I("a!b", false, false), |
435 | | I("a.!", false, false), |
436 | | I("a.a!", false, false), |
437 | | I("a.!a", false, false), |
438 | | I("a.a!a", false, false), |
439 | | I("a.!a.a", false, false), |
440 | | I("a.a!.a", false, false), |
441 | | I("a.a!a.a", false, false), |
442 | | |
443 | | // Various other invalid characters |
444 | | I("a!", false, false), |
445 | | I("a@", false, false), |
446 | | I("a#", false, false), |
447 | | I("a$", false, false), |
448 | | I("a%", false, false), |
449 | | I("a^", false, false), |
450 | | I("a&", false, false), |
451 | | I("a*", false, false), |
452 | | I("a(", false, false), |
453 | | I("a)", false, false), |
454 | | |
455 | | // last label can't be fully numeric |
456 | | I("1", false, false), |
457 | | I("a.1", false, false), |
458 | | |
459 | | // other labels can be fully numeric |
460 | | I("1.a", true, true), |
461 | | I("1.2.a", true, true), |
462 | | I("1.2.3.a", true, true), |
463 | | |
464 | | // last label can be *partly* numeric |
465 | | I("1a", true, true), |
466 | | I("1.1a", true, true), |
467 | | I("1-1", true, true), |
468 | | I("a.1-1", true, true), |
469 | | I("a.1-a", true, true), |
470 | | |
471 | | // labels cannot start with a hyphen |
472 | | I("-", false, false), |
473 | | I("-1", false, false), |
474 | | |
475 | | // labels cannot end with a hyphen |
476 | | I("1-", false, false), |
477 | | I("1-.a", false, false), |
478 | | I("a-", false, false), |
479 | | I("a-.a", false, false), |
480 | | I("a.1-.a", false, false), |
481 | | I("a.a-.a", false, false), |
482 | | |
483 | | // labels can contain a hyphen in the middle |
484 | | I("a-b", true, true), |
485 | | I("1-2", true, true), |
486 | | I("a.a-1", true, true), |
487 | | |
488 | | // multiple consecutive hyphens allowed |
489 | | I("a--1", true, true), |
490 | | I("1---a", true, true), |
491 | | I("a-----------------b", true, true), |
492 | | |
493 | | // Wildcard specifications are not valid reference names, but are valid |
494 | | // presented names if there are enough labels and if '*' is the only |
495 | | // character in the wildcard label. |
496 | | I("*.a", false, false), |
497 | | I("a*", false, false), |
498 | | I("a*.", false, false), |
499 | | I("a*.a", false, false), |
500 | | I("a*.a.", false, false), |
501 | | I("*.a.b", false, true), |
502 | | I("*.a.b.", false, false), |
503 | | I("a*.b.c", false, false), |
504 | | I("*.a.b.c", false, true), |
505 | | I("a*.b.c.d", false, false), |
506 | | |
507 | | // Multiple wildcards are not allowed. |
508 | | I("a**.b.c", false, false), |
509 | | I("a*b*.c.d", false, false), |
510 | | I("a*.b*.c", false, false), |
511 | | |
512 | | // Wildcards are only allowed in the first label. |
513 | | I("a.*", false, false), |
514 | | I("a.*.b", false, false), |
515 | | I("a.b.*", false, false), |
516 | | I("a.b*.c", false, false), |
517 | | I("*.b*.c", false, false), |
518 | | I(".*.a.b", false, false), |
519 | | I(".a*.b.c", false, false), |
520 | | |
521 | | // Wildcards must be at the *end* of the first label. |
522 | | I("*a.b.c", false, false), |
523 | | I("a*b.c.d", false, false), |
524 | | |
525 | | // Wildcards not allowed with IDNA prefix |
526 | | I("x*.a.b", false, false), |
527 | | I("xn*.a.b", false, false), |
528 | | I("xn-*.a.b", false, false), |
529 | | I("xn--*.a.b", false, false), |
530 | | I("xn--w*.a.b", false, false), |
531 | | |
532 | | // Redacted labels from RFC6962bis draft 4 |
533 | | // https://tools.ietf.org/html/draft-ietf-trans-rfc6962-bis-04#section-3.2.2 |
534 | | I("(PRIVATE).foo", false, false), |
535 | | |
536 | | // maximum label length is 63 characters |
537 | | I("1234567890" "1234567890" "1234567890" |
538 | | "1234567890" "1234567890" "1234567890" "abc", true, true), |
539 | | I("1234567890" "1234567890" "1234567890" |
540 | | "1234567890" "1234567890" "1234567890" "abcd", false, false), |
541 | | |
542 | | // maximum total length is 253 characters |
543 | | I("1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "." |
544 | | "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "." |
545 | | "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "." |
546 | | "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "." |
547 | | "1234567890" "1234567890" "1234567890" "1234567890" "12345678" "a", |
548 | | true, true), |
549 | | I("1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "." |
550 | | "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "." |
551 | | "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "." |
552 | | "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "." |
553 | | "1234567890" "1234567890" "1234567890" "1234567890" "123456789" "a", |
554 | | false, false), |
555 | | }; |
556 | | |
557 | | static const InputValidity DNSNAMES_VALIDITY_TURKISH_I[] = |
558 | | { |
559 | | // http://en.wikipedia.org/wiki/Dotted_and_dotless_I#In_computing |
560 | | // IDN registration rules disallow "latin capital letter i with dot above," |
561 | | // but our checks aren't intended to enforce those rules. |
562 | | I("I", true, true), // ASCII capital I |
563 | | I("i", true, true), // ASCII lowercase i |
564 | | I("\xC4\xB0", false, false), // latin capital letter i with dot above |
565 | | I("\xC4\xB1", false, false), // latin small letter dotless i |
566 | | I("xn--i-9bb", true, true), // latin capital letter i with dot above, in punycode |
567 | | I("xn--cfa", true, true), // latin small letter dotless i, in punycode |
568 | | I("xn--\xC4\xB0", false, false), // latin capital letter i with dot above, mashup |
569 | | I("xn--\xC4\xB1", false, false), // latin small letter dotless i, mashup |
570 | | }; |
571 | | |
572 | | static const uint8_t LOWERCASE_I_VALUE[1] = { 'i' }; |
573 | | static const uint8_t UPPERCASE_I_VALUE[1] = { 'I' }; |
574 | | static const Input LOWERCASE_I(LOWERCASE_I_VALUE); |
575 | | static const Input UPPERCASE_I(UPPERCASE_I_VALUE); |
576 | | |
577 | | template <unsigned int L> |
578 | | struct IPAddressParams |
579 | | { |
580 | | ByteString input; |
581 | | bool isValid; |
582 | | uint8_t expectedValueIfValid[L]; |
583 | | }; |
584 | | |
585 | | template <unsigned int L> |
586 | | ::std::ostream& operator<<(::std::ostream& os, const IPAddressParams<L>&) |
587 | 0 | { |
588 | 0 | return os << "TODO (bug 1318770)"; |
589 | 0 | } Unexecuted instantiation: std::__1::basic_ostream<char, std::__1::char_traits<char> >& operator<< <4u>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, IPAddressParams<4u> const&) Unexecuted instantiation: std::__1::basic_ostream<char, std::__1::char_traits<char> >& operator<< <16u>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, IPAddressParams<16u> const&) |
590 | | |
591 | | #define IPV4_VALID(str, a, b, c, d) \ |
592 | | { \ |
593 | | ByteString(reinterpret_cast<const uint8_t*>(str), sizeof(str) - 1), \ |
594 | | true, \ |
595 | | { a, b, c, d } \ |
596 | | } |
597 | | |
598 | | // The value of expectedValueIfValid must be ignored for invalid IP addresses. |
599 | | // The value { 73, 73, 73, 73 } is used because it is unlikely to result in an |
600 | | // accidental match, unlike { 0, 0, 0, 0 }, which is a value we actually test. |
601 | | #define IPV4_INVALID(str) \ |
602 | | { \ |
603 | | ByteString(reinterpret_cast<const uint8_t*>(str), sizeof(str) - 1), \ |
604 | | false, \ |
605 | | { 73, 73, 73, 73 } \ |
606 | | } |
607 | | |
608 | | static const IPAddressParams<4> IPV4_ADDRESSES[] = |
609 | | { |
610 | | IPV4_INVALID(""), |
611 | | IPV4_INVALID("1"), |
612 | | IPV4_INVALID("1.2"), |
613 | | IPV4_INVALID("1.2.3"), |
614 | | IPV4_VALID("1.2.3.4", 1, 2, 3, 4), |
615 | | IPV4_INVALID("1.2.3.4.5"), |
616 | | |
617 | | IPV4_INVALID("1.2.3.4a"), // a DNSName! |
618 | | IPV4_INVALID("a.2.3.4"), // not even a DNSName! |
619 | | IPV4_INVALID("1::2"), // IPv6 address |
620 | | |
621 | | // Whitespace not allowed |
622 | | IPV4_INVALID(" 1.2.3.4"), |
623 | | IPV4_INVALID("1.2.3.4 "), |
624 | | IPV4_INVALID("1 .2.3.4"), |
625 | | IPV4_INVALID("\n1.2.3.4"), |
626 | | IPV4_INVALID("1.2.3.4\n"), |
627 | | |
628 | | // Nulls not allowed |
629 | | IPV4_INVALID("\0"), |
630 | | IPV4_INVALID("\0" "1.2.3.4"), |
631 | | IPV4_INVALID("1.2.3.4\0"), |
632 | | IPV4_INVALID("1.2.3.4\0.5"), |
633 | | |
634 | | // Range |
635 | | IPV4_VALID("0.0.0.0", 0, 0, 0, 0), |
636 | | IPV4_VALID("255.255.255.255", 255, 255, 255, 255), |
637 | | IPV4_INVALID("256.0.0.0"), |
638 | | IPV4_INVALID("0.256.0.0"), |
639 | | IPV4_INVALID("0.0.256.0"), |
640 | | IPV4_INVALID("0.0.0.256"), |
641 | | IPV4_INVALID("999.0.0.0"), |
642 | | IPV4_INVALID("9999999999999999999.0.0.0"), |
643 | | |
644 | | // All digits allowed |
645 | | IPV4_VALID("0.1.2.3", 0, 1, 2, 3), |
646 | | IPV4_VALID("4.5.6.7", 4, 5, 6, 7), |
647 | | IPV4_VALID("8.9.0.1", 8, 9, 0, 1), |
648 | | |
649 | | // Leading zeros not allowed |
650 | | IPV4_INVALID("01.2.3.4"), |
651 | | IPV4_INVALID("001.2.3.4"), |
652 | | IPV4_INVALID("00000000001.2.3.4"), |
653 | | IPV4_INVALID("010.2.3.4"), |
654 | | IPV4_INVALID("1.02.3.4"), |
655 | | IPV4_INVALID("1.2.03.4"), |
656 | | IPV4_INVALID("1.2.3.04"), |
657 | | |
658 | | // Empty components |
659 | | IPV4_INVALID(".2.3.4"), |
660 | | IPV4_INVALID("1..3.4"), |
661 | | IPV4_INVALID("1.2..4"), |
662 | | IPV4_INVALID("1.2.3."), |
663 | | |
664 | | // Too many components |
665 | | IPV4_INVALID("1.2.3.4.5"), |
666 | | IPV4_INVALID("1.2.3.4.5.6"), |
667 | | IPV4_INVALID("0.1.2.3.4"), |
668 | | IPV4_INVALID("1.2.3.4.0"), |
669 | | |
670 | | // Leading/trailing dot |
671 | | IPV4_INVALID(".1.2.3.4"), |
672 | | IPV4_INVALID("1.2.3.4."), |
673 | | |
674 | | // Other common forms of IPv4 address |
675 | | // http://en.wikipedia.org/wiki/IPv4#Address_representations |
676 | | IPV4_VALID("192.0.2.235", 192, 0, 2, 235), // dotted decimal (control value) |
677 | | IPV4_INVALID("0xC0.0x00.0x02.0xEB"), // dotted hex |
678 | | IPV4_INVALID("0301.0000.0002.0353"), // dotted octal |
679 | | IPV4_INVALID("0xC00002EB"), // non-dotted hex |
680 | | IPV4_INVALID("3221226219"), // non-dotted decimal |
681 | | IPV4_INVALID("030000001353"), // non-dotted octal |
682 | | IPV4_INVALID("192.0.0002.0xEB"), // mixed |
683 | | }; |
684 | | |
685 | | #define IPV6_VALID(str, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ |
686 | | { \ |
687 | | ByteString(reinterpret_cast<const uint8_t*>(str), sizeof(str) - 1), \ |
688 | | true, \ |
689 | | { a, b, c, d, \ |
690 | | e, f, g, h, \ |
691 | | i, j, k, l, \ |
692 | | m, n, o, p } \ |
693 | | } |
694 | | |
695 | | #define IPV6_INVALID(str) \ |
696 | | { \ |
697 | | ByteString(reinterpret_cast<const uint8_t*>(str), sizeof(str) - 1), \ |
698 | | false, \ |
699 | | { 73, 73, 73, 73, \ |
700 | | 73, 73, 73, 73, \ |
701 | | 73, 73, 73, 73, \ |
702 | | 73, 73, 73, 73 } \ |
703 | | } |
704 | | |
705 | | static const IPAddressParams<16> IPV6_ADDRESSES[] = |
706 | | { |
707 | | IPV6_INVALID(""), |
708 | | IPV6_INVALID("1234"), |
709 | | IPV6_INVALID("1234:5678"), |
710 | | IPV6_INVALID("1234:5678:9abc"), |
711 | | IPV6_INVALID("1234:5678:9abc:def0"), |
712 | | IPV6_INVALID("1234:5678:9abc:def0:1234:"), |
713 | | IPV6_INVALID("1234:5678:9abc:def0:1234:5678:"), |
714 | | IPV6_INVALID("1234:5678:9abc:def0:1234:5678:9abc:"), |
715 | | IPV6_VALID("1234:5678:9abc:def0:1234:5678:9abc:def0", |
716 | | 0x12, 0x34, 0x56, 0x78, |
717 | | 0x9a, 0xbc, 0xde, 0xf0, |
718 | | 0x12, 0x34, 0x56, 0x78, |
719 | | 0x9a, 0xbc, 0xde, 0xf0), |
720 | | IPV6_INVALID("1234:5678:9abc:def0:1234:5678:9abc:def0:"), |
721 | | IPV6_INVALID(":1234:5678:9abc:def0:1234:5678:9abc:def0"), |
722 | | IPV6_INVALID("1234:5678:9abc:def0:1234:5678:9abc:def0:0000"), |
723 | | |
724 | | // Valid contractions |
725 | | IPV6_VALID("::1", |
726 | | 0x00, 0x00, 0x00, 0x00, |
727 | | 0x00, 0x00, 0x00, 0x00, |
728 | | 0x00, 0x00, 0x00, 0x00, |
729 | | 0x00, 0x00, 0x00, 0x01), |
730 | | IPV6_VALID("::1234", |
731 | | 0x00, 0x00, 0x00, 0x00, |
732 | | 0x00, 0x00, 0x00, 0x00, |
733 | | 0x00, 0x00, 0x00, 0x00, |
734 | | 0x00, 0x00, 0x12, 0x34), |
735 | | IPV6_VALID("1234::", |
736 | | 0x12, 0x34, 0x00, 0x00, |
737 | | 0x00, 0x00, 0x00, 0x00, |
738 | | 0x00, 0x00, 0x00, 0x00, |
739 | | 0x00, 0x00, 0x00, 0x00), |
740 | | IPV6_VALID("1234::5678", |
741 | | 0x12, 0x34, 0x00, 0x00, |
742 | | 0x00, 0x00, 0x00, 0x00, |
743 | | 0x00, 0x00, 0x00, 0x00, |
744 | | 0x00, 0x00, 0x56, 0x78), |
745 | | IPV6_VALID("1234:5678::abcd", |
746 | | 0x12, 0x34, 0x56, 0x78, |
747 | | 0x00, 0x00, 0x00, 0x00, |
748 | | 0x00, 0x00, 0x00, 0x00, |
749 | | 0x00, 0x00, 0xab, 0xcd), |
750 | | IPV6_VALID("1234:5678:9abc:def0:1234:5678:9abc::", |
751 | | 0x12, 0x34, 0x56, 0x78, |
752 | | 0x9a, 0xbc, 0xde, 0xf0, |
753 | | 0x12, 0x34, 0x56, 0x78, |
754 | | 0x9a, 0xbc, 0x00, 0x00), |
755 | | |
756 | | // Contraction in full IPv6 addresses not allowed |
757 | | IPV6_INVALID("::1234:5678:9abc:def0:1234:5678:9abc:def0"), // start |
758 | | IPV6_INVALID("1234:5678:9abc:def0:1234:5678:9abc:def0::"), // end |
759 | | IPV6_INVALID("1234:5678::9abc:def0:1234:5678:9abc:def0"), // interior |
760 | | |
761 | | // Multiple contractions not allowed |
762 | | IPV6_INVALID("::1::"), |
763 | | IPV6_INVALID("::1::2"), |
764 | | IPV6_INVALID("1::2::"), |
765 | | |
766 | | // Colon madness! |
767 | | IPV6_INVALID(":"), |
768 | | IPV6_INVALID("::"), |
769 | | IPV6_INVALID(":::"), |
770 | | IPV6_INVALID("::::"), |
771 | | IPV6_INVALID(":::1"), |
772 | | IPV6_INVALID("::::1"), |
773 | | IPV6_INVALID("1:::2"), |
774 | | IPV6_INVALID("1::::2"), |
775 | | IPV6_INVALID("1:2:::"), |
776 | | IPV6_INVALID("1:2::::"), |
777 | | IPV6_INVALID("::1234:"), |
778 | | IPV6_INVALID(":1234::"), |
779 | | |
780 | | IPV6_INVALID("01234::"), // too many digits, even if zero |
781 | | IPV6_INVALID("12345678::"), // too many digits or missing colon |
782 | | |
783 | | // uppercase |
784 | | IPV6_VALID("ABCD:EFAB::", |
785 | | 0xab, 0xcd, 0xef, 0xab, |
786 | | 0x00, 0x00, 0x00, 0x00, |
787 | | 0x00, 0x00, 0x00, 0x00, |
788 | | 0x00, 0x00, 0x00, 0x00), |
789 | | |
790 | | // miXeD CAse |
791 | | IPV6_VALID("aBcd:eFAb::", |
792 | | 0xab, 0xcd, 0xef, 0xab, |
793 | | 0x00, 0x00, 0x00, 0x00, |
794 | | 0x00, 0x00, 0x00, 0x00, |
795 | | 0x00, 0x00, 0x00, 0x00), |
796 | | |
797 | | // IPv4-style |
798 | | IPV6_VALID("::2.3.4.5", |
799 | | 0x00, 0x00, 0x00, 0x00, |
800 | | 0x00, 0x00, 0x00, 0x00, |
801 | | 0x00, 0x00, 0x00, 0x00, |
802 | | 0x02, 0x03, 0x04, 0x05), |
803 | | IPV6_VALID("1234::2.3.4.5", |
804 | | 0x12, 0x34, 0x00, 0x00, |
805 | | 0x00, 0x00, 0x00, 0x00, |
806 | | 0x00, 0x00, 0x00, 0x00, |
807 | | 0x02, 0x03, 0x04, 0x05), |
808 | | IPV6_VALID("::abcd:2.3.4.5", |
809 | | 0x00, 0x00, 0x00, 0x00, |
810 | | 0x00, 0x00, 0x00, 0x00, |
811 | | 0x00, 0x00, 0xab, 0xcd, |
812 | | 0x02, 0x03, 0x04, 0x05), |
813 | | IPV6_VALID("1234:5678:9abc:def0:1234:5678:252.253.254.255", |
814 | | 0x12, 0x34, 0x56, 0x78, |
815 | | 0x9a, 0xbc, 0xde, 0xf0, |
816 | | 0x12, 0x34, 0x56, 0x78, |
817 | | 252, 253, 254, 255), |
818 | | IPV6_VALID("1234:5678:9abc:def0:1234::252.253.254.255", |
819 | | 0x12, 0x34, 0x56, 0x78, |
820 | | 0x9a, 0xbc, 0xde, 0xf0, |
821 | | 0x12, 0x34, 0x00, 0x00, |
822 | | 252, 253, 254, 255), |
823 | | IPV6_INVALID("1234::252.253.254"), |
824 | | IPV6_INVALID("::252.253.254"), |
825 | | IPV6_INVALID("::252.253.254.300"), |
826 | | IPV6_INVALID("1234::252.253.254.255:"), |
827 | | IPV6_INVALID("1234::252.253.254.255:5678"), |
828 | | |
829 | | // Contractions that don't contract |
830 | | IPV6_INVALID("::1234:5678:9abc:def0:1234:5678:9abc:def0"), |
831 | | IPV6_INVALID("1234:5678:9abc:def0:1234:5678:9abc:def0::"), |
832 | | IPV6_INVALID("1234:5678:9abc:def0::1234:5678:9abc:def0"), |
833 | | IPV6_INVALID("1234:5678:9abc:def0:1234:5678::252.253.254.255"), |
834 | | |
835 | | // With and without leading zeros |
836 | | IPV6_VALID("::123", |
837 | | 0x00, 0x00, 0x00, 0x00, |
838 | | 0x00, 0x00, 0x00, 0x00, |
839 | | 0x00, 0x00, 0x00, 0x00, |
840 | | 0x00, 0x00, 0x01, 0x23), |
841 | | IPV6_VALID("::0123", |
842 | | 0x00, 0x00, 0x00, 0x00, |
843 | | 0x00, 0x00, 0x00, 0x00, |
844 | | 0x00, 0x00, 0x00, 0x00, |
845 | | 0x00, 0x00, 0x01, 0x23), |
846 | | IPV6_VALID("::012", |
847 | | 0x00, 0x00, 0x00, 0x00, |
848 | | 0x00, 0x00, 0x00, 0x00, |
849 | | 0x00, 0x00, 0x00, 0x00, |
850 | | 0x00, 0x00, 0x00, 0x12), |
851 | | IPV6_VALID("::0012", |
852 | | 0x00, 0x00, 0x00, 0x00, |
853 | | 0x00, 0x00, 0x00, 0x00, |
854 | | 0x00, 0x00, 0x00, 0x00, |
855 | | 0x00, 0x00, 0x00, 0x12), |
856 | | IPV6_VALID("::01", |
857 | | 0x00, 0x00, 0x00, 0x00, |
858 | | 0x00, 0x00, 0x00, 0x00, |
859 | | 0x00, 0x00, 0x00, 0x00, |
860 | | 0x00, 0x00, 0x00, 0x01), |
861 | | IPV6_VALID("::001", |
862 | | 0x00, 0x00, 0x00, 0x00, |
863 | | 0x00, 0x00, 0x00, 0x00, |
864 | | 0x00, 0x00, 0x00, 0x00, |
865 | | 0x00, 0x00, 0x00, 0x01), |
866 | | IPV6_VALID("::0001", |
867 | | 0x00, 0x00, 0x00, 0x00, |
868 | | 0x00, 0x00, 0x00, 0x00, |
869 | | 0x00, 0x00, 0x00, 0x00, |
870 | | 0x00, 0x00, 0x00, 0x01), |
871 | | IPV6_VALID("::0", |
872 | | 0x00, 0x00, 0x00, 0x00, |
873 | | 0x00, 0x00, 0x00, 0x00, |
874 | | 0x00, 0x00, 0x00, 0x00, |
875 | | 0x00, 0x00, 0x00, 0x00), |
876 | | IPV6_VALID("::00", |
877 | | 0x00, 0x00, 0x00, 0x00, |
878 | | 0x00, 0x00, 0x00, 0x00, |
879 | | 0x00, 0x00, 0x00, 0x00, |
880 | | 0x00, 0x00, 0x00, 0x00), |
881 | | IPV6_VALID("::000", |
882 | | 0x00, 0x00, 0x00, 0x00, |
883 | | 0x00, 0x00, 0x00, 0x00, |
884 | | 0x00, 0x00, 0x00, 0x00, |
885 | | 0x00, 0x00, 0x00, 0x00), |
886 | | IPV6_VALID("::0000", |
887 | | 0x00, 0x00, 0x00, 0x00, |
888 | | 0x00, 0x00, 0x00, 0x00, |
889 | | 0x00, 0x00, 0x00, 0x00, |
890 | | 0x00, 0x00, 0x00, 0x00), |
891 | | IPV6_INVALID("::01234"), |
892 | | IPV6_INVALID("::00123"), |
893 | | IPV6_INVALID("::000123"), |
894 | | |
895 | | // Trailing zero |
896 | | IPV6_INVALID("::12340"), |
897 | | |
898 | | // Whitespace |
899 | | IPV6_INVALID(" 1234:5678:9abc:def0:1234:5678:9abc:def0"), |
900 | | IPV6_INVALID("\t1234:5678:9abc:def0:1234:5678:9abc:def0"), |
901 | | IPV6_INVALID("\t1234:5678:9abc:def0:1234:5678:9abc:def0\n"), |
902 | | IPV6_INVALID("1234 :5678:9abc:def0:1234:5678:9abc:def0"), |
903 | | IPV6_INVALID("1234: 5678:9abc:def0:1234:5678:9abc:def0"), |
904 | | IPV6_INVALID(":: 2.3.4.5"), |
905 | | IPV6_INVALID("1234::252.253.254.255 "), |
906 | | IPV6_INVALID("1234::252.253.254.255\n"), |
907 | | IPV6_INVALID("1234::252.253. 254.255"), |
908 | | |
909 | | // Nulls |
910 | | IPV6_INVALID("\0"), |
911 | | IPV6_INVALID("::1\0:2"), |
912 | | IPV6_INVALID("::1\0"), |
913 | | IPV6_INVALID("::1.2.3.4\0"), |
914 | | IPV6_INVALID("::1.2\02.3.4"), |
915 | | }; |
916 | | |
917 | | class pkixnames_MatchPresentedDNSIDWithReferenceDNSID |
918 | | : public ::testing::Test |
919 | | , public ::testing::WithParamInterface<PresentedMatchesReference> |
920 | | { |
921 | | public: |
922 | | DefaultNameMatchingPolicy mNameMatchingPolicy; |
923 | | }; |
924 | | |
925 | | TEST_P(pkixnames_MatchPresentedDNSIDWithReferenceDNSID, |
926 | | MatchPresentedDNSIDWithReferenceDNSID) |
927 | 0 | { |
928 | 0 | const PresentedMatchesReference& param(GetParam()); |
929 | 0 | SCOPED_TRACE(param.presentedDNSID.c_str()); |
930 | 0 | SCOPED_TRACE(param.referenceDNSID.c_str()); |
931 | 0 | Input presented; |
932 | 0 | ASSERT_EQ(Success, presented.Init(param.presentedDNSID.data(), |
933 | 0 | param.presentedDNSID.length())); |
934 | 0 | Input reference; |
935 | 0 | ASSERT_EQ(Success, reference.Init(param.referenceDNSID.data(), |
936 | 0 | param.referenceDNSID.length())); |
937 | 0 |
|
938 | 0 | // sanity check that test makes sense |
939 | 0 | ASSERT_TRUE(IsValidReferenceDNSID(reference)); |
940 | 0 |
|
941 | 0 | bool matches; |
942 | 0 | ASSERT_EQ(param.expectedResult, |
943 | 0 | MatchPresentedDNSIDWithReferenceDNSID(presented, reference, |
944 | 0 | matches)); |
945 | 0 | if (param.expectedResult == Success) { |
946 | 0 | ASSERT_EQ(param.expectedMatches, matches); |
947 | 0 | } |
948 | 0 | } |
949 | | |
950 | | INSTANTIATE_TEST_CASE_P(pkixnames_MatchPresentedDNSIDWithReferenceDNSID, |
951 | | pkixnames_MatchPresentedDNSIDWithReferenceDNSID, |
952 | | testing::ValuesIn(DNSID_MATCH_PARAMS)); |
953 | | |
954 | | class pkixnames_Turkish_I_Comparison |
955 | | : public ::testing::Test |
956 | | , public ::testing::WithParamInterface<InputValidity> |
957 | | { |
958 | | public: |
959 | | DefaultNameMatchingPolicy mNameMatchingPolicy; |
960 | | }; |
961 | | |
962 | | TEST_P(pkixnames_Turkish_I_Comparison, MatchPresentedDNSIDWithReferenceDNSID) |
963 | 0 | { |
964 | 0 | // Make sure we don't have the similar problems that strcasecmp and others |
965 | 0 | // have with the other kinds of "i" and "I" commonly used in Turkish locales. |
966 | 0 |
|
967 | 0 | const InputValidity& inputValidity(GetParam()); |
968 | 0 | SCOPED_TRACE(inputValidity.input.c_str()); |
969 | 0 | Input input; |
970 | 0 | ASSERT_EQ(Success, input.Init(inputValidity.input.data(), |
971 | 0 | inputValidity.input.length())); |
972 | 0 |
|
973 | 0 | bool isASCII = InputsAreEqual(LOWERCASE_I, input) || |
974 | 0 | InputsAreEqual(UPPERCASE_I, input); |
975 | 0 | { |
976 | 0 | bool matches; |
977 | 0 | ASSERT_EQ(inputValidity.isValidPresentedID ? Success |
978 | 0 | : Result::ERROR_BAD_DER, |
979 | 0 | MatchPresentedDNSIDWithReferenceDNSID(input, LOWERCASE_I, |
980 | 0 | matches)); |
981 | 0 | if (inputValidity.isValidPresentedID) { |
982 | 0 | ASSERT_EQ(isASCII, matches); |
983 | 0 | } |
984 | 0 | } |
985 | 0 | { |
986 | 0 | bool matches; |
987 | 0 | ASSERT_EQ(inputValidity.isValidPresentedID ? Success |
988 | 0 | : Result::ERROR_BAD_DER, |
989 | 0 | MatchPresentedDNSIDWithReferenceDNSID(input, UPPERCASE_I, |
990 | 0 | matches)); |
991 | 0 | if (inputValidity.isValidPresentedID) { |
992 | 0 | ASSERT_EQ(isASCII, matches); |
993 | 0 | } |
994 | 0 | } |
995 | 0 | } |
996 | | |
997 | | INSTANTIATE_TEST_CASE_P(pkixnames_Turkish_I_Comparison, |
998 | | pkixnames_Turkish_I_Comparison, |
999 | | testing::ValuesIn(DNSNAMES_VALIDITY_TURKISH_I)); |
1000 | | |
1001 | | class pkixnames_IsValidReferenceDNSID |
1002 | | : public ::testing::Test |
1003 | | , public ::testing::WithParamInterface<InputValidity> |
1004 | | { |
1005 | | public: |
1006 | | DefaultNameMatchingPolicy mNameMatchingPolicy; |
1007 | | }; |
1008 | | |
1009 | | TEST_P(pkixnames_IsValidReferenceDNSID, IsValidReferenceDNSID) |
1010 | 0 | { |
1011 | 0 | const InputValidity& inputValidity(GetParam()); |
1012 | 0 | SCOPED_TRACE(inputValidity.input.c_str()); |
1013 | 0 | Input input; |
1014 | 0 | ASSERT_EQ(Success, input.Init(inputValidity.input.data(), |
1015 | 0 | inputValidity.input.length())); |
1016 | 0 | ASSERT_EQ(inputValidity.isValidReferenceID, IsValidReferenceDNSID(input)); |
1017 | 0 | ASSERT_EQ(inputValidity.isValidPresentedID, IsValidPresentedDNSID(input)); |
1018 | 0 | } |
1019 | | |
1020 | | INSTANTIATE_TEST_CASE_P(pkixnames_IsValidReferenceDNSID, |
1021 | | pkixnames_IsValidReferenceDNSID, |
1022 | | testing::ValuesIn(DNSNAMES_VALIDITY)); |
1023 | | INSTANTIATE_TEST_CASE_P(pkixnames_IsValidReferenceDNSID_Turkish_I, |
1024 | | pkixnames_IsValidReferenceDNSID, |
1025 | | testing::ValuesIn(DNSNAMES_VALIDITY_TURKISH_I)); |
1026 | | |
1027 | | class pkixnames_ParseIPv4Address |
1028 | | : public ::testing::Test |
1029 | | , public ::testing::WithParamInterface<IPAddressParams<4>> |
1030 | | { |
1031 | | public: |
1032 | | DefaultNameMatchingPolicy mNameMatchingPolicy; |
1033 | | }; |
1034 | | |
1035 | | TEST_P(pkixnames_ParseIPv4Address, ParseIPv4Address) |
1036 | 0 | { |
1037 | 0 | const IPAddressParams<4>& param(GetParam()); |
1038 | 0 | SCOPED_TRACE(param.input.c_str()); |
1039 | 0 | Input input; |
1040 | 0 | ASSERT_EQ(Success, input.Init(param.input.data(), |
1041 | 0 | param.input.length())); |
1042 | 0 | uint8_t ipAddress[4]; |
1043 | 0 | ASSERT_EQ(param.isValid, ParseIPv4Address(input, ipAddress)); |
1044 | 0 | if (param.isValid) { |
1045 | 0 | for (size_t i = 0; i < sizeof(ipAddress); ++i) { |
1046 | 0 | ASSERT_EQ(param.expectedValueIfValid[i], ipAddress[i]); |
1047 | 0 | } |
1048 | 0 | } |
1049 | 0 | } |
1050 | | |
1051 | | INSTANTIATE_TEST_CASE_P(pkixnames_ParseIPv4Address, |
1052 | | pkixnames_ParseIPv4Address, |
1053 | | testing::ValuesIn(IPV4_ADDRESSES)); |
1054 | | |
1055 | | class pkixnames_ParseIPv6Address |
1056 | | : public ::testing::Test |
1057 | | , public ::testing::WithParamInterface<IPAddressParams<16>> |
1058 | | { |
1059 | | public: |
1060 | | DefaultNameMatchingPolicy mNameMatchingPolicy; |
1061 | | }; |
1062 | | |
1063 | | TEST_P(pkixnames_ParseIPv6Address, ParseIPv6Address) |
1064 | 0 | { |
1065 | 0 | const IPAddressParams<16>& param(GetParam()); |
1066 | 0 | SCOPED_TRACE(param.input.c_str()); |
1067 | 0 | Input input; |
1068 | 0 | ASSERT_EQ(Success, input.Init(param.input.data(), |
1069 | 0 | param.input.length())); |
1070 | 0 | uint8_t ipAddress[16]; |
1071 | 0 | ASSERT_EQ(param.isValid, ParseIPv6Address(input, ipAddress)); |
1072 | 0 | if (param.isValid) { |
1073 | 0 | for (size_t i = 0; i < sizeof(ipAddress); ++i) { |
1074 | 0 | ASSERT_EQ(param.expectedValueIfValid[i], ipAddress[i]); |
1075 | 0 | } |
1076 | 0 | } |
1077 | 0 | } |
1078 | | |
1079 | | INSTANTIATE_TEST_CASE_P(pkixnames_ParseIPv6Address, |
1080 | | pkixnames_ParseIPv6Address, |
1081 | | testing::ValuesIn(IPV6_ADDRESSES)); |
1082 | | |
1083 | | // This is an arbitrary string that is used to indicate that no SAN extension |
1084 | | // should be put into the generated certificate. It needs to be different from |
1085 | | // "" or any other subjectAltName value that we actually want to test, but its |
1086 | | // actual value does not matter. Note that this isn't a correctly-encoded SAN |
1087 | | // extension value! |
1088 | | static const ByteString |
1089 | | NO_SAN(reinterpret_cast<const uint8_t*>("I'm a bad, bad, certificate")); |
1090 | | |
1091 | | struct CheckCertHostnameParams |
1092 | | { |
1093 | | ByteString hostname; |
1094 | | ByteString subject; |
1095 | | ByteString subjectAltName; |
1096 | | Result result; |
1097 | | }; |
1098 | | |
1099 | | ::std::ostream& operator<<(::std::ostream& os, const CheckCertHostnameParams&) |
1100 | 0 | { |
1101 | 0 | return os << "TODO (bug 1318770)"; |
1102 | 0 | } |
1103 | | |
1104 | | class pkixnames_CheckCertHostname |
1105 | | : public ::testing::Test |
1106 | | , public ::testing::WithParamInterface<CheckCertHostnameParams> |
1107 | | { |
1108 | | public: |
1109 | | DefaultNameMatchingPolicy mNameMatchingPolicy; |
1110 | | }; |
1111 | | |
1112 | | #define WITH_SAN(r, ps, psan, result) \ |
1113 | | { \ |
1114 | | ByteString(reinterpret_cast<const uint8_t*>(r), sizeof(r) - 1), \ |
1115 | | ps, \ |
1116 | | psan, \ |
1117 | | result \ |
1118 | | } |
1119 | | |
1120 | | #define WITHOUT_SAN(r, ps, result) \ |
1121 | | { \ |
1122 | | ByteString(reinterpret_cast<const uint8_t*>(r), sizeof(r) - 1), \ |
1123 | | ps, \ |
1124 | | NO_SAN, \ |
1125 | | result \ |
1126 | | } |
1127 | | |
1128 | | static const uint8_t example_com[] = { |
1129 | | 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm' |
1130 | | }; |
1131 | | |
1132 | | // Note that We avoid zero-valued bytes in these IP addresses so that we don't |
1133 | | // get false negatives from anti-NULL-byte defenses in dNSName decoding. |
1134 | | static const uint8_t ipv4_addr_bytes[] = { |
1135 | | 1, 2, 3, 4 |
1136 | | }; |
1137 | | static const uint8_t ipv4_addr_bytes_as_str[] = "\x01\x02\x03\x04"; |
1138 | | static const uint8_t ipv4_addr_str[] = "1.2.3.4"; |
1139 | | static const uint8_t ipv4_addr_bytes_FFFFFFFF[8] = { |
1140 | | 1, 2, 3, 4, 0xff, 0xff, 0xff, 0xff |
1141 | | }; |
1142 | | |
1143 | | static const uint8_t ipv4_compatible_ipv6_addr_bytes[] = { |
1144 | | 0, 0, 0, 0, |
1145 | | 0, 0, 0, 0, |
1146 | | 0, 0, 0, 0, |
1147 | | 1, 2, 3, 4 |
1148 | | }; |
1149 | | static const uint8_t ipv4_compatible_ipv6_addr_str[] = "::1.2.3.4"; |
1150 | | |
1151 | | static const uint8_t ipv4_mapped_ipv6_addr_bytes[] = { |
1152 | | 0, 0, 0, 0, |
1153 | | 0, 0, 0, 0, |
1154 | | 0, 0, 0xFF, 0xFF, |
1155 | | 1, 2, 3, 4 |
1156 | | }; |
1157 | | static const uint8_t ipv4_mapped_ipv6_addr_str[] = "::FFFF:1.2.3.4"; |
1158 | | |
1159 | | static const uint8_t ipv6_addr_bytes[] = { |
1160 | | 0x11, 0x22, 0x33, 0x44, |
1161 | | 0x55, 0x66, 0x77, 0x88, |
1162 | | 0x99, 0xaa, 0xbb, 0xcc, |
1163 | | 0xdd, 0xee, 0xff, 0x11 |
1164 | | }; |
1165 | | static const uint8_t ipv6_addr_bytes_as_str[] = |
1166 | | "\x11\x22\x33\x44" |
1167 | | "\x55\x66\x77\x88" |
1168 | | "\x99\xaa\xbb\xcc" |
1169 | | "\xdd\xee\xff\x11"; |
1170 | | |
1171 | | static const uint8_t ipv6_addr_str[] = |
1172 | | "1122:3344:5566:7788:99aa:bbcc:ddee:ff11"; |
1173 | | |
1174 | | static const uint8_t ipv6_other_addr_bytes[] = { |
1175 | | 0xff, 0xee, 0xdd, 0xcc, |
1176 | | 0xbb, 0xaa, 0x99, 0x88, |
1177 | | 0x77, 0x66, 0x55, 0x44, |
1178 | | 0x33, 0x22, 0x11, 0x00, |
1179 | | }; |
1180 | | |
1181 | | static const uint8_t ipv4_other_addr_bytes[] = { |
1182 | | 5, 6, 7, 8 |
1183 | | }; |
1184 | | static const uint8_t ipv4_other_addr_bytes_FFFFFFFF[] = { |
1185 | | 5, 6, 7, 8, 0xff, 0xff, 0xff, 0xff |
1186 | | }; |
1187 | | |
1188 | | static const uint8_t ipv4_addr_00000000_bytes[] = { |
1189 | | 0, 0, 0, 0 |
1190 | | }; |
1191 | | static const uint8_t ipv4_addr_FFFFFFFF_bytes[] = { |
1192 | | 0, 0, 0, 0 |
1193 | | }; |
1194 | | |
1195 | | static const uint8_t ipv4_constraint_all_zeros_bytes[] = { |
1196 | | 0, 0, 0, 0, 0, 0, 0, 0 |
1197 | | }; |
1198 | | |
1199 | | static const uint8_t ipv6_addr_all_zeros_bytes[] = { |
1200 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1201 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1202 | | }; |
1203 | | |
1204 | | static const uint8_t ipv6_constraint_all_zeros_bytes[] = { |
1205 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1206 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1207 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1208 | | 0, 0, 0, 0, 0, 0, 0, 0 |
1209 | | }; |
1210 | | |
1211 | | static const uint8_t ipv4_constraint_CIDR_16_bytes[] = { |
1212 | | 1, 2, 0, 0, 0xff, 0xff, 0, 0 |
1213 | | }; |
1214 | | static const uint8_t ipv4_constraint_CIDR_17_bytes[] = { |
1215 | | 1, 2, 0, 0, 0xff, 0xff, 0x80, 0 |
1216 | | }; |
1217 | | |
1218 | | // The subnet is 1.2.0.0/16 but it is specified as 1.2.3.0/16 |
1219 | | static const uint8_t ipv4_constraint_CIDR_16_bad_addr_bytes[] = { |
1220 | | 1, 2, 3, 0, 0xff, 0xff, 0, 0 |
1221 | | }; |
1222 | | |
1223 | | // Masks are supposed to be of the form <ones><zeros>, but this one is of the |
1224 | | // form <ones><zeros><ones><zeros>. |
1225 | | static const uint8_t ipv4_constraint_bad_mask_bytes[] = { |
1226 | | 1, 2, 3, 0, 0xff, 0, 0xff, 0 |
1227 | | }; |
1228 | | |
1229 | | static const uint8_t ipv6_constraint_CIDR_16_bytes[] = { |
1230 | | 0x11, 0x22, 0, 0, 0, 0, 0, 0, |
1231 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1232 | | 0xff, 0xff, 0, 0, 0, 0, 0, 0, |
1233 | | 0, 0, 0, 0, 0, 0, 0, 0 |
1234 | | }; |
1235 | | |
1236 | | // The subnet is 1122::/16 but it is specified as 1122:3344::/16 |
1237 | | static const uint8_t ipv6_constraint_CIDR_16_bad_addr_bytes[] = { |
1238 | | 0x11, 0x22, 0x33, 0x44, 0, 0, 0, 0, |
1239 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1240 | | 0xff, 0xff, 0, 0, 0, 0, 0, 0, |
1241 | | 0, 0, 0, 0, 0, 0, 0, 0 |
1242 | | }; |
1243 | | |
1244 | | // Masks are supposed to be of the form <ones><zeros>, but this one is of the |
1245 | | // form <ones><zeros><ones><zeros>. |
1246 | | static const uint8_t ipv6_constraint_bad_mask_bytes[] = { |
1247 | | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0, 0, |
1248 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1249 | | 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, |
1250 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1251 | | }; |
1252 | | |
1253 | | static const uint8_t ipv4_addr_truncated_bytes[] = { |
1254 | | 1, 2, 3 |
1255 | | }; |
1256 | | static const uint8_t ipv4_addr_overlong_bytes[] = { |
1257 | | 1, 2, 3, 4, 5 |
1258 | | }; |
1259 | | static const uint8_t ipv4_constraint_truncated_bytes[] = { |
1260 | | 0, 0, 0, 0, |
1261 | | 0, 0, 0, |
1262 | | }; |
1263 | | static const uint8_t ipv4_constraint_overlong_bytes[] = { |
1264 | | 0, 0, 0, 0, |
1265 | | 0, 0, 0, 0, 0 |
1266 | | }; |
1267 | | |
1268 | | static const uint8_t ipv6_addr_truncated_bytes[] = { |
1269 | | 0x11, 0x22, 0x33, 0x44, |
1270 | | 0x55, 0x66, 0x77, 0x88, |
1271 | | 0x99, 0xaa, 0xbb, 0xcc, |
1272 | | 0xdd, 0xee, 0xff |
1273 | | }; |
1274 | | static const uint8_t ipv6_addr_overlong_bytes[] = { |
1275 | | 0x11, 0x22, 0x33, 0x44, |
1276 | | 0x55, 0x66, 0x77, 0x88, |
1277 | | 0x99, 0xaa, 0xbb, 0xcc, |
1278 | | 0xdd, 0xee, 0xff, 0x11, 0x00 |
1279 | | }; |
1280 | | static const uint8_t ipv6_constraint_truncated_bytes[] = { |
1281 | | 0x11, 0x22, 0, 0, 0, 0, 0, 0, |
1282 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1283 | | 0xff, 0xff, 0, 0, 0, 0, 0, 0, |
1284 | | 0, 0, 0, 0, 0, 0, 0 |
1285 | | }; |
1286 | | static const uint8_t ipv6_constraint_overlong_bytes[] = { |
1287 | | 0x11, 0x22, 0, 0, 0, 0, 0, 0, |
1288 | | 0, 0, 0, 0, 0, 0, 0, 0, |
1289 | | 0xff, 0xff, 0, 0, 0, 0, 0, 0, |
1290 | | 0, 0, 0, 0, 0, 0, 0, 0, 0 |
1291 | | }; |
1292 | | |
1293 | | // Note that, for DNSNames, these test cases in CHECK_CERT_HOSTNAME_PARAMS are |
1294 | | // mostly about testing different scenerios regarding the structure of entries |
1295 | | // in the subjectAltName and subject of the certificate, than about the how |
1296 | | // specific presented identifier values are matched against the reference |
1297 | | // identifier values. This is because we also use the test cases in |
1298 | | // DNSNAMES_VALIDITY to test CheckCertHostname. Consequently, tests about |
1299 | | // whether specific presented DNSNames (including wildcards, in particular) are |
1300 | | // matched against a reference DNSName only need to be added to |
1301 | | // DNSNAMES_VALIDITY, and not here. |
1302 | | static const CheckCertHostnameParams CHECK_CERT_HOSTNAME_PARAMS[] = |
1303 | | { |
1304 | | // This is technically illegal. PrintableString is defined in such a way that |
1305 | | // '*' is not an allowed character, but there are many real-world certificates |
1306 | | // that are encoded this way. |
1307 | | WITHOUT_SAN("foo.example.com", RDN(CN("*.example.com", der::PrintableString)), |
1308 | | Success), |
1309 | | WITHOUT_SAN("foo.example.com", RDN(CN("*.example.com", der::UTF8String)), |
1310 | | Success), |
1311 | | |
1312 | | // Many certificates use TeletexString when encoding wildcards in CN-IDs |
1313 | | // because PrintableString is defined as not allowing '*' and UTF8String was, |
1314 | | // at one point in history, considered too new to depend on for compatibility. |
1315 | | // We accept TeletexString-encoded CN-IDs when they don't contain any escape |
1316 | | // sequences. The reference I used for the escape codes was |
1317 | | // https://tools.ietf.org/html/rfc1468. The escaping mechanism is actually |
1318 | | // pretty complex and these tests don't even come close to testing all the |
1319 | | // possibilities. |
1320 | | WITHOUT_SAN("foo.example.com", RDN(CN("*.example.com", der::TeletexString)), |
1321 | | Success), |
1322 | | // "ESC ( B" ({0x1B,0x50,0x42}) is the escape code to switch to ASCII, which |
1323 | | // is redundant because it already the default. |
1324 | | WITHOUT_SAN("foo.example.com", |
1325 | | RDN(CN("\x1B(B*.example.com", der::TeletexString)), |
1326 | | Result::ERROR_BAD_CERT_DOMAIN), |
1327 | | WITHOUT_SAN("foo.example.com", |
1328 | | RDN(CN("*.example\x1B(B.com", der::TeletexString)), |
1329 | | Result::ERROR_BAD_CERT_DOMAIN), |
1330 | | WITHOUT_SAN("foo.example.com", |
1331 | | RDN(CN("*.example.com\x1B(B", der::TeletexString)), |
1332 | | Result::ERROR_BAD_CERT_DOMAIN), |
1333 | | // "ESC $ B" ({0x1B,0x24,0x42}) is the escape code to switch to |
1334 | | // JIS X 0208-1983 (a Japanese character set). |
1335 | | WITHOUT_SAN("foo.example.com", |
1336 | | RDN(CN("\x1B$B*.example.com", der::TeletexString)), |
1337 | | Result::ERROR_BAD_CERT_DOMAIN), |
1338 | | WITHOUT_SAN("foo.example.com", |
1339 | | RDN(CN("*.example.com\x1B$B", der::TeletexString)), |
1340 | | Result::ERROR_BAD_CERT_DOMAIN), |
1341 | | |
1342 | | // Match a DNSName SAN entry with a redundant (ignored) matching CN-ID. |
1343 | | WITH_SAN("a", RDN(CN("a")), DNSName("a"), Success), |
1344 | | // Match a DNSName SAN entry when there is an CN-ID that doesn't match. |
1345 | | WITH_SAN("b", RDN(CN("a")), DNSName("b"), Success), |
1346 | | // Do not match a CN-ID when there is a valid DNSName SAN Entry. |
1347 | | WITH_SAN("a", RDN(CN("a")), DNSName("b"), Result::ERROR_BAD_CERT_DOMAIN), |
1348 | | // Do not match a CN-ID when there is a malformed DNSName SAN Entry. |
1349 | | WITH_SAN("a", RDN(CN("a")), DNSName("!"), Result::ERROR_BAD_DER), |
1350 | | // Do not match a matching CN-ID when there is a valid IPAddress SAN entry. |
1351 | | WITH_SAN("a", RDN(CN("a")), IPAddress(ipv4_addr_bytes), |
1352 | | Result::ERROR_BAD_CERT_DOMAIN), |
1353 | | // Do not match a matching CN-ID when there is a malformed IPAddress SAN entry. |
1354 | | WITH_SAN("a", RDN(CN("a")), IPAddress(example_com), |
1355 | | Result::ERROR_BAD_CERT_DOMAIN), |
1356 | | // Match a DNSName against a matching CN-ID when there is a SAN, but the SAN |
1357 | | // does not contain an DNSName or IPAddress entry. |
1358 | | WITH_SAN("a", RDN(CN("a")), RFC822Name("foo@example.com"), Success), |
1359 | | // Match a matching CN-ID when there is no SAN. |
1360 | | WITHOUT_SAN("a", RDN(CN("a")), Success), |
1361 | | // Do not match a mismatching CN-ID when there is no SAN. |
1362 | | WITHOUT_SAN("a", RDN(CN("b")), Result::ERROR_BAD_CERT_DOMAIN), |
1363 | | |
1364 | | // The first DNSName matches. |
1365 | | WITH_SAN("a", RDN(CN("foo")), DNSName("a") + DNSName("b"), Success), |
1366 | | // The last DNSName matches. |
1367 | | WITH_SAN("b", RDN(CN("foo")), DNSName("a") + DNSName("b"), Success), |
1368 | | // The middle DNSName matches. |
1369 | | WITH_SAN("b", RDN(CN("foo")), |
1370 | | DNSName("a") + DNSName("b") + DNSName("c"), Success), |
1371 | | // After an IP address. |
1372 | | WITH_SAN("b", RDN(CN("foo")), |
1373 | | IPAddress(ipv4_addr_bytes) + DNSName("b"), Success), |
1374 | | // Before an IP address. |
1375 | | WITH_SAN("a", RDN(CN("foo")), |
1376 | | DNSName("a") + IPAddress(ipv4_addr_bytes), Success), |
1377 | | // Between an RFC822Name and an IP address. |
1378 | | WITH_SAN("b", RDN(CN("foo")), |
1379 | | RFC822Name("foo@example.com") + DNSName("b") + |
1380 | | IPAddress(ipv4_addr_bytes), |
1381 | | Success), |
1382 | | // Duplicate DNSName. |
1383 | | WITH_SAN("a", RDN(CN("foo")), DNSName("a") + DNSName("a"), Success), |
1384 | | // After an invalid DNSName. |
1385 | | WITH_SAN("b", RDN(CN("foo")), DNSName("!") + DNSName("b"), |
1386 | | Result::ERROR_BAD_DER), |
1387 | | |
1388 | | // http://tools.ietf.org/html/rfc5280#section-4.2.1.6: "If the subjectAltName |
1389 | | // extension is present, the sequence MUST contain at least one entry." |
1390 | | // However, for compatibility reasons, this is not enforced. See bug 1143085. |
1391 | | // This case is treated as if the extension is not present (i.e. name |
1392 | | // matching falls back to the subject CN). |
1393 | | WITH_SAN("a", RDN(CN("a")), ByteString(), Success), |
1394 | | WITH_SAN("a", RDN(CN("b")), ByteString(), Result::ERROR_BAD_CERT_DOMAIN), |
1395 | | |
1396 | | // http://tools.ietf.org/html/rfc5280#section-4.1.2.6 says "If subject naming |
1397 | | // information is present only in the subjectAltName extension (e.g., a key |
1398 | | // bound only to an email address or URI), then the subject name MUST be an |
1399 | | // empty sequence and the subjectAltName extension MUST be critical." So, we |
1400 | | // have to support an empty subject. We don't enforce that the SAN must be |
1401 | | // critical or even that there is a SAN when the subject is empty, though. |
1402 | | WITH_SAN("a", ByteString(), DNSName("a"), Success), |
1403 | | // Make sure we return ERROR_BAD_CERT_DOMAIN and not ERROR_BAD_DER. |
1404 | | WITHOUT_SAN("a", ByteString(), Result::ERROR_BAD_CERT_DOMAIN), |
1405 | | |
1406 | | // Two CNs in the same RDN, both match. |
1407 | | WITHOUT_SAN("a", RDN(CN("a") + CN("a")), Success), |
1408 | | // Two CNs in the same RDN, both DNSNames, first one matches. |
1409 | | WITHOUT_SAN("a", RDN(CN("a") + CN("b")), |
1410 | | Result::ERROR_BAD_CERT_DOMAIN), |
1411 | | // Two CNs in the same RDN, both DNSNames, last one matches. |
1412 | | WITHOUT_SAN("b", RDN(CN("a") + CN("b")), Success), |
1413 | | // Two CNs in the same RDN, first one matches, second isn't a DNSName. |
1414 | | WITHOUT_SAN("a", RDN(CN("a") + CN("Not a DNSName")), |
1415 | | Result::ERROR_BAD_CERT_DOMAIN), |
1416 | | // Two CNs in the same RDN, first one not a DNSName, second matches. |
1417 | | WITHOUT_SAN("b", RDN(CN("Not a DNSName") + CN("b")), Success), |
1418 | | |
1419 | | // Two CNs in separate RDNs, both match. |
1420 | | WITHOUT_SAN("a", RDN(CN("a")) + RDN(CN("a")), Success), |
1421 | | // Two CNs in separate RDNs, both DNSNames, first one matches. |
1422 | | WITHOUT_SAN("a", RDN(CN("a")) + RDN(CN("b")), |
1423 | | Result::ERROR_BAD_CERT_DOMAIN), |
1424 | | // Two CNs in separate RDNs, both DNSNames, last one matches. |
1425 | | WITHOUT_SAN("b", RDN(CN("a")) + RDN(CN("b")), Success), |
1426 | | // Two CNs in separate RDNs, first one matches, second isn't a DNSName. |
1427 | | WITHOUT_SAN("a", RDN(CN("a")) + RDN(CN("Not a DNSName")), |
1428 | | Result::ERROR_BAD_CERT_DOMAIN), |
1429 | | // Two CNs in separate RDNs, first one not a DNSName, second matches. |
1430 | | WITHOUT_SAN("b", RDN(CN("Not a DNSName")) + RDN(CN("b")), Success), |
1431 | | |
1432 | | // One CN, one RDN, CN is the first AVA in the RDN, CN matches. |
1433 | | WITHOUT_SAN("a", RDN(CN("a") + OU("b")), Success), |
1434 | | // One CN, one RDN, CN is the first AVA in the RDN, CN does not match. |
1435 | | WITHOUT_SAN("b", RDN(CN("a") + OU("b")), |
1436 | | Result::ERROR_BAD_CERT_DOMAIN), |
1437 | | // One CN, one RDN, CN is not the first AVA in the RDN, CN matches. |
1438 | | WITHOUT_SAN("b", RDN(OU("a") + CN("b")), Success), |
1439 | | // One CN, one RDN, CN is not the first AVA in the RDN, CN does not match. |
1440 | | WITHOUT_SAN("a", RDN(OU("a") + CN("b")), |
1441 | | Result::ERROR_BAD_CERT_DOMAIN), |
1442 | | |
1443 | | // One CN, multiple RDNs, CN is in the first RDN, CN matches. |
1444 | | WITHOUT_SAN("a", RDN(CN("a")) + RDN(OU("b")), Success), |
1445 | | // One CN, multiple RDNs, CN is in the first RDN, CN does not match. |
1446 | | WITHOUT_SAN("b", RDN(CN("a")) + RDN(OU("b")), Result::ERROR_BAD_CERT_DOMAIN), |
1447 | | // One CN, multiple RDNs, CN is not in the first RDN, CN matches. |
1448 | | WITHOUT_SAN("b", RDN(OU("a")) + RDN(CN("b")), Success), |
1449 | | // One CN, multiple RDNs, CN is not in the first RDN, CN does not match. |
1450 | | WITHOUT_SAN("a", RDN(OU("a")) + RDN(CN("b")), Result::ERROR_BAD_CERT_DOMAIN), |
1451 | | |
1452 | | // One CN, one RDN, CN is not in the first or last AVA, CN matches. |
1453 | | WITHOUT_SAN("b", RDN(OU("a") + CN("b") + OU("c")), Success), |
1454 | | // One CN, multiple RDNs, CN is not in the first or last RDN, CN matches. |
1455 | | WITHOUT_SAN("b", RDN(OU("a")) + RDN(CN("b")) + RDN(OU("c")), Success), |
1456 | | |
1457 | | // Empty CN does not match. |
1458 | | WITHOUT_SAN("example.com", RDN(CN("")), Result::ERROR_BAD_CERT_DOMAIN), |
1459 | | |
1460 | | WITHOUT_SAN("uses_underscore.example.com", RDN(CN("*.example.com")), Success), |
1461 | | WITHOUT_SAN("a.uses_underscore.example.com", |
1462 | | RDN(CN("*.uses_underscore.example.com")), Success), |
1463 | | WITH_SAN("uses_underscore.example.com", RDN(CN("foo")), |
1464 | | DNSName("*.example.com"), Success), |
1465 | | WITH_SAN("a.uses_underscore.example.com", RDN(CN("foo")), |
1466 | | DNSName("*.uses_underscore.example.com"), Success), |
1467 | | |
1468 | | // Do not match a DNSName that is encoded in a malformed IPAddress. |
1469 | | WITH_SAN("example.com", RDN(CN("foo")), IPAddress(example_com), |
1470 | | Result::ERROR_BAD_CERT_DOMAIN), |
1471 | | |
1472 | | // We skip over the malformed IPAddress and match the DNSName entry because |
1473 | | // we've heard reports of real-world certificates that have malformed |
1474 | | // IPAddress SANs. |
1475 | | WITH_SAN("example.org", RDN(CN("foo")), |
1476 | | IPAddress(example_com) + DNSName("example.org"), Success), |
1477 | | |
1478 | | WITH_SAN("example.com", RDN(CN("foo")), |
1479 | | DNSName("!") + DNSName("example.com"), Result::ERROR_BAD_DER), |
1480 | | |
1481 | | // Match a matching IPv4 address SAN entry. |
1482 | | WITH_SAN(ipv4_addr_str, RDN(CN("foo")), IPAddress(ipv4_addr_bytes), |
1483 | | Success), |
1484 | | // Match a matching IPv4 addresses in the CN when there is no SAN |
1485 | | WITHOUT_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)), Success), |
1486 | | // Do not match a matching IPv4 address in the CN when there is a SAN with |
1487 | | // a DNSName entry. |
1488 | | WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)), |
1489 | | DNSName("example.com"), Result::ERROR_BAD_CERT_DOMAIN), |
1490 | | // Do not match a matching IPv4 address in the CN when there is a SAN with |
1491 | | // a non-matching IPAddress entry. |
1492 | | WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)), |
1493 | | IPAddress(ipv6_addr_bytes), Result::ERROR_BAD_CERT_DOMAIN), |
1494 | | // Match a matching IPv4 address in the CN when there is a SAN with a |
1495 | | // non-IPAddress, non-DNSName entry. |
1496 | | WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)), |
1497 | | RFC822Name("foo@example.com"), Success), |
1498 | | // Do not match a matching IPv4 address in the CN when there is a SAN with a |
1499 | | // malformed IPAddress entry. |
1500 | | WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)), |
1501 | | IPAddress(example_com), Result::ERROR_BAD_CERT_DOMAIN), |
1502 | | // Do not match a matching IPv4 address in the CN when there is a SAN with a |
1503 | | // malformed DNSName entry. |
1504 | | WITH_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_str)), |
1505 | | DNSName("!"), Result::ERROR_BAD_CERT_DOMAIN), |
1506 | | |
1507 | | // We don't match IPv6 addresses in the CN, regardless of whether there is |
1508 | | // a SAN. |
1509 | | WITHOUT_SAN(ipv6_addr_str, RDN(CN(ipv6_addr_str)), |
1510 | | Result::ERROR_BAD_CERT_DOMAIN), |
1511 | | WITH_SAN(ipv6_addr_str, RDN(CN(ipv6_addr_str)), |
1512 | | DNSName("example.com"), Result::ERROR_BAD_CERT_DOMAIN), |
1513 | | WITH_SAN(ipv6_addr_str, RDN(CN(ipv6_addr_str)), |
1514 | | IPAddress(ipv6_addr_bytes), Success), |
1515 | | WITH_SAN(ipv6_addr_str, RDN(CN("foo")), IPAddress(ipv6_addr_bytes), |
1516 | | Success), |
1517 | | |
1518 | | // We don't match the binary encoding of the bytes of IP addresses in the |
1519 | | // CN. |
1520 | | WITHOUT_SAN(ipv4_addr_str, RDN(CN(ipv4_addr_bytes_as_str)), |
1521 | | Result::ERROR_BAD_CERT_DOMAIN), |
1522 | | WITHOUT_SAN(ipv6_addr_str, RDN(CN(ipv6_addr_bytes_as_str)), |
1523 | | Result::ERROR_BAD_CERT_DOMAIN), |
1524 | | |
1525 | | // We don't match IP addresses with DNSName SANs. |
1526 | | WITH_SAN(ipv4_addr_str, RDN(CN("foo")), |
1527 | | DNSName(ipv4_addr_bytes_as_str), Result::ERROR_BAD_CERT_DOMAIN), |
1528 | | WITH_SAN(ipv4_addr_str, RDN(CN("foo")), DNSName(ipv4_addr_str), |
1529 | | Result::ERROR_BAD_CERT_DOMAIN), |
1530 | | WITH_SAN(ipv6_addr_str, RDN(CN("foo")), |
1531 | | DNSName(ipv6_addr_bytes_as_str), Result::ERROR_BAD_CERT_DOMAIN), |
1532 | | WITH_SAN(ipv6_addr_str, RDN(CN("foo")), DNSName(ipv6_addr_str), |
1533 | | Result::ERROR_BAD_CERT_DOMAIN), |
1534 | | |
1535 | | // Do not match an IPv4 reference ID against the equivalent IPv4-compatible |
1536 | | // IPv6 SAN entry. |
1537 | | WITH_SAN(ipv4_addr_str, RDN(CN("foo")), |
1538 | | IPAddress(ipv4_compatible_ipv6_addr_bytes), |
1539 | | Result::ERROR_BAD_CERT_DOMAIN), |
1540 | | // Do not match an IPv4 reference ID against the equivalent IPv4-mapped IPv6 |
1541 | | // SAN entry. |
1542 | | WITH_SAN(ipv4_addr_str, RDN(CN("foo")), |
1543 | | IPAddress(ipv4_mapped_ipv6_addr_bytes), |
1544 | | Result::ERROR_BAD_CERT_DOMAIN), |
1545 | | // Do not match an IPv4-compatible IPv6 reference ID against the equivalent |
1546 | | // IPv4 SAN entry. |
1547 | | WITH_SAN(ipv4_compatible_ipv6_addr_str, RDN(CN("foo")), |
1548 | | IPAddress(ipv4_addr_bytes), Result::ERROR_BAD_CERT_DOMAIN), |
1549 | | // Do not match an IPv4 reference ID against the equivalent IPv4-mapped IPv6 |
1550 | | // SAN entry. |
1551 | | WITH_SAN(ipv4_mapped_ipv6_addr_str, RDN(CN("foo")), |
1552 | | IPAddress(ipv4_addr_bytes), |
1553 | | Result::ERROR_BAD_CERT_DOMAIN), |
1554 | | |
1555 | | // Test that the presence of an otherName entry is handled appropriately. |
1556 | | // (The actual value of the otherName entry isn't important - that's not what |
1557 | | // we're testing here.) |
1558 | | WITH_SAN("example.com", ByteString(), |
1559 | | // The tag for otherName is CONTEXT_SPECIFIC | CONSTRUCTED | 0 |
1560 | | TLV((2 << 6) | (1 << 5) | 0, ByteString()) + DNSName("example.com"), |
1561 | | Success), |
1562 | | WITH_SAN("example.com", ByteString(), |
1563 | | TLV((2 << 6) | (1 << 5) | 0, ByteString()), |
1564 | | Result::ERROR_BAD_CERT_DOMAIN), |
1565 | | }; |
1566 | | |
1567 | | ByteString |
1568 | | CreateCert(const ByteString& subject, const ByteString& subjectAltName, |
1569 | | EndEntityOrCA endEntityOrCA = EndEntityOrCA::MustBeEndEntity) |
1570 | 0 | { |
1571 | 0 | ByteString serialNumber(CreateEncodedSerialNumber(1)); |
1572 | 0 | EXPECT_FALSE(ENCODING_FAILED(serialNumber)); |
1573 | 0 |
|
1574 | 0 | ByteString issuerDER(Name(RDN(CN("issuer")))); |
1575 | 0 | EXPECT_FALSE(ENCODING_FAILED(issuerDER)); |
1576 | 0 |
|
1577 | 0 | ByteString extensions[2]; |
1578 | 0 | if (subjectAltName != NO_SAN) { |
1579 | 0 | extensions[0] = CreateEncodedSubjectAltName(subjectAltName); |
1580 | 0 | EXPECT_FALSE(ENCODING_FAILED(extensions[0])); |
1581 | 0 | } |
1582 | 0 | if (endEntityOrCA == EndEntityOrCA::MustBeCA) { |
1583 | 0 | // Currently, these tests assume that if we're creating a CA certificate, it |
1584 | 0 | // will not have a subjectAlternativeName extension. If that assumption |
1585 | 0 | // changes, this code will have to be updated. Ideally this would be |
1586 | 0 | // ASSERT_EQ, but that inserts a 'return;', which doesn't match this |
1587 | 0 | // function's return type. |
1588 | 0 | EXPECT_EQ(subjectAltName, NO_SAN); |
1589 | 0 | extensions[0] = CreateEncodedBasicConstraints(true, nullptr, |
1590 | 0 | Critical::Yes); |
1591 | 0 | EXPECT_FALSE(ENCODING_FAILED(extensions[0])); |
1592 | 0 | } |
1593 | 0 |
|
1594 | 0 | ScopedTestKeyPair keyPair(CloneReusedKeyPair()); |
1595 | 0 | return CreateEncodedCertificate( |
1596 | 0 | v3, sha256WithRSAEncryption(), serialNumber, issuerDER, |
1597 | 0 | oneDayBeforeNow, oneDayAfterNow, Name(subject), *keyPair, |
1598 | 0 | extensions, *keyPair, sha256WithRSAEncryption()); |
1599 | 0 | } |
1600 | | |
1601 | | TEST_P(pkixnames_CheckCertHostname, CheckCertHostname) |
1602 | 0 | { |
1603 | 0 | const CheckCertHostnameParams& param(GetParam()); |
1604 | 0 |
|
1605 | 0 | ByteString cert(CreateCert(param.subject, param.subjectAltName)); |
1606 | 0 | ASSERT_FALSE(ENCODING_FAILED(cert)); |
1607 | 0 | Input certInput; |
1608 | 0 | ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); |
1609 | 0 |
|
1610 | 0 | Input hostnameInput; |
1611 | 0 | ASSERT_EQ(Success, hostnameInput.Init(param.hostname.data(), |
1612 | 0 | param.hostname.length())); |
1613 | 0 |
|
1614 | 0 | ASSERT_EQ(param.result, CheckCertHostname(certInput, hostnameInput, |
1615 | 0 | mNameMatchingPolicy)); |
1616 | 0 | } |
1617 | | |
1618 | | INSTANTIATE_TEST_CASE_P(pkixnames_CheckCertHostname, |
1619 | | pkixnames_CheckCertHostname, |
1620 | | testing::ValuesIn(CHECK_CERT_HOSTNAME_PARAMS)); |
1621 | | |
1622 | | TEST_F(pkixnames_CheckCertHostname, SANWithoutSequence) |
1623 | 0 | { |
1624 | 0 | // A certificate with a truly empty SAN extension (one that doesn't even |
1625 | 0 | // contain a SEQUENCE at all) is malformed. If we didn't treat this as |
1626 | 0 | // malformed then we'd have to treat it like the CN_EmptySAN cases. |
1627 | 0 |
|
1628 | 0 | ByteString serialNumber(CreateEncodedSerialNumber(1)); |
1629 | 0 | EXPECT_FALSE(ENCODING_FAILED(serialNumber)); |
1630 | 0 |
|
1631 | 0 | ByteString extensions[2]; |
1632 | 0 | extensions[0] = CreateEncodedEmptySubjectAltName(); |
1633 | 0 | ASSERT_FALSE(ENCODING_FAILED(extensions[0])); |
1634 | 0 |
|
1635 | 0 | ScopedTestKeyPair keyPair(CloneReusedKeyPair()); |
1636 | 0 | ByteString certDER(CreateEncodedCertificate( |
1637 | 0 | v3, sha256WithRSAEncryption(), serialNumber, |
1638 | 0 | Name(RDN(CN("issuer"))), oneDayBeforeNow, oneDayAfterNow, |
1639 | 0 | Name(RDN(CN("a"))), *keyPair, extensions, |
1640 | 0 | *keyPair, sha256WithRSAEncryption())); |
1641 | 0 | ASSERT_FALSE(ENCODING_FAILED(certDER)); |
1642 | 0 | Input certInput; |
1643 | 0 | ASSERT_EQ(Success, certInput.Init(certDER.data(), certDER.length())); |
1644 | 0 |
|
1645 | 0 | static const uint8_t a[] = { 'a' }; |
1646 | 0 | ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID, |
1647 | 0 | CheckCertHostname(certInput, Input(a), mNameMatchingPolicy)); |
1648 | 0 | } |
1649 | | |
1650 | | class pkixnames_CheckCertHostname_PresentedMatchesReference |
1651 | | : public ::testing::Test |
1652 | | , public ::testing::WithParamInterface<PresentedMatchesReference> |
1653 | | { |
1654 | | public: |
1655 | | DefaultNameMatchingPolicy mNameMatchingPolicy; |
1656 | | }; |
1657 | | |
1658 | | TEST_P(pkixnames_CheckCertHostname_PresentedMatchesReference, CN_NoSAN) |
1659 | 0 | { |
1660 | 0 | // Since there is no SAN, a valid presented DNS ID in the subject CN field |
1661 | 0 | // should result in a match. |
1662 | 0 |
|
1663 | 0 | const PresentedMatchesReference& param(GetParam()); |
1664 | 0 |
|
1665 | 0 | ByteString cert(CreateCert(RDN(CN(param.presentedDNSID)), NO_SAN)); |
1666 | 0 | ASSERT_FALSE(ENCODING_FAILED(cert)); |
1667 | 0 | Input certInput; |
1668 | 0 | ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); |
1669 | 0 |
|
1670 | 0 | Input hostnameInput; |
1671 | 0 | ASSERT_EQ(Success, hostnameInput.Init(param.referenceDNSID.data(), |
1672 | 0 | param.referenceDNSID.length())); |
1673 | 0 |
|
1674 | 0 | ASSERT_EQ(param.expectedMatches ? Success : Result::ERROR_BAD_CERT_DOMAIN, |
1675 | 0 | CheckCertHostname(certInput, hostnameInput, mNameMatchingPolicy)); |
1676 | 0 | } |
1677 | | |
1678 | | TEST_P(pkixnames_CheckCertHostname_PresentedMatchesReference, |
1679 | | SubjectAltName_CNNotDNSName) |
1680 | 0 | { |
1681 | 0 | // A DNSName SAN entry should match, regardless of the contents of the |
1682 | 0 | // subject CN. |
1683 | 0 |
|
1684 | 0 | const PresentedMatchesReference& param(GetParam()); |
1685 | 0 |
|
1686 | 0 | ByteString cert(CreateCert(RDN(CN("Common Name")), |
1687 | 0 | DNSName(param.presentedDNSID))); |
1688 | 0 | ASSERT_FALSE(ENCODING_FAILED(cert)); |
1689 | 0 | Input certInput; |
1690 | 0 | ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); |
1691 | 0 |
|
1692 | 0 | Input hostnameInput; |
1693 | 0 | ASSERT_EQ(Success, hostnameInput.Init(param.referenceDNSID.data(), |
1694 | 0 | param.referenceDNSID.length())); |
1695 | 0 | Result expectedResult |
1696 | 0 | = param.expectedResult != Success ? param.expectedResult |
1697 | 0 | : param.expectedMatches ? Success |
1698 | 0 | : Result::ERROR_BAD_CERT_DOMAIN; |
1699 | 0 | ASSERT_EQ(expectedResult, CheckCertHostname(certInput, hostnameInput, |
1700 | 0 | mNameMatchingPolicy)); |
1701 | 0 | } |
1702 | | |
1703 | | INSTANTIATE_TEST_CASE_P(pkixnames_CheckCertHostname_DNSID_MATCH_PARAMS, |
1704 | | pkixnames_CheckCertHostname_PresentedMatchesReference, |
1705 | | testing::ValuesIn(DNSID_MATCH_PARAMS)); |
1706 | | |
1707 | | TEST_P(pkixnames_Turkish_I_Comparison, CheckCertHostname_CN_NoSAN) |
1708 | 0 | { |
1709 | 0 | // Make sure we don't have the similar problems that strcasecmp and others |
1710 | 0 | // have with the other kinds of "i" and "I" commonly used in Turkish locales, |
1711 | 0 | // when we're matching a CN due to lack of subjectAltName. |
1712 | 0 |
|
1713 | 0 | const InputValidity& param(GetParam()); |
1714 | 0 | SCOPED_TRACE(param.input.c_str()); |
1715 | 0 |
|
1716 | 0 | Input input; |
1717 | 0 | ASSERT_EQ(Success, input.Init(param.input.data(), param.input.length())); |
1718 | 0 |
|
1719 | 0 | ByteString cert(CreateCert(RDN(CN(param.input)), NO_SAN)); |
1720 | 0 | ASSERT_FALSE(ENCODING_FAILED(cert)); |
1721 | 0 | Input certInput; |
1722 | 0 | ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); |
1723 | 0 |
|
1724 | 0 | Result expectedResult = (InputsAreEqual(LOWERCASE_I, input) || |
1725 | 0 | InputsAreEqual(UPPERCASE_I, input)) |
1726 | 0 | ? Success |
1727 | 0 | : Result::ERROR_BAD_CERT_DOMAIN; |
1728 | 0 |
|
1729 | 0 | ASSERT_EQ(expectedResult, CheckCertHostname(certInput, UPPERCASE_I, |
1730 | 0 | mNameMatchingPolicy)); |
1731 | 0 | ASSERT_EQ(expectedResult, CheckCertHostname(certInput, LOWERCASE_I, |
1732 | 0 | mNameMatchingPolicy)); |
1733 | 0 | } |
1734 | | |
1735 | | TEST_P(pkixnames_Turkish_I_Comparison, CheckCertHostname_SAN) |
1736 | 0 | { |
1737 | 0 | // Make sure we don't have the similar problems that strcasecmp and others |
1738 | 0 | // have with the other kinds of "i" and "I" commonly used in Turkish locales, |
1739 | 0 | // when we're matching a dNSName in the SAN. |
1740 | 0 |
|
1741 | 0 | const InputValidity& param(GetParam()); |
1742 | 0 | SCOPED_TRACE(param.input.c_str()); |
1743 | 0 |
|
1744 | 0 | Input input; |
1745 | 0 | ASSERT_EQ(Success, input.Init(param.input.data(), param.input.length())); |
1746 | 0 |
|
1747 | 0 | ByteString cert(CreateCert(RDN(CN("Common Name")), DNSName(param.input))); |
1748 | 0 | ASSERT_FALSE(ENCODING_FAILED(cert)); |
1749 | 0 | Input certInput; |
1750 | 0 | ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); |
1751 | 0 |
|
1752 | 0 | Result expectedResult |
1753 | 0 | = (!param.isValidPresentedID) ? Result::ERROR_BAD_DER |
1754 | 0 | : (InputsAreEqual(LOWERCASE_I, input) || |
1755 | 0 | InputsAreEqual(UPPERCASE_I, input)) ? Success |
1756 | 0 | : Result::ERROR_BAD_CERT_DOMAIN; |
1757 | 0 |
|
1758 | 0 | ASSERT_EQ(expectedResult, CheckCertHostname(certInput, UPPERCASE_I, |
1759 | 0 | mNameMatchingPolicy)); |
1760 | 0 | ASSERT_EQ(expectedResult, CheckCertHostname(certInput, LOWERCASE_I, |
1761 | 0 | mNameMatchingPolicy)); |
1762 | 0 | } |
1763 | | |
1764 | | class pkixnames_CheckCertHostname_IPV4_Addresses |
1765 | | : public ::testing::Test |
1766 | | , public ::testing::WithParamInterface<IPAddressParams<4>> |
1767 | | { |
1768 | | public: |
1769 | | DefaultNameMatchingPolicy mNameMatchingPolicy; |
1770 | | }; |
1771 | | |
1772 | | TEST_P(pkixnames_CheckCertHostname_IPV4_Addresses, |
1773 | | ValidIPv4AddressInIPAddressSAN) |
1774 | 0 | { |
1775 | 0 | // When the reference hostname is a valid IPv4 address, a correctly-formed |
1776 | 0 | // IPv4 Address SAN matches it. |
1777 | 0 |
|
1778 | 0 | const IPAddressParams<4>& param(GetParam()); |
1779 | 0 |
|
1780 | 0 | ByteString cert(CreateCert(RDN(CN("Common Name")), |
1781 | 0 | IPAddress(param.expectedValueIfValid))); |
1782 | 0 | ASSERT_FALSE(ENCODING_FAILED(cert)); |
1783 | 0 | Input certInput; |
1784 | 0 | ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); |
1785 | 0 |
|
1786 | 0 | Input hostnameInput; |
1787 | 0 | ASSERT_EQ(Success, hostnameInput.Init(param.input.data(), |
1788 | 0 | param.input.length())); |
1789 | 0 |
|
1790 | 0 | ASSERT_EQ(param.isValid ? Success : Result::ERROR_BAD_CERT_DOMAIN, |
1791 | 0 | CheckCertHostname(certInput, hostnameInput, mNameMatchingPolicy)); |
1792 | 0 | } |
1793 | | |
1794 | | TEST_P(pkixnames_CheckCertHostname_IPV4_Addresses, |
1795 | | ValidIPv4AddressInCN_NoSAN) |
1796 | 0 | { |
1797 | 0 | // When the reference hostname is a valid IPv4 address, a correctly-formed |
1798 | 0 | // IPv4 Address in the CN matches it when there is no SAN. |
1799 | 0 |
|
1800 | 0 | const IPAddressParams<4>& param(GetParam()); |
1801 | 0 |
|
1802 | 0 | SCOPED_TRACE(param.input.c_str()); |
1803 | 0 |
|
1804 | 0 | ByteString cert(CreateCert(RDN(CN(param.input)), NO_SAN)); |
1805 | 0 | ASSERT_FALSE(ENCODING_FAILED(cert)); |
1806 | 0 | Input certInput; |
1807 | 0 | ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); |
1808 | 0 |
|
1809 | 0 | Input hostnameInput; |
1810 | 0 | ASSERT_EQ(Success, hostnameInput.Init(param.input.data(), |
1811 | 0 | param.input.length())); |
1812 | 0 |
|
1813 | 0 | // Some of the invalid IPv4 addresses are valid DNS names! |
1814 | 0 | Result expectedResult = (param.isValid || IsValidReferenceDNSID(hostnameInput)) |
1815 | 0 | ? Success |
1816 | 0 | : Result::ERROR_BAD_CERT_DOMAIN; |
1817 | 0 |
|
1818 | 0 | ASSERT_EQ(expectedResult, CheckCertHostname(certInput, hostnameInput, |
1819 | 0 | mNameMatchingPolicy)); |
1820 | 0 | } |
1821 | | |
1822 | | INSTANTIATE_TEST_CASE_P(pkixnames_CheckCertHostname_IPV4_ADDRESSES, |
1823 | | pkixnames_CheckCertHostname_IPV4_Addresses, |
1824 | | testing::ValuesIn(IPV4_ADDRESSES)); |
1825 | | |
1826 | | struct NameConstraintParams |
1827 | | { |
1828 | | ByteString subject; |
1829 | | ByteString subjectAltName; |
1830 | | ByteString subtrees; |
1831 | | Result expectedPermittedSubtreesResult; |
1832 | | Result expectedExcludedSubtreesResult; |
1833 | | }; |
1834 | | |
1835 | | ::std::ostream& operator<<(::std::ostream& os, const NameConstraintParams&) |
1836 | 0 | { |
1837 | 0 | return os << "TODO (bug 1318770)"; |
1838 | 0 | } |
1839 | | |
1840 | | static ByteString |
1841 | | PermittedSubtrees(const ByteString& generalSubtrees) |
1842 | 0 | { |
1843 | 0 | return TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0, |
1844 | 0 | generalSubtrees); |
1845 | 0 | } |
1846 | | |
1847 | | static ByteString |
1848 | | ExcludedSubtrees(const ByteString& generalSubtrees) |
1849 | 0 | { |
1850 | 0 | return TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, |
1851 | 0 | generalSubtrees); |
1852 | 0 | } |
1853 | | |
1854 | | // Does not encode min or max. |
1855 | | static ByteString |
1856 | | GeneralSubtree(const ByteString& base) |
1857 | 429 | { |
1858 | 429 | return TLV(der::SEQUENCE, base); |
1859 | 429 | } |
1860 | | |
1861 | | static const NameConstraintParams NAME_CONSTRAINT_PARAMS[] = |
1862 | | { |
1863 | | ///////////////////////////////////////////////////////////////////////////// |
1864 | | // XXX: Malformed name constraints for supported types of names are ignored |
1865 | | // when there are no names of that type to constrain. |
1866 | | { ByteString(), NO_SAN, |
1867 | | GeneralSubtree(DNSName("!")), |
1868 | | Success, Success |
1869 | | }, |
1870 | | { // DirectoryName constraints are an exception, because *every* certificate |
1871 | | // has at least one DirectoryName (tbsCertificate.subject). |
1872 | | ByteString(), NO_SAN, |
1873 | | GeneralSubtree(Name(ByteString(reinterpret_cast<const uint8_t*>("!"), 1))), |
1874 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
1875 | | }, |
1876 | | { ByteString(), NO_SAN, |
1877 | | GeneralSubtree(IPAddress(ipv4_constraint_truncated_bytes)), |
1878 | | Success, Success |
1879 | | }, |
1880 | | { ByteString(), NO_SAN, |
1881 | | GeneralSubtree(IPAddress(ipv4_constraint_overlong_bytes)), |
1882 | | Success, Success |
1883 | | }, |
1884 | | { ByteString(), NO_SAN, |
1885 | | GeneralSubtree(IPAddress(ipv6_constraint_truncated_bytes)), |
1886 | | Success, Success |
1887 | | }, |
1888 | | { ByteString(), NO_SAN, |
1889 | | GeneralSubtree(IPAddress(ipv6_constraint_overlong_bytes)), |
1890 | | Success, Success |
1891 | | }, |
1892 | | { ByteString(), NO_SAN, |
1893 | | GeneralSubtree(RFC822Name("!")), |
1894 | | Success, Success |
1895 | | }, |
1896 | | |
1897 | | ///////////////////////////////////////////////////////////////////////////// |
1898 | | // Edge cases of name constraint absolute vs. relative and subdomain matching |
1899 | | // that are not clearly explained in RFC 5280. (See the long comment above |
1900 | | // MatchPresentedDNSIDWithReferenceDNSID.) |
1901 | | |
1902 | | // Q: Does a presented identifier equal (case insensitive) to the name |
1903 | | // constraint match the constraint? For example, does the presented |
1904 | | // ID "host.example.com" match a "host.example.com" constraint? |
1905 | | { ByteString(), DNSName("host.example.com"), |
1906 | | GeneralSubtree(DNSName("host.example.com")), |
1907 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
1908 | | }, |
1909 | | { // This test case is an example from RFC 5280. |
1910 | | ByteString(), DNSName("host1.example.com"), |
1911 | | GeneralSubtree(DNSName("host.example.com")), |
1912 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
1913 | | }, |
1914 | | { ByteString(), RFC822Name("a@host.example.com"), |
1915 | | GeneralSubtree(RFC822Name("host.example.com")), |
1916 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
1917 | | }, |
1918 | | { // This test case is an example from RFC 5280. |
1919 | | ByteString(), RFC822Name("a@host1.example.com"), |
1920 | | GeneralSubtree(RFC822Name("host.example.com")), |
1921 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
1922 | | }, |
1923 | | |
1924 | | // Q: When the name constraint does not start with ".", do subdomain |
1925 | | // presented identifiers match it? For example, does the presented |
1926 | | // ID "www.host.example.com" match a "host.example.com" constraint? |
1927 | | { // This test case is an example from RFC 5280. |
1928 | | ByteString(), DNSName("www.host.example.com"), |
1929 | | GeneralSubtree(DNSName( "host.example.com")), |
1930 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
1931 | | }, |
1932 | | { // The subdomain matching rule for host names that do not start with "." is |
1933 | | // different for RFC822Names than for DNSNames! |
1934 | | ByteString(), RFC822Name("a@www.host.example.com"), |
1935 | | GeneralSubtree(RFC822Name( "host.example.com")), |
1936 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, |
1937 | | Success |
1938 | | }, |
1939 | | |
1940 | | // Q: When the name constraint does not start with ".", does a |
1941 | | // non-subdomain prefix match it? For example, does "bigfoo.bar.com" |
1942 | | // match "foo.bar.com"? |
1943 | | { ByteString(), DNSName("bigfoo.bar.com"), |
1944 | | GeneralSubtree(DNSName( "foo.bar.com")), |
1945 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
1946 | | }, |
1947 | | { ByteString(), RFC822Name("a@bigfoo.bar.com"), |
1948 | | GeneralSubtree(RFC822Name( "foo.bar.com")), |
1949 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
1950 | | }, |
1951 | | |
1952 | | // Q: Is a name constraint that starts with "." valid, and if so, what |
1953 | | // semantics does it have? For example, does a presented ID of |
1954 | | // "www.example.com" match a constraint of ".example.com"? Does a |
1955 | | // presented ID of "example.com" match a constraint of ".example.com"? |
1956 | | { ByteString(), DNSName("www.example.com"), |
1957 | | GeneralSubtree(DNSName( ".example.com")), |
1958 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
1959 | | }, |
1960 | | { // When there is no Local-part, an RFC822 name constraint's domain may |
1961 | | // start with '.', and the semantics are the same as for DNSNames. |
1962 | | ByteString(), RFC822Name("a@www.example.com"), |
1963 | | GeneralSubtree(RFC822Name( ".example.com")), |
1964 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
1965 | | }, |
1966 | | { // When there is a Local-part, an RFC822 name constraint's domain must not |
1967 | | // start with '.'. |
1968 | | ByteString(), RFC822Name("a@www.example.com"), |
1969 | | GeneralSubtree(RFC822Name( "a@.example.com")), |
1970 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
1971 | | }, |
1972 | | { // Check that we only allow subdomains to match. |
1973 | | ByteString(), DNSName( "example.com"), |
1974 | | GeneralSubtree(DNSName(".example.com")), |
1975 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
1976 | | }, |
1977 | | { // Check that we only allow subdomains to match. |
1978 | | ByteString(), RFC822Name("a@example.com"), |
1979 | | GeneralSubtree(RFC822Name(".example.com")), |
1980 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
1981 | | }, |
1982 | | { // Check that we don't get confused and consider "b" == "." |
1983 | | ByteString(), DNSName("bexample.com"), |
1984 | | GeneralSubtree(DNSName(".example.com")), |
1985 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
1986 | | }, |
1987 | | { // Check that we don't get confused and consider "b" == "." |
1988 | | ByteString(), RFC822Name("a@bexample.com"), |
1989 | | GeneralSubtree(RFC822Name( ".example.com")), |
1990 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
1991 | | }, |
1992 | | |
1993 | | // Q: Is there a way to prevent subdomain matches? |
1994 | | // (This is tested in a different set of tests because it requires a |
1995 | | // combination of permittedSubtrees and excludedSubtrees.) |
1996 | | |
1997 | | // Q: Are name constraints allowed to be specified as absolute names? |
1998 | | // For example, does a presented ID of "example.com" match a name |
1999 | | // constraint of "example.com." and vice versa? |
2000 | | // |
2001 | | { // The DNSName in the constraint is not valid because constraint DNS IDs |
2002 | | // are not allowed to be absolute. |
2003 | | ByteString(), DNSName("example.com"), |
2004 | | GeneralSubtree(DNSName("example.com.")), |
2005 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER, |
2006 | | }, |
2007 | | { ByteString(), RFC822Name("a@example.com"), |
2008 | | GeneralSubtree(RFC822Name( "example.com.")), |
2009 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER, |
2010 | | }, |
2011 | | { // The DNSName in the SAN is not valid because presented DNS IDs are not |
2012 | | // allowed to be absolute. |
2013 | | ByteString(), DNSName("example.com."), |
2014 | | GeneralSubtree(DNSName("example.com")), |
2015 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER, |
2016 | | }, |
2017 | | { ByteString(), RFC822Name("a@example.com."), |
2018 | | GeneralSubtree(RFC822Name( "example.com")), |
2019 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER, |
2020 | | }, |
2021 | | { // The presented DNSName is the same length as the constraint, because the |
2022 | | // subdomain is only one character long and because the constraint both |
2023 | | // begins and ends with ".". But, it doesn't matter because absolute names |
2024 | | // are not allowed for DNSName constraints. |
2025 | | ByteString(), DNSName("p.example.com"), |
2026 | | GeneralSubtree(DNSName(".example.com.")), |
2027 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER, |
2028 | | }, |
2029 | | { // The presented DNSName is the same length as the constraint, because the |
2030 | | // subdomain is only one character long and because the constraint both |
2031 | | // begins and ends with ".". |
2032 | | ByteString(), RFC822Name("a@p.example.com"), |
2033 | | GeneralSubtree(RFC822Name( ".example.com.")), |
2034 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER, |
2035 | | }, |
2036 | | { // Same as previous test case, but using a wildcard presented ID. |
2037 | | ByteString(), DNSName("*.example.com"), |
2038 | | GeneralSubtree(DNSName(".example.com.")), |
2039 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2040 | | }, |
2041 | | { // Same as previous test case, but using a wildcard presented ID, which is |
2042 | | // invalid in an RFC822Name. |
2043 | | ByteString(), RFC822Name("a@*.example.com"), |
2044 | | GeneralSubtree(RFC822Name( ".example.com.")), |
2045 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2046 | | }, |
2047 | | |
2048 | | // Q: Are "" and "." valid DNSName constraints? If so, what do they mean? |
2049 | | { ByteString(), DNSName("example.com"), |
2050 | | GeneralSubtree(DNSName("")), |
2051 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2052 | | }, |
2053 | | { ByteString(), RFC822Name("a@example.com"), |
2054 | | GeneralSubtree(RFC822Name("")), |
2055 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2056 | | }, |
2057 | | { // The malformed (absolute) presented ID does not match. |
2058 | | ByteString(), DNSName("example.com."), |
2059 | | GeneralSubtree(DNSName("")), |
2060 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2061 | | }, |
2062 | | { ByteString(), RFC822Name("a@example.com."), |
2063 | | GeneralSubtree(RFC822Name("")), |
2064 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2065 | | }, |
2066 | | { // Invalid syntax in name constraint |
2067 | | ByteString(), DNSName("example.com"), |
2068 | | GeneralSubtree(DNSName(".")), |
2069 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER, |
2070 | | }, |
2071 | | { // Invalid syntax in name constraint |
2072 | | ByteString(), RFC822Name("a@example.com"), |
2073 | | GeneralSubtree(RFC822Name(".")), |
2074 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER, |
2075 | | }, |
2076 | | { ByteString(), DNSName("example.com."), |
2077 | | GeneralSubtree(DNSName(".")), |
2078 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2079 | | }, |
2080 | | { ByteString(), RFC822Name("a@example.com."), |
2081 | | GeneralSubtree(RFC822Name(".")), |
2082 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2083 | | }, |
2084 | | |
2085 | | ///////////////////////////////////////////////////////////////////////////// |
2086 | | // Basic IP Address constraints (non-CN-ID) |
2087 | | |
2088 | | // The Mozilla CA Policy says this means "no IPv4 addresses allowed." |
2089 | | { ByteString(), IPAddress(ipv4_addr_bytes), |
2090 | | GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)), |
2091 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2092 | | }, |
2093 | | { ByteString(), IPAddress(ipv4_addr_00000000_bytes), |
2094 | | GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)), |
2095 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2096 | | }, |
2097 | | { ByteString(), IPAddress(ipv4_addr_FFFFFFFF_bytes), |
2098 | | GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)), |
2099 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2100 | | }, |
2101 | | |
2102 | | // The Mozilla CA Policy says this means "no IPv6 addresses allowed." |
2103 | | { ByteString(), IPAddress(ipv6_addr_bytes), |
2104 | | GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)), |
2105 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2106 | | }, |
2107 | | { ByteString(), IPAddress(ipv6_addr_all_zeros_bytes), |
2108 | | GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)), |
2109 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2110 | | }, |
2111 | | |
2112 | | // RFC 5280 doesn't partition IP address constraints into separate IPv4 and |
2113 | | // IPv6 categories, so a IPv4 permittedSubtrees constraint excludes all IPv6 |
2114 | | // addresses, and vice versa. |
2115 | | { ByteString(), IPAddress(ipv4_addr_bytes), |
2116 | | GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)), |
2117 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2118 | | }, |
2119 | | { ByteString(), IPAddress(ipv6_addr_bytes), |
2120 | | GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)), |
2121 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2122 | | }, |
2123 | | |
2124 | | // IPv4 Subnets |
2125 | | { ByteString(), IPAddress(ipv4_addr_bytes), |
2126 | | GeneralSubtree(IPAddress(ipv4_constraint_CIDR_16_bytes)), |
2127 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2128 | | }, |
2129 | | { ByteString(), IPAddress(ipv4_addr_bytes), |
2130 | | GeneralSubtree(IPAddress(ipv4_constraint_CIDR_17_bytes)), |
2131 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2132 | | }, |
2133 | | { ByteString(), IPAddress(ipv4_other_addr_bytes), |
2134 | | GeneralSubtree(IPAddress(ipv4_constraint_CIDR_16_bytes)), |
2135 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2136 | | }, |
2137 | | { // XXX(bug 1089430): We don't reject this even though it is weird. |
2138 | | ByteString(), IPAddress(ipv4_addr_bytes), |
2139 | | GeneralSubtree(IPAddress(ipv4_constraint_CIDR_16_bad_addr_bytes)), |
2140 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2141 | | }, |
2142 | | { // XXX(bug 1089430): We don't reject this even though it is weird. |
2143 | | ByteString(), IPAddress(ipv4_other_addr_bytes), |
2144 | | GeneralSubtree(IPAddress(ipv4_constraint_bad_mask_bytes)), |
2145 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2146 | | }, |
2147 | | |
2148 | | // IPv6 Subnets |
2149 | | { ByteString(), IPAddress(ipv6_addr_bytes), |
2150 | | GeneralSubtree(IPAddress(ipv6_constraint_CIDR_16_bytes)), |
2151 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2152 | | }, |
2153 | | { ByteString(), IPAddress(ipv6_other_addr_bytes), |
2154 | | GeneralSubtree(IPAddress(ipv6_constraint_CIDR_16_bytes)), |
2155 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2156 | | }, |
2157 | | { // XXX(bug 1089430): We don't reject this even though it is weird. |
2158 | | ByteString(), IPAddress(ipv6_addr_bytes), |
2159 | | GeneralSubtree(IPAddress(ipv6_constraint_CIDR_16_bad_addr_bytes)), |
2160 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2161 | | }, |
2162 | | { // XXX(bug 1089430): We don't reject this even though it is weird. |
2163 | | ByteString(), IPAddress(ipv6_other_addr_bytes), |
2164 | | GeneralSubtree(IPAddress(ipv6_constraint_bad_mask_bytes)), |
2165 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2166 | | }, |
2167 | | |
2168 | | // Malformed presented IP addresses and constraints |
2169 | | |
2170 | | { // The presented IPv4 address is empty |
2171 | | ByteString(), IPAddress(), |
2172 | | GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)), |
2173 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2174 | | }, |
2175 | | { // The presented IPv4 address is truncated |
2176 | | ByteString(), IPAddress(ipv4_addr_truncated_bytes), |
2177 | | GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)), |
2178 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2179 | | }, |
2180 | | { // The presented IPv4 address is too long |
2181 | | ByteString(), IPAddress(ipv4_addr_overlong_bytes), |
2182 | | GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)), |
2183 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2184 | | }, |
2185 | | { // The presented IPv4 constraint is empty |
2186 | | ByteString(), IPAddress(ipv4_addr_bytes), |
2187 | | GeneralSubtree(IPAddress()), |
2188 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2189 | | }, |
2190 | | { // The presented IPv4 constraint is truncated |
2191 | | ByteString(), IPAddress(ipv4_addr_bytes), |
2192 | | GeneralSubtree(IPAddress(ipv4_constraint_truncated_bytes)), |
2193 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2194 | | }, |
2195 | | { // The presented IPv4 constraint is too long |
2196 | | ByteString(), IPAddress(ipv4_addr_bytes), |
2197 | | GeneralSubtree(IPAddress(ipv4_constraint_overlong_bytes)), |
2198 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2199 | | }, |
2200 | | { // The presented IPv6 address is empty |
2201 | | ByteString(), IPAddress(), |
2202 | | GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)), |
2203 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2204 | | }, |
2205 | | { // The presented IPv6 address is truncated |
2206 | | ByteString(), IPAddress(ipv6_addr_truncated_bytes), |
2207 | | GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)), |
2208 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2209 | | }, |
2210 | | { // The presented IPv6 address is too long |
2211 | | ByteString(), IPAddress(ipv6_addr_overlong_bytes), |
2212 | | GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)), |
2213 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2214 | | }, |
2215 | | { // The presented IPv6 constraint is empty |
2216 | | ByteString(), IPAddress(ipv6_addr_bytes), |
2217 | | GeneralSubtree(IPAddress()), |
2218 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2219 | | }, |
2220 | | { // The presented IPv6 constraint is truncated |
2221 | | ByteString(), IPAddress(ipv6_addr_bytes), |
2222 | | GeneralSubtree(IPAddress(ipv6_constraint_truncated_bytes)), |
2223 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2224 | | }, |
2225 | | { // The presented IPv6 constraint is too long |
2226 | | ByteString(), IPAddress(ipv6_addr_bytes), |
2227 | | GeneralSubtree(IPAddress(ipv6_constraint_overlong_bytes)), |
2228 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2229 | | }, |
2230 | | |
2231 | | ///////////////////////////////////////////////////////////////////////////// |
2232 | | // XXX: We don't reject malformed name constraints when there are no names of |
2233 | | // that type. |
2234 | | { ByteString(), NO_SAN, GeneralSubtree(DNSName("!")), |
2235 | | Success, Success |
2236 | | }, |
2237 | | { ByteString(), NO_SAN, GeneralSubtree(IPAddress(ipv4_addr_overlong_bytes)), |
2238 | | Success, Success |
2239 | | }, |
2240 | | { ByteString(), NO_SAN, GeneralSubtree(IPAddress(ipv6_addr_overlong_bytes)), |
2241 | | Success, Success |
2242 | | }, |
2243 | | { ByteString(), NO_SAN, GeneralSubtree(RFC822Name("\0")), |
2244 | | Success, Success |
2245 | | }, |
2246 | | |
2247 | | ///////////////////////////////////////////////////////////////////////////// |
2248 | | // Basic CN-ID DNSName constraint tests. |
2249 | | |
2250 | | { // Empty Name is ignored for DNSName constraints. |
2251 | | ByteString(), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2252 | | Success, Success |
2253 | | }, |
2254 | | { // Empty CN is ignored for DNSName constraints because it isn't a |
2255 | | // syntactically-valid DNSName. |
2256 | | // |
2257 | | // NSS gives different results. |
2258 | | RDN(CN("")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2259 | | Success, Success |
2260 | | }, |
2261 | | { // IP Address is ignored for DNSName constraints. |
2262 | | // |
2263 | | // NSS gives different results. |
2264 | | RDN(CN("1.2.3.4")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2265 | | Success, Success |
2266 | | }, |
2267 | | { // OU has something that looks like a dNSName that matches. |
2268 | | RDN(OU("a.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2269 | | Success, Success |
2270 | | }, |
2271 | | { // OU has something that looks like a dNSName that does not match. |
2272 | | RDN(OU("b.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2273 | | Success, Success |
2274 | | }, |
2275 | | { // NSS gives different results. |
2276 | | RDN(CN("Not a DNSName")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2277 | | Success, Success |
2278 | | }, |
2279 | | { RDN(CN("a.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2280 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2281 | | }, |
2282 | | { RDN(CN("b.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2283 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2284 | | }, |
2285 | | { // DNSName CN-ID match is detected when there is a SAN w/o any DNSName or |
2286 | | // IPAddress |
2287 | | RDN(CN("a.example.com")), RFC822Name("foo@example.com"), |
2288 | | GeneralSubtree(DNSName("a.example.com")), |
2289 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2290 | | }, |
2291 | | { // DNSName CN-ID mismatch is detected when there is a SAN w/o any DNSName |
2292 | | // or IPAddress |
2293 | | RDN(CN("a.example.com")), RFC822Name("foo@example.com"), |
2294 | | GeneralSubtree(DNSName("b.example.com")), |
2295 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2296 | | }, |
2297 | | { // DNSName CN-ID match not reported when there is a DNSName SAN |
2298 | | RDN(CN("a.example.com")), DNSName("b.example.com"), |
2299 | | GeneralSubtree(DNSName("a.example.com")), |
2300 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2301 | | }, |
2302 | | { // DNSName CN-ID mismatch not reported when there is a DNSName SAN |
2303 | | RDN(CN("a.example.com")), DNSName("b.example.com"), |
2304 | | GeneralSubtree(DNSName("b.example.com")), |
2305 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE, |
2306 | | }, |
2307 | | { // DNSName CN-ID match not reported when there is an IPAddress SAN |
2308 | | RDN(CN("a.example.com")), IPAddress(ipv4_addr_bytes), |
2309 | | GeneralSubtree(DNSName("a.example.com")), |
2310 | | Success, Success |
2311 | | }, |
2312 | | { // DNSName CN-ID mismatch not reported when there is an IPAddress SAN |
2313 | | RDN(CN("a.example.com")), IPAddress(ipv4_addr_bytes), |
2314 | | GeneralSubtree(DNSName("b.example.com")), |
2315 | | Success, Success |
2316 | | }, |
2317 | | |
2318 | | { // IPAddress CN-ID match is detected when there is a SAN w/o any DNSName or |
2319 | | // IPAddress |
2320 | | RDN(CN(ipv4_addr_str)), RFC822Name("foo@example.com"), |
2321 | | GeneralSubtree(IPAddress(ipv4_addr_bytes_FFFFFFFF)), |
2322 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2323 | | }, |
2324 | | { // IPAddress CN-ID mismatch is detected when there is a SAN w/o any DNSName |
2325 | | // or IPAddress |
2326 | | RDN(CN(ipv4_addr_str)), RFC822Name("foo@example.com"), |
2327 | | GeneralSubtree(IPAddress(ipv4_other_addr_bytes_FFFFFFFF)), |
2328 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2329 | | }, |
2330 | | { // IPAddress CN-ID match not reported when there is a DNSName SAN |
2331 | | RDN(CN(ipv4_addr_str)), DNSName("b.example.com"), |
2332 | | GeneralSubtree(IPAddress(ipv4_addr_bytes_FFFFFFFF)), |
2333 | | Success, Success |
2334 | | }, |
2335 | | { // IPAddress CN-ID mismatch not reported when there is a DNSName SAN |
2336 | | RDN(CN(ipv4_addr_str)), DNSName("b.example.com"), |
2337 | | GeneralSubtree(IPAddress(ipv4_addr_bytes_FFFFFFFF)), |
2338 | | Success, Success |
2339 | | }, |
2340 | | { // IPAddress CN-ID match not reported when there is an IPAddress SAN |
2341 | | RDN(CN(ipv4_addr_str)), IPAddress(ipv4_other_addr_bytes), |
2342 | | GeneralSubtree(IPAddress(ipv4_addr_bytes_FFFFFFFF)), |
2343 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2344 | | }, |
2345 | | { // IPAddress CN-ID mismatch not reported when there is an IPAddress SAN |
2346 | | RDN(CN(ipv4_addr_str)), IPAddress(ipv4_other_addr_bytes), |
2347 | | GeneralSubtree(IPAddress(ipv4_other_addr_bytes_FFFFFFFF)), |
2348 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2349 | | }, |
2350 | | |
2351 | | ///////////////////////////////////////////////////////////////////////////// |
2352 | | // Test that constraints are applied to the most specific (last) CN, and only |
2353 | | // that CN-ID. |
2354 | | |
2355 | | { // Name constraint only matches a.example.com, but the most specific CN |
2356 | | // (i.e. the CN-ID) is b.example.com. (Two CNs in one RDN.) |
2357 | | RDN(CN("a.example.com") + CN("b.example.com")), NO_SAN, |
2358 | | GeneralSubtree(DNSName("a.example.com")), |
2359 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2360 | | }, |
2361 | | { // Name constraint only matches a.example.com, but the most specific CN |
2362 | | // (i.e. the CN-ID) is b.example.com. (Two CNs in separate RDNs.) |
2363 | | RDN(CN("a.example.com")) + RDN(CN("b.example.com")), NO_SAN, |
2364 | | GeneralSubtree(DNSName("a.example.com")), |
2365 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success |
2366 | | }, |
2367 | | { // Name constraint only permits b.example.com, and the most specific CN |
2368 | | // (i.e. the CN-ID) is b.example.com. (Two CNs in one RDN.) |
2369 | | RDN(CN("a.example.com") + CN("b.example.com")), NO_SAN, |
2370 | | GeneralSubtree(DNSName("b.example.com")), |
2371 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2372 | | }, |
2373 | | { // Name constraint only permits b.example.com, and the most specific CN |
2374 | | // (i.e. the CN-ID) is b.example.com. (Two CNs in separate RDNs.) |
2375 | | RDN(CN("a.example.com")) + RDN(CN("b.example.com")), NO_SAN, |
2376 | | GeneralSubtree(DNSName("b.example.com")), |
2377 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2378 | | }, |
2379 | | |
2380 | | ///////////////////////////////////////////////////////////////////////////// |
2381 | | // Additional RFC822 name constraint tests. There are more tests regarding |
2382 | | // the DNSName part of the constraint mixed into the DNSName constraint |
2383 | | // tests. |
2384 | | |
2385 | | { ByteString(), RFC822Name("a@example.com"), |
2386 | | GeneralSubtree(RFC822Name("a@example.com")), |
2387 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2388 | | }, |
2389 | | |
2390 | | // Bug 1056773: name constraints that omit Local-part but include '@' are |
2391 | | // invalid. |
2392 | | { ByteString(), RFC822Name("a@example.com"), |
2393 | | GeneralSubtree(RFC822Name("@example.com")), |
2394 | | Result::ERROR_BAD_DER, |
2395 | | Result::ERROR_BAD_DER |
2396 | | }, |
2397 | | { ByteString(), RFC822Name("@example.com"), |
2398 | | GeneralSubtree(RFC822Name("@example.com")), |
2399 | | Result::ERROR_BAD_DER, |
2400 | | Result::ERROR_BAD_DER |
2401 | | }, |
2402 | | { ByteString(), RFC822Name("example.com"), |
2403 | | GeneralSubtree(RFC822Name("@example.com")), |
2404 | | Result::ERROR_BAD_DER, |
2405 | | Result::ERROR_BAD_DER |
2406 | | }, |
2407 | | { ByteString(), RFC822Name("a@mail.example.com"), |
2408 | | GeneralSubtree(RFC822Name("a@*.example.com")), |
2409 | | Result::ERROR_BAD_DER, |
2410 | | Result::ERROR_BAD_DER |
2411 | | }, |
2412 | | { ByteString(), RFC822Name("a@*.example.com"), |
2413 | | GeneralSubtree(RFC822Name(".example.com")), |
2414 | | Result::ERROR_BAD_DER, |
2415 | | Result::ERROR_BAD_DER |
2416 | | }, |
2417 | | { ByteString(), RFC822Name("@example.com"), |
2418 | | GeneralSubtree(RFC822Name(".example.com")), |
2419 | | Result::ERROR_BAD_DER, |
2420 | | Result::ERROR_BAD_DER |
2421 | | }, |
2422 | | { ByteString(), RFC822Name("@a.example.com"), |
2423 | | GeneralSubtree(RFC822Name(".example.com")), |
2424 | | Result::ERROR_BAD_DER, |
2425 | | Result::ERROR_BAD_DER |
2426 | | }, |
2427 | | |
2428 | | ///////////////////////////////////////////////////////////////////////////// |
2429 | | // Test name constraints with underscores. |
2430 | | // |
2431 | | { ByteString(), DNSName("uses_underscore.example.com"), |
2432 | | GeneralSubtree(DNSName("uses_underscore.example.com")), |
2433 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2434 | | }, |
2435 | | { ByteString(), DNSName("uses_underscore.example.com"), |
2436 | | GeneralSubtree(DNSName("example.com")), |
2437 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2438 | | }, |
2439 | | { ByteString(), DNSName("a.uses_underscore.example.com"), |
2440 | | GeneralSubtree(DNSName("uses_underscore.example.com")), |
2441 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2442 | | }, |
2443 | | { ByteString(), RFC822Name("a@uses_underscore.example.com"), |
2444 | | GeneralSubtree(RFC822Name("uses_underscore.example.com")), |
2445 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2446 | | }, |
2447 | | { ByteString(), RFC822Name("uses_underscore@example.com"), |
2448 | | GeneralSubtree(RFC822Name("example.com")), |
2449 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2450 | | }, |
2451 | | { ByteString(), RFC822Name("a@a.uses_underscore.example.com"), |
2452 | | GeneralSubtree(RFC822Name(".uses_underscore.example.com")), |
2453 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2454 | | }, |
2455 | | |
2456 | | ///////////////////////////////////////////////////////////////////////////// |
2457 | | // Name constraint tests that relate to having an empty SAN. According to RFC |
2458 | | // 5280 this isn't valid, but we allow it for compatibility reasons (see bug |
2459 | | // 1143085). |
2460 | | { // For DNSNames, we fall back to the subject CN. |
2461 | | RDN(CN("a.example.com")), ByteString(), |
2462 | | GeneralSubtree(DNSName("a.example.com")), |
2463 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2464 | | }, |
2465 | | { // For RFC822Names, we do not fall back to the subject emailAddress. |
2466 | | // This new implementation seems to conform better to the standards for |
2467 | | // RFC822 name constraints, by only applying the name constraints to |
2468 | | // emailAddress names in the certificate subject if there is no |
2469 | | // subjectAltName extension in the cert. |
2470 | | // In this case, the presence of the (empty) SAN extension means that RFC822 |
2471 | | // name constraints are not enforced on the emailAddress attributes of the |
2472 | | // subject. |
2473 | | RDN(emailAddress("a@example.com")), ByteString(), |
2474 | | GeneralSubtree(RFC822Name("a@example.com")), |
2475 | | Success, Success |
2476 | | }, |
2477 | | { // Compare this to the case where there is no SAN (i.e. the name |
2478 | | // constraints are enforced, because the extension is not present at all). |
2479 | | RDN(emailAddress("a@example.com")), NO_SAN, |
2480 | | GeneralSubtree(RFC822Name("a@example.com")), |
2481 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2482 | | }, |
2483 | | |
2484 | | ///////////////////////////////////////////////////////////////////////////// |
2485 | | // DirectoryName name constraint tests |
2486 | | |
2487 | | { // One AVA per RDN |
2488 | | RDN(OU("Example Organization")) + RDN(CN("example.com")), NO_SAN, |
2489 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization")) + |
2490 | | RDN(CN("example.com"))))), |
2491 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2492 | | }, |
2493 | | { // RDNs can have multiple AVAs. |
2494 | | RDN(OU("Example Organization") + CN("example.com")), NO_SAN, |
2495 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization") + |
2496 | | CN("example.com"))))), |
2497 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2498 | | }, |
2499 | | { // The constraint is a prefix of the subject DN. |
2500 | | RDN(OU("Example Organization")) + RDN(CN("example.com")), NO_SAN, |
2501 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))), |
2502 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2503 | | }, |
2504 | | { // The name constraint is not a prefix of the subject DN. |
2505 | | // Note that for excludedSubtrees, we simply prohibit any non-empty |
2506 | | // directoryName constraint to ensure we are not being too lenient. |
2507 | | RDN(OU("Other Example Organization")) + RDN(CN("example.com")), NO_SAN, |
2508 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization")) + |
2509 | | RDN(CN("example.com"))))), |
2510 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2511 | | }, |
2512 | | { // Same as the previous one, but one RDN with multiple AVAs. |
2513 | | RDN(OU("Other Example Organization") + CN("example.com")), NO_SAN, |
2514 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization") + |
2515 | | CN("example.com"))))), |
2516 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2517 | | }, |
2518 | | { // With multiple AVAs per RDN in the subject DN, the constraint is not a |
2519 | | // prefix of the subject DN. |
2520 | | RDN(OU("Example Organization") + CN("example.com")), NO_SAN, |
2521 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))), |
2522 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2523 | | }, |
2524 | | { // The subject DN RDN has multiple AVAs, but the name constraint has only |
2525 | | // one AVA per RDN. |
2526 | | RDN(OU("Example Organization") + CN("example.com")), NO_SAN, |
2527 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization")) + |
2528 | | RDN(CN("example.com"))))), |
2529 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2530 | | }, |
2531 | | { // The name constraint RDN has multiple AVAs, but the subject DN has only |
2532 | | // one AVA per RDN. |
2533 | | RDN(OU("Example Organization")) + RDN(CN("example.com")), NO_SAN, |
2534 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization") + |
2535 | | CN("example.com"))))), |
2536 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2537 | | }, |
2538 | | { // In this case, the constraint uses a different encoding from the subject. |
2539 | | // We consider them to match because we allow UTF8String and |
2540 | | // PrintableString to compare equal when their contents are equal. |
2541 | | RDN(OU("Example Organization", der::UTF8String)) + RDN(CN("example.com")), |
2542 | | NO_SAN, GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization", |
2543 | | der::PrintableString)) + |
2544 | | RDN(CN("example.com"))))), |
2545 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2546 | | }, |
2547 | | { // Same as above, but with UTF8String/PrintableString switched. |
2548 | | RDN(OU("Example Organization", der::PrintableString)) + RDN(CN("example.com")), |
2549 | | NO_SAN, GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization", |
2550 | | der::UTF8String)) + |
2551 | | RDN(CN("example.com"))))), |
2552 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2553 | | }, |
2554 | | { // If the contents aren't the same, then they shouldn't match. |
2555 | | RDN(OU("Other Example Organization", der::UTF8String)) + RDN(CN("example.com")), |
2556 | | NO_SAN, GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization", |
2557 | | der::PrintableString)) + |
2558 | | RDN(CN("example.com"))))), |
2559 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2560 | | }, |
2561 | | { // Only UTF8String and PrintableString are considered equivalent. |
2562 | | RDN(OU("Example Organization", der::PrintableString)) + RDN(CN("example.com")), |
2563 | | NO_SAN, GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization", |
2564 | | der::TeletexString)) + |
2565 | | RDN(CN("example.com"))))), |
2566 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2567 | | }, |
2568 | | // Some additional tests for completeness: |
2569 | | // Ensure that wildcards are handled: |
2570 | | { RDN(CN("*.example.com")), NO_SAN, GeneralSubtree(DNSName("example.com")), |
2571 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2572 | | }, |
2573 | | { ByteString(), DNSName("*.example.com"), |
2574 | | GeneralSubtree(DNSName("example.com")), |
2575 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2576 | | }, |
2577 | | { ByteString(), DNSName("www.example.com"), |
2578 | | GeneralSubtree(DNSName("*.example.com")), |
2579 | | Result::ERROR_BAD_DER, Result::ERROR_BAD_DER |
2580 | | }, |
2581 | | // Handle multiple name constraint entries: |
2582 | | { RDN(CN("example.com")), NO_SAN, |
2583 | | GeneralSubtree(DNSName("example.org")) + |
2584 | | GeneralSubtree(DNSName("example.com")), |
2585 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2586 | | }, |
2587 | | { ByteString(), DNSName("example.com"), |
2588 | | GeneralSubtree(DNSName("example.org")) + |
2589 | | GeneralSubtree(DNSName("example.com")), |
2590 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2591 | | }, |
2592 | | // Handle multiple names in subject alternative name extension: |
2593 | | { ByteString(), DNSName("example.com") + DNSName("example.org"), |
2594 | | GeneralSubtree(DNSName("example.com")), |
2595 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2596 | | }, |
2597 | | // Handle a mix of DNSName and DirectoryName: |
2598 | | { RDN(OU("Example Organization")), DNSName("example.com"), |
2599 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))) + |
2600 | | GeneralSubtree(DNSName("example.com")), |
2601 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2602 | | }, |
2603 | | { RDN(OU("Other Example Organization")), DNSName("example.com"), |
2604 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))) + |
2605 | | GeneralSubtree(DNSName("example.com")), |
2606 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2607 | | }, |
2608 | | { RDN(OU("Example Organization")), DNSName("example.org"), |
2609 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))) + |
2610 | | GeneralSubtree(DNSName("example.com")), |
2611 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2612 | | }, |
2613 | | // Handle a certificate with no DirectoryName: |
2614 | | { ByteString(), DNSName("example.com"), |
2615 | | GeneralSubtree(DirectoryName(Name(RDN(OU("Example Organization"))))), |
2616 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2617 | | }, |
2618 | | }; |
2619 | | |
2620 | | class pkixnames_CheckNameConstraints |
2621 | | : public ::testing::Test |
2622 | | , public ::testing::WithParamInterface<NameConstraintParams> |
2623 | | { |
2624 | | public: |
2625 | | DefaultNameMatchingPolicy mNameMatchingPolicy; |
2626 | | }; |
2627 | | |
2628 | | TEST_P(pkixnames_CheckNameConstraints, |
2629 | | NameConstraintsEnforcedForDirectlyIssuedEndEntity) |
2630 | 0 | { |
2631 | 0 | // Test that name constraints are enforced on a certificate directly issued by |
2632 | 0 | // a certificate with the given name constraints. |
2633 | 0 |
|
2634 | 0 | const NameConstraintParams& param(GetParam()); |
2635 | 0 |
|
2636 | 0 | ByteString certDER(CreateCert(param.subject, param.subjectAltName)); |
2637 | 0 | ASSERT_FALSE(ENCODING_FAILED(certDER)); |
2638 | 0 | Input certInput; |
2639 | 0 | ASSERT_EQ(Success, certInput.Init(certDER.data(), certDER.length())); |
2640 | 0 | BackCert cert(certInput, EndEntityOrCA::MustBeEndEntity, nullptr); |
2641 | 0 | ASSERT_EQ(Success, cert.Init()); |
2642 | 0 |
|
2643 | 0 | { |
2644 | 0 | ByteString nameConstraintsDER(TLV(der::SEQUENCE, |
2645 | 0 | PermittedSubtrees(param.subtrees))); |
2646 | 0 | Input nameConstraints; |
2647 | 0 | ASSERT_EQ(Success, |
2648 | 0 | nameConstraints.Init(nameConstraintsDER.data(), |
2649 | 0 | nameConstraintsDER.length())); |
2650 | 0 | ASSERT_EQ(param.expectedPermittedSubtreesResult, |
2651 | 0 | CheckNameConstraints(nameConstraints, cert, |
2652 | 0 | KeyPurposeId::id_kp_serverAuth)); |
2653 | 0 | } |
2654 | 0 | { |
2655 | 0 | ByteString nameConstraintsDER(TLV(der::SEQUENCE, |
2656 | 0 | ExcludedSubtrees(param.subtrees))); |
2657 | 0 | Input nameConstraints; |
2658 | 0 | ASSERT_EQ(Success, |
2659 | 0 | nameConstraints.Init(nameConstraintsDER.data(), |
2660 | 0 | nameConstraintsDER.length())); |
2661 | 0 | ASSERT_EQ(param.expectedExcludedSubtreesResult, |
2662 | 0 | CheckNameConstraints(nameConstraints, cert, |
2663 | 0 | KeyPurposeId::id_kp_serverAuth)); |
2664 | 0 | } |
2665 | 0 | { |
2666 | 0 | ByteString nameConstraintsDER(TLV(der::SEQUENCE, |
2667 | 0 | PermittedSubtrees(param.subtrees) + |
2668 | 0 | ExcludedSubtrees(param.subtrees))); |
2669 | 0 | Input nameConstraints; |
2670 | 0 | ASSERT_EQ(Success, |
2671 | 0 | nameConstraints.Init(nameConstraintsDER.data(), |
2672 | 0 | nameConstraintsDER.length())); |
2673 | 0 | ASSERT_EQ((param.expectedPermittedSubtreesResult == |
2674 | 0 | param.expectedExcludedSubtreesResult) |
2675 | 0 | ? param.expectedExcludedSubtreesResult |
2676 | 0 | : Result::ERROR_CERT_NOT_IN_NAME_SPACE, |
2677 | 0 | CheckNameConstraints(nameConstraints, cert, |
2678 | 0 | KeyPurposeId::id_kp_serverAuth)); |
2679 | 0 | } |
2680 | 0 | } |
2681 | | |
2682 | | INSTANTIATE_TEST_CASE_P(pkixnames_CheckNameConstraints, |
2683 | | pkixnames_CheckNameConstraints, |
2684 | | testing::ValuesIn(NAME_CONSTRAINT_PARAMS)); |
2685 | | |
2686 | | // The |subjectAltName| param is not used for these test cases (hence the use of |
2687 | | // "NO_SAN"). |
2688 | | static const NameConstraintParams NO_FALLBACK_NAME_CONSTRAINT_PARAMS[] = |
2689 | | { |
2690 | | // The only difference between end-entities being verified for serverAuth and |
2691 | | // intermediates or end-entities being verified for other uses is that for |
2692 | | // the latter cases, there is no fallback matching of DNSName entries to the |
2693 | | // subject common name. |
2694 | | { RDN(CN("Not a DNSName")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2695 | | Success, Success |
2696 | | }, |
2697 | | { RDN(CN("a.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2698 | | Success, Success |
2699 | | }, |
2700 | | { RDN(CN("b.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")), |
2701 | | Success, Success |
2702 | | }, |
2703 | | // Sanity-check that name constraints are in fact enforced in these cases. |
2704 | | { RDN(CN("Example Name")), NO_SAN, |
2705 | | GeneralSubtree(DirectoryName(Name(RDN(CN("Example Name"))))), |
2706 | | Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2707 | | }, |
2708 | | // (In this implementation, if a DirectoryName is in excludedSubtrees, nothing |
2709 | | // is considered to be in the name space.) |
2710 | | { RDN(CN("Other Example Name")), NO_SAN, |
2711 | | GeneralSubtree(DirectoryName(Name(RDN(CN("Example Name"))))), |
2712 | | Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE |
2713 | | }, |
2714 | | }; |
2715 | | |
2716 | | class pkixnames_CheckNameConstraintsOnIntermediate |
2717 | | : public ::testing::Test |
2718 | | , public ::testing::WithParamInterface<NameConstraintParams> |
2719 | | { |
2720 | | }; |
2721 | | |
2722 | | TEST_P(pkixnames_CheckNameConstraintsOnIntermediate, |
2723 | | NameConstraintsEnforcedOnIntermediate) |
2724 | 0 | { |
2725 | 0 | // Test that name constraints are enforced on an intermediate certificate |
2726 | 0 | // directly issued by a certificate with the given name constraints. |
2727 | 0 |
|
2728 | 0 | const NameConstraintParams& param(GetParam()); |
2729 | 0 |
|
2730 | 0 | ByteString certDER(CreateCert(param.subject, NO_SAN, |
2731 | 0 | EndEntityOrCA::MustBeCA)); |
2732 | 0 | ASSERT_FALSE(ENCODING_FAILED(certDER)); |
2733 | 0 | Input certInput; |
2734 | 0 | ASSERT_EQ(Success, certInput.Init(certDER.data(), certDER.length())); |
2735 | 0 | BackCert cert(certInput, EndEntityOrCA::MustBeCA, nullptr); |
2736 | 0 | ASSERT_EQ(Success, cert.Init()); |
2737 | 0 |
|
2738 | 0 | { |
2739 | 0 | ByteString nameConstraintsDER(TLV(der::SEQUENCE, |
2740 | 0 | PermittedSubtrees(param.subtrees))); |
2741 | 0 | Input nameConstraints; |
2742 | 0 | ASSERT_EQ(Success, |
2743 | 0 | nameConstraints.Init(nameConstraintsDER.data(), |
2744 | 0 | nameConstraintsDER.length())); |
2745 | 0 | ASSERT_EQ(param.expectedPermittedSubtreesResult, |
2746 | 0 | CheckNameConstraints(nameConstraints, cert, |
2747 | 0 | KeyPurposeId::id_kp_serverAuth)); |
2748 | 0 | } |
2749 | 0 | { |
2750 | 0 | ByteString nameConstraintsDER(TLV(der::SEQUENCE, |
2751 | 0 | ExcludedSubtrees(param.subtrees))); |
2752 | 0 | Input nameConstraints; |
2753 | 0 | ASSERT_EQ(Success, |
2754 | 0 | nameConstraints.Init(nameConstraintsDER.data(), |
2755 | 0 | nameConstraintsDER.length())); |
2756 | 0 | ASSERT_EQ(param.expectedExcludedSubtreesResult, |
2757 | 0 | CheckNameConstraints(nameConstraints, cert, |
2758 | 0 | KeyPurposeId::id_kp_serverAuth)); |
2759 | 0 | } |
2760 | 0 | { |
2761 | 0 | ByteString nameConstraintsDER(TLV(der::SEQUENCE, |
2762 | 0 | PermittedSubtrees(param.subtrees) + |
2763 | 0 | ExcludedSubtrees(param.subtrees))); |
2764 | 0 | Input nameConstraints; |
2765 | 0 | ASSERT_EQ(Success, |
2766 | 0 | nameConstraints.Init(nameConstraintsDER.data(), |
2767 | 0 | nameConstraintsDER.length())); |
2768 | 0 | ASSERT_EQ(param.expectedExcludedSubtreesResult, |
2769 | 0 | CheckNameConstraints(nameConstraints, cert, |
2770 | 0 | KeyPurposeId::id_kp_serverAuth)); |
2771 | 0 | } |
2772 | 0 | } |
2773 | | |
2774 | | INSTANTIATE_TEST_CASE_P(pkixnames_CheckNameConstraintsOnIntermediate, |
2775 | | pkixnames_CheckNameConstraintsOnIntermediate, |
2776 | | testing::ValuesIn(NO_FALLBACK_NAME_CONSTRAINT_PARAMS)); |
2777 | | |
2778 | | class pkixnames_CheckNameConstraintsForNonServerAuthUsage |
2779 | | : public ::testing::Test |
2780 | | , public ::testing::WithParamInterface<NameConstraintParams> |
2781 | | { |
2782 | | }; |
2783 | | |
2784 | | TEST_P(pkixnames_CheckNameConstraintsForNonServerAuthUsage, |
2785 | | NameConstraintsEnforcedForNonServerAuthUsage) |
2786 | 0 | { |
2787 | 0 | // Test that for key purposes other than serverAuth, fallback to the subject |
2788 | 0 | // common name does not occur. |
2789 | 0 |
|
2790 | 0 | const NameConstraintParams& param(GetParam()); |
2791 | 0 |
|
2792 | 0 | ByteString certDER(CreateCert(param.subject, NO_SAN)); |
2793 | 0 | ASSERT_FALSE(ENCODING_FAILED(certDER)); |
2794 | 0 | Input certInput; |
2795 | 0 | ASSERT_EQ(Success, certInput.Init(certDER.data(), certDER.length())); |
2796 | 0 | BackCert cert(certInput, EndEntityOrCA::MustBeEndEntity, nullptr); |
2797 | 0 | ASSERT_EQ(Success, cert.Init()); |
2798 | 0 |
|
2799 | 0 | { |
2800 | 0 | ByteString nameConstraintsDER(TLV(der::SEQUENCE, |
2801 | 0 | PermittedSubtrees(param.subtrees))); |
2802 | 0 | Input nameConstraints; |
2803 | 0 | ASSERT_EQ(Success, |
2804 | 0 | nameConstraints.Init(nameConstraintsDER.data(), |
2805 | 0 | nameConstraintsDER.length())); |
2806 | 0 | ASSERT_EQ(param.expectedPermittedSubtreesResult, |
2807 | 0 | CheckNameConstraints(nameConstraints, cert, |
2808 | 0 | KeyPurposeId::id_kp_clientAuth)); |
2809 | 0 | } |
2810 | 0 | { |
2811 | 0 | ByteString nameConstraintsDER(TLV(der::SEQUENCE, |
2812 | 0 | ExcludedSubtrees(param.subtrees))); |
2813 | 0 | Input nameConstraints; |
2814 | 0 | ASSERT_EQ(Success, |
2815 | 0 | nameConstraints.Init(nameConstraintsDER.data(), |
2816 | 0 | nameConstraintsDER.length())); |
2817 | 0 | ASSERT_EQ(param.expectedExcludedSubtreesResult, |
2818 | 0 | CheckNameConstraints(nameConstraints, cert, |
2819 | 0 | KeyPurposeId::id_kp_clientAuth)); |
2820 | 0 | } |
2821 | 0 | { |
2822 | 0 | ByteString nameConstraintsDER(TLV(der::SEQUENCE, |
2823 | 0 | PermittedSubtrees(param.subtrees) + |
2824 | 0 | ExcludedSubtrees(param.subtrees))); |
2825 | 0 | Input nameConstraints; |
2826 | 0 | ASSERT_EQ(Success, |
2827 | 0 | nameConstraints.Init(nameConstraintsDER.data(), |
2828 | 0 | nameConstraintsDER.length())); |
2829 | 0 | ASSERT_EQ(param.expectedExcludedSubtreesResult, |
2830 | 0 | CheckNameConstraints(nameConstraints, cert, |
2831 | 0 | KeyPurposeId::id_kp_clientAuth)); |
2832 | 0 | } |
2833 | 0 | } |
2834 | | |
2835 | | INSTANTIATE_TEST_CASE_P(pkixnames_CheckNameConstraintsForNonServerAuthUsage, |
2836 | | pkixnames_CheckNameConstraintsForNonServerAuthUsage, |
2837 | | testing::ValuesIn(NO_FALLBACK_NAME_CONSTRAINT_PARAMS)); |