1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.conn.ssl;
29
30 import java.io.ByteArrayInputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.InputStreamReader;
34 import java.nio.charset.Charset;
35 import java.security.cert.CertificateFactory;
36 import java.security.cert.X509Certificate;
37 import java.util.Arrays;
38 import java.util.Collections;
39 import java.util.List;
40
41 import javax.net.ssl.SSLException;
42
43 import org.apache.http.conn.util.DomainType;
44 import org.apache.http.conn.util.PublicSuffixList;
45 import org.apache.http.conn.util.PublicSuffixListParser;
46 import org.apache.http.conn.util.PublicSuffixMatcher;
47 import org.junit.Assert;
48 import org.junit.Before;
49 import org.junit.Test;
50
51
52
53
54 public class TestDefaultHostnameVerifier {
55
56 private DefaultHostnameVerifier impl;
57 private PublicSuffixMatcher publicSuffixMatcher;
58 private DefaultHostnameVerifier implWithPublicSuffixCheck;
59
60 private static final String PUBLIC_SUFFIX_MATCHER_SOURCE_FILE = "suffixlistmatcher.txt";
61
62 private static final Charset UTF_8 = Charset.forName("UTF-8");
63
64 @Before
65 public void setup() throws IOException {
66 impl = new DefaultHostnameVerifier();
67
68
69 final ClassLoader classLoader = getClass().getClassLoader();
70 final InputStream in = classLoader.getResourceAsStream(PUBLIC_SUFFIX_MATCHER_SOURCE_FILE);
71 Assert.assertNotNull(in);
72 final List<PublicSuffixList> lists = new PublicSuffixListParser().parseByType(
73 new InputStreamReader(in, UTF_8));
74 publicSuffixMatcher = new PublicSuffixMatcher(lists);
75
76 implWithPublicSuffixCheck = new DefaultHostnameVerifier(publicSuffixMatcher);
77 }
78
79 @Test
80 public void testVerify() throws Exception {
81 final CertificateFactory cf = CertificateFactory.getInstance("X.509");
82 InputStream in;
83 X509Certificate x509;
84 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO);
85 x509 = (X509Certificate) cf.generateCertificate(in);
86
87 impl.verify("foo.com", x509);
88 exceptionPlease(impl, "a.foo.com", x509);
89 exceptionPlease(impl, "bar.com", x509);
90
91 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_HANAKO);
92 x509 = (X509Certificate) cf.generateCertificate(in);
93 impl.verify("\u82b1\u5b50.co.jp", x509);
94 exceptionPlease(impl, "a.\u82b1\u5b50.co.jp", x509);
95
96 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO_BAR);
97 x509 = (X509Certificate) cf.generateCertificate(in);
98 exceptionPlease(impl, "foo.com", x509);
99 exceptionPlease(impl, "a.foo.com", x509);
100 impl.verify("bar.com", x509);
101 exceptionPlease(impl, "a.bar.com", x509);
102
103 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO_BAR_HANAKO);
104 x509 = (X509Certificate) cf.generateCertificate(in);
105 exceptionPlease(impl, "foo.com", x509);
106 exceptionPlease(impl, "a.foo.com", x509);
107 impl.verify("bar.com", x509);
108 exceptionPlease(impl, "a.bar.com", x509);
109
110
111
112
113
114
115
116 exceptionPlease(impl, "a.\u82b1\u5b50.co.jp", x509);
117
118 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_NO_CNS_FOO);
119 x509 = (X509Certificate) cf.generateCertificate(in);
120 impl.verify("foo.com", x509);
121 exceptionPlease(impl, "a.foo.com", x509);
122
123 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_NO_CNS_FOO);
124 x509 = (X509Certificate) cf.generateCertificate(in);
125 impl.verify("foo.com", x509);
126 exceptionPlease(impl, "a.foo.com", x509);
127
128 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_THREE_CNS_FOO_BAR_HANAKO);
129 x509 = (X509Certificate) cf.generateCertificate(in);
130 exceptionPlease(impl, "foo.com", x509);
131 exceptionPlease(impl, "a.foo.com", x509);
132 exceptionPlease(impl, "bar.com", x509);
133 exceptionPlease(impl, "a.bar.com", x509);
134 impl.verify("\u82b1\u5b50.co.jp", x509);
135 exceptionPlease(impl, "a.\u82b1\u5b50.co.jp", x509);
136
137 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_FOO);
138 x509 = (X509Certificate) cf.generateCertificate(in);
139 exceptionPlease(impl, "foo.com", x509);
140 impl.verify("www.foo.com", x509);
141 impl.verify("\u82b1\u5b50.foo.com", x509);
142 exceptionPlease(impl, "a.b.foo.com", x509);
143
144 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_CO_JP);
145 x509 = (X509Certificate) cf.generateCertificate(in);
146
147
148 impl.verify("*.co.jp", x509);
149 impl.verify("foo.co.jp", x509);
150 impl.verify("\u82b1\u5b50.co.jp", x509);
151
152 exceptionPlease(implWithPublicSuffixCheck, "foo.co.jp", x509);
153 exceptionPlease(implWithPublicSuffixCheck, "\u82b1\u5b50.co.jp", x509);
154
155 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_FOO_BAR_HANAKO);
156 x509 = (X509Certificate) cf.generateCertificate(in);
157
158 exceptionPlease(impl, "foo.com", x509);
159 exceptionPlease(impl, "www.foo.com", x509);
160 exceptionPlease(impl, "\u82b1\u5b50.foo.com", x509);
161 exceptionPlease(impl, "a.b.foo.com", x509);
162
163 exceptionPlease(impl, "bar.com", x509);
164 impl.verify("www.bar.com", x509);
165 impl.verify("\u82b1\u5b50.bar.com", x509);
166 exceptionPlease(impl, "a.b.bar.com", x509);
167
168 in = new ByteArrayInputStream(CertificatesToPlayWith.X509_MULTIPLE_VALUE_AVA);
169 x509 = (X509Certificate) cf.generateCertificate(in);
170 impl.verify("repository.infonotary.com", x509);
171
172 in = new ByteArrayInputStream(CertificatesToPlayWith.S_GOOGLE_COM);
173 x509 = (X509Certificate) cf.generateCertificate(in);
174 impl.verify("*.google.com", x509);
175
176 in = new ByteArrayInputStream(CertificatesToPlayWith.S_GOOGLE_COM);
177 x509 = (X509Certificate) cf.generateCertificate(in);
178 impl.verify("*.Google.com", x509);
179
180 in = new ByteArrayInputStream(CertificatesToPlayWith.IP_1_1_1_1);
181 x509 = (X509Certificate) cf.generateCertificate(in);
182 impl.verify("1.1.1.1", x509);
183
184 exceptionPlease(impl, "1.1.1.2", x509);
185 exceptionPlease(impl, "dummy-value.com", x509);
186
187 in = new ByteArrayInputStream(CertificatesToPlayWith.EMAIL_ALT_SUBJECT_NAME);
188 x509 = (X509Certificate) cf.generateCertificate(in);
189 impl.verify("www.company.com", x509);
190 }
191
192 @Test
193 public void testSubjectAlt() throws Exception {
194 final CertificateFactory cf = CertificateFactory.getInstance("X.509");
195 final InputStream in = new ByteArrayInputStream(CertificatesToPlayWith.X509_MULTIPLE_SUBJECT_ALT);
196 final X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
197
198 Assert.assertEquals("CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=CH",
199 x509.getSubjectDN().getName());
200
201 impl.verify("localhost.localdomain", x509);
202 impl.verify("127.0.0.1", x509);
203
204 try {
205 impl.verify("localhost", x509);
206 Assert.fail("SSLException should have been thrown");
207 } catch (final SSLException ex) {
208
209 }
210 try {
211 impl.verify("local.host", x509);
212 Assert.fail("SSLException should have been thrown");
213 } catch (final SSLException ex) {
214
215 }
216 try {
217 impl.verify("127.0.0.2", x509);
218 Assert.fail("SSLException should have been thrown");
219 } catch (final SSLException ex) {
220
221 }
222 }
223
224 public void exceptionPlease(final DefaultHostnameVerifier hv, final String host,
225 final X509Certificate x509) {
226 try {
227 hv.verify(host, x509);
228 Assert.fail("HostnameVerifier shouldn't allow [" + host + "]");
229 }
230 catch(final SSLException e) {
231
232 }
233 }
234
235 @Test
236 public void testDomainRootMatching() {
237
238 Assert.assertFalse(DefaultHostnameVerifier.matchDomainRoot("a.b.c", null));
239 Assert.assertTrue(DefaultHostnameVerifier.matchDomainRoot("a.b.c", "a.b.c"));
240 Assert.assertFalse(DefaultHostnameVerifier.matchDomainRoot("aa.b.c", "a.b.c"));
241 Assert.assertFalse(DefaultHostnameVerifier.matchDomainRoot("a.b.c", "aa.b.c"));
242 Assert.assertTrue(DefaultHostnameVerifier.matchDomainRoot("a.a.b.c", "a.b.c"));
243 }
244
245 @Test
246 public void testIdentityMatching() {
247
248 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.b.c", "*.b.c"));
249 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "*.b.c"));
250
251 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.b.c", "*.b.c"));
252 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.b.c", "*.b.c"));
253
254 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("a.gov.uk", "*.gov.uk", publicSuffixMatcher));
255 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.gov.uk", "*.gov.uk", publicSuffixMatcher));
256
257 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.gov.uk", "*.a.gov.uk", publicSuffixMatcher));
258 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.uk", "*.a.gov.uk", publicSuffixMatcher));
259
260 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("s.a.gov.uk", "*.gov.uk", publicSuffixMatcher));
261 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.uk", "*.gov.uk", publicSuffixMatcher));
262
263 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.gov.com", "*.gov.com", publicSuffixMatcher));
264 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.gov.com", "*.gov.com", publicSuffixMatcher));
265
266 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.gov.com", "*.gov.com", publicSuffixMatcher));
267 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.com", "*.gov.com", publicSuffixMatcher));
268
269 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("a.gov.uk", "a*.gov.uk", publicSuffixMatcher));
270 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.gov.uk", "a*.gov.uk", publicSuffixMatcher));
271
272 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("s.a.gov.uk", "a*.gov.uk", publicSuffixMatcher));
273 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.uk", "a*.gov.uk", publicSuffixMatcher));
274
275 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("a.b.c", "*.b.*"));
276 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "*.b.*"));
277
278 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("a.b.c", "*.*.c"));
279 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "*.*.c"));
280 }
281
282 @Test
283 public void testHTTPCLIENT_1097() {
284 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.b.c", "a*.b.c"));
285 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "a*.b.c"));
286
287 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.a.b.c", "a*.b.c"));
288 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.a.b.c", "a*.b.c"));
289 }
290
291 @Test
292 public void testHTTPCLIENT_1255() {
293 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("mail.a.b.c.com", "m*.a.b.c.com"));
294 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("mail.a.b.c.com", "m*.a.b.c.com"));
295 }
296
297
298 @Test
299 public void testHTTPCLIENT_1997_ANY() {
300 String domain;
301
302 domain = "dev.b.cloud.a";
303 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain));
304 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain));
305 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher));
306 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher));
307
308
309 domain = "dev.b.cloud.com";
310 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain));
311 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain));
312 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher));
313 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher));
314
315
316 domain = "dev.b.cloud.lan";
317 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain));
318 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain));
319 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher));
320 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher));
321 }
322
323 @Test
324 public void testHTTPCLIENT_1997_ICANN() {
325 String domain;
326
327 domain = "dev.b.cloud.a";
328 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.ICANN));
329 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.ICANN));
330
331
332 domain = "dev.b.cloud.com";
333 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.ICANN));
334 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.ICANN));
335
336
337 domain = "dev.b.cloud.lan";
338 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.ICANN));
339 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.ICANN));
340 }
341
342 @Test
343 public void testHTTPCLIENT_1997_PRIVATE() {
344 String domain;
345
346 domain = "dev.b.cloud.a";
347 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.PRIVATE));
348 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.PRIVATE));
349
350
351 domain = "dev.b.cloud.com";
352 Assert.assertFalse(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.PRIVATE));
353 Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.PRIVATE));
354
355
356 domain = "dev.b.cloud.lan";
357 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.PRIVATE));
358 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.PRIVATE));
359 }
360
361 @Test
362 public void testHTTPCLIENT_1997_UNKNOWN() {
363 String domain;
364
365 domain = "dev.b.cloud.a";
366 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.UNKNOWN));
367 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.UNKNOWN));
368
369
370 domain = "dev.b.cloud.com";
371 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.UNKNOWN));
372 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.UNKNOWN));
373
374
375 domain = "dev.b.cloud.lan";
376 Assert.assertTrue(DefaultHostnameVerifier.matchIdentity( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.UNKNOWN));
377 Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict( "service.apps." + domain, "*.apps." + domain, publicSuffixMatcher, DomainType.UNKNOWN));
378 }
379
380 @Test
381 public void testHTTPCLIENT_1316() throws Exception{
382 final String host1 = "2001:0db8:aaaa:bbbb:cccc:0:0:0001";
383 DefaultHostnameVerifier.matchIPv6Address(host1, Arrays.asList(SubjectName.IP("2001:0db8:aaaa:bbbb:cccc:0:0:0001")));
384 DefaultHostnameVerifier.matchIPv6Address(host1, Arrays.asList(SubjectName.IP("2001:0db8:aaaa:bbbb:cccc::1")));
385 try {
386 DefaultHostnameVerifier.matchIPv6Address(host1, Arrays.asList(SubjectName.IP("2001:0db8:aaaa:bbbb:cccc::10")));
387 Assert.fail("SSLException expected");
388 } catch (final SSLException expected) {
389 }
390 final String host2 = "2001:0db8:aaaa:bbbb:cccc::1";
391 DefaultHostnameVerifier.matchIPv6Address(host2, Arrays.asList(SubjectName.IP("2001:0db8:aaaa:bbbb:cccc:0:0:0001")));
392 DefaultHostnameVerifier.matchIPv6Address(host2, Arrays.asList(SubjectName.IP("2001:0db8:aaaa:bbbb:cccc::1")));
393 try {
394 DefaultHostnameVerifier.matchIPv6Address(host2, Arrays.asList(SubjectName.IP("2001:0db8:aaaa:bbbb:cccc::10")));
395 Assert.fail("SSLException expected");
396 } catch (final SSLException expected) {
397 }
398 }
399
400 @Test
401 public void testExtractCN() throws Exception {
402 Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=blah, ou=blah, o=blah"));
403 Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=blah, cn=yada, cn=booh"));
404 Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("c = pampa , cn = blah , ou = blah , o = blah"));
405 Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=\"blah\", ou=blah, o=blah"));
406 Assert.assertEquals("blah blah", DefaultHostnameVerifier.extractCN("cn=\"blah blah\", ou=blah, o=blah"));
407 Assert.assertEquals("blah, blah", DefaultHostnameVerifier.extractCN("cn=\"blah, blah\", ou=blah, o=blah"));
408 Assert.assertEquals("blah, blah", DefaultHostnameVerifier.extractCN("cn=blah\\, blah, ou=blah, o=blah"));
409 Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("c = cn=uuh, cn=blah, ou=blah, o=blah"));
410 try {
411 DefaultHostnameVerifier.extractCN("blah,blah");
412 Assert.fail("SSLException expected");
413 } catch (final SSLException expected) {
414 }
415 try {
416 DefaultHostnameVerifier.extractCN("cn,o=blah");
417 Assert.fail("SSLException expected");
418 } catch (final SSLException expected) {
419 }
420 }
421
422 @Test
423 public void testMatchDNSName() throws Exception {
424 DefaultHostnameVerifier.matchDNSName(
425 "host.domain.com",
426 Collections.singletonList(SubjectName.DNS("*.domain.com")),
427 publicSuffixMatcher);
428 DefaultHostnameVerifier.matchDNSName(
429 "host.xx",
430 Collections.singletonList(SubjectName.DNS("*.xx")),
431 publicSuffixMatcher);
432 DefaultHostnameVerifier.matchDNSName(
433 "host.appspot.com",
434 Collections.singletonList(SubjectName.DNS("*.appspot.com")),
435 publicSuffixMatcher);
436 DefaultHostnameVerifier.matchDNSName(
437 "demo-s3-bucket.s3.eu-central-1.amazonaws.com",
438 Collections.singletonList(SubjectName.DNS("*.s3.eu-central-1.amazonaws.com")),
439 publicSuffixMatcher);
440 DefaultHostnameVerifier.matchDNSName(
441 "hostname-workspace-1.local",
442 Collections.singletonList(SubjectName.DNS("hostname-workspace-1.local")),
443 publicSuffixMatcher);
444 }
445
446 }