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.hc.core5.ssl;
29
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.OutputStream;
33 import java.net.InetSocketAddress;
34 import java.net.ServerSocket;
35 import java.net.Socket;
36 import java.net.URL;
37 import java.security.KeyStore;
38 import java.security.KeyStoreException;
39 import java.security.NoSuchAlgorithmException;
40 import java.security.NoSuchProviderException;
41 import java.security.Principal;
42 import java.security.Security;
43 import java.security.UnrecoverableKeyException;
44 import java.security.cert.X509Certificate;
45 import java.util.Arrays;
46 import java.util.LinkedHashSet;
47 import java.util.Set;
48 import java.util.concurrent.ExecutorService;
49 import java.util.concurrent.Executors;
50 import java.util.concurrent.Future;
51 import java.util.concurrent.TimeUnit;
52 import java.util.concurrent.atomic.AtomicReference;
53
54 import javax.net.ssl.KeyManagerFactory;
55 import javax.net.ssl.SSLContext;
56 import javax.net.ssl.SSLException;
57 import javax.net.ssl.SSLPeerUnverifiedException;
58 import javax.net.ssl.SSLServerSocket;
59 import javax.net.ssl.SSLSession;
60 import javax.net.ssl.SSLSocket;
61 import javax.net.ssl.TrustManagerFactory;
62
63 import org.apache.hc.core5.util.Timeout;
64 import org.junit.jupiter.api.AfterEach;
65 import org.junit.jupiter.api.Assertions;
66 import org.junit.jupiter.api.Test;
67
68
69
70
71 public class TestSSLContextBuilder {
72
73 static final String PROVIDER_SUN_JSSE = "SunJSSE";
74 static final String PROVIDER_SUN_JCE = "SunJCE";
75
76 private static boolean isWindows() {
77 return System.getProperty("os.name").contains("Windows");
78 }
79
80 private static final Timeout TIMEOUT = Timeout.ofSeconds(5);
81 private ExecutorService executorService;
82
83 @AfterEach
84 public void cleanup() throws Exception {
85 if (this.executorService != null) {
86 this.executorService.shutdown();
87 this.executorService.awaitTermination(5, TimeUnit.SECONDS);
88 }
89 }
90
91 private URL getResource(final String name) {
92 return getClass().getResource(name);
93 }
94
95 @Test
96 public void testBuildAllDefaults() throws Exception {
97 final SSLContext sslContext = SSLContextBuilder.create()
98 .setKeyStoreType(KeyStore.getDefaultType())
99 .setKeyManagerFactoryAlgorithm(KeyManagerFactory.getDefaultAlgorithm())
100 .setTrustManagerFactoryAlgorithm(TrustManagerFactory.getDefaultAlgorithm())
101 .setProvider(PROVIDER_SUN_JSSE)
102 .setProtocol("TLS")
103 .setSecureRandom(null)
104 .loadTrustMaterial((KeyStore) null, null)
105 .loadKeyMaterial((KeyStore) null, null, null)
106 .build();
107 Assertions.assertNotNull(sslContext);
108 Assertions.assertEquals("TLS", sslContext.getProtocol());
109 Assertions.assertEquals(PROVIDER_SUN_JSSE, sslContext.getProvider().getName());
110 }
111
112 @Test
113 public void testBuildAllNull() throws Exception {
114 final SSLContext sslContext = SSLContextBuilder.create()
115 .setKeyStoreType(null)
116 .setKeyManagerFactoryAlgorithm(null)
117 .setTrustManagerFactoryAlgorithm(null)
118 .setProtocol(null)
119 .setProvider((String) null)
120 .setSecureRandom(null)
121 .loadTrustMaterial((KeyStore) null, null)
122 .loadKeyMaterial((KeyStore) null, null, null)
123 .build();
124 Assertions.assertNotNull(sslContext);
125 Assertions.assertEquals("TLS", sslContext.getProtocol());
126 Assertions.assertEquals(PROVIDER_SUN_JSSE, sslContext.getProvider().getName());
127 }
128
129 @Test
130 public void testBuildAllNull_deprecated() throws Exception {
131 final SSLContext sslContext = SSLContextBuilder.create()
132 .setProtocol(null)
133 .setSecureRandom(null)
134 .loadTrustMaterial((KeyStore) null, null)
135 .loadKeyMaterial((KeyStore) null, null, null)
136 .build();
137 Assertions.assertNotNull(sslContext);
138 Assertions.assertEquals("TLS", sslContext.getProtocol());
139 }
140
141 @Test
142 public void testBuildDefault() throws Exception {
143 new SSLContextBuilder().build();
144 }
145
146 @Test
147 public void testBuildNoSuchKeyManagerFactoryAlgorithm() throws Exception {
148 final URL resource1 = getResource("/test-keypasswd.p12");
149 final String storePassword = "nopassword";
150 final String keyPassword = "password";
151 Assertions.assertThrows(NoSuchAlgorithmException.class, () ->
152 SSLContextBuilder.create()
153 .setKeyManagerFactoryAlgorithm(" BAD ")
154 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
155 .build());
156 }
157
158 @Test
159 public void testBuildNoSuchKeyStoreType() throws Exception {
160 final URL resource1 = getResource("/test-keypasswd.p12");
161 final String storePassword = "nopassword";
162 final String keyPassword = "password";
163 Assertions.assertThrows(KeyStoreException.class, () ->
164 SSLContextBuilder.create()
165 .setKeyStoreType(" BAD ")
166 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
167 .build());
168 }
169
170 @Test
171 public void testBuildNoSuchTrustManagerFactoryAlgorithm() throws Exception {
172 final URL resource1 = getResource("/test-keypasswd.p12");
173 final String storePassword = "nopassword";
174 Assertions.assertThrows(NoSuchAlgorithmException.class, () ->
175 SSLContextBuilder.create()
176 .setTrustManagerFactoryAlgorithm(" BAD ")
177 .loadTrustMaterial(resource1, storePassword.toCharArray())
178 .build());
179 }
180
181 @Test
182 public void testBuildWithProvider() throws Exception {
183 final URL resource1 = getResource("/test-server.p12");
184 final String storePassword = "nopassword";
185 final String keyPassword = "nopassword";
186 final DummyProvider provider = new DummyProvider();
187 SSLContextBuilder.create()
188 .setProvider(provider)
189 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
190 .build();
191 Assertions.assertTrue(provider.hasBeenRequested("SSLContext"));
192 }
193
194 @Test
195 public void testBuildWithProviderName() throws Exception {
196
197 final DummyProvider provider = new DummyProvider();
198 Security.insertProviderAt(provider, 1);
199 try {
200
201 final URL resource1 = getResource("/test-server.p12");
202 final String storePassword = "nopassword";
203 final String keyPassword = "nopassword";
204 SSLContextBuilder.create()
205 .setProvider(DummyProvider.NAME)
206 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
207 .build();
208 Assertions.assertTrue(provider.hasBeenRequested("SSLContext"));
209
210 } finally {
211 Security.removeProvider(DummyProvider.NAME);
212 }
213 }
214
215 @Test
216 public void testBuildKSWithNoSuchProvider() {
217 Assertions.assertThrows(NoSuchProviderException.class,
218 () -> SSLContextBuilder.create()
219 .setKeyStoreProvider("no-such-provider")
220 .build());
221 }
222
223 @Test
224 public void testBuildKSWithProvider() throws Exception {
225 final URL resource1 = getResource("/test-server.p12");
226 final String storePassword = "nopassword";
227 final String keyPassword = "nopassword";
228 final DummyProvider provider = new DummyProvider();
229 SSLContextBuilder.create()
230 .setKeyStoreProvider(provider)
231 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
232 .build();
233 Assertions.assertTrue(provider.hasBeenRequested("KeyManagerFactory"));
234 }
235
236 @Test
237 public void testBuildKSWithProviderName() throws Exception {
238
239 final DummyProvider provider = new DummyProvider();
240 Security.insertProviderAt(provider, 1);
241 try {
242
243 final URL resource1 = getResource("/test-server.p12");
244 final String storePassword = "nopassword";
245 final String keyPassword = "nopassword";
246 SSLContextBuilder.create()
247 .setKeyStoreProvider(DummyProvider.NAME)
248 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
249 .build();
250 Assertions.assertTrue(provider.hasBeenRequested("KeyManagerFactory"));
251
252 } finally {
253 Security.removeProvider(DummyProvider.NAME);
254 }
255 }
256
257 @Test
258 public void testBuildTSWithNoSuchProvider() {
259 Assertions.assertThrows(NoSuchProviderException.class, ()->
260 SSLContextBuilder.create()
261 .setTrustStoreProvider("no-such-provider")
262 .build());
263 }
264
265 @Test
266 public void testBuildTSWithProvider() throws Exception {
267 final DummyProvider provider = new DummyProvider();
268 SSLContextBuilder.create()
269 .setTrustStoreProvider(provider)
270 .loadTrustMaterial((KeyStore) null, null)
271 .build();
272 Assertions.assertTrue(provider.hasBeenRequested("TrustManagerFactory"));
273 }
274
275 @Test
276 public void testBuildTSWithProviderName() throws Exception {
277
278 final DummyProvider provider = new DummyProvider();
279 Security.insertProviderAt(provider, 1);
280 try {
281
282 SSLContextBuilder.create()
283 .setTrustStoreProvider(DummyProvider.NAME)
284 .loadTrustMaterial((KeyStore) null, null)
285 .build();
286 Assertions.assertTrue(provider.hasBeenRequested("TrustManagerFactory"));
287
288 } finally {
289 Security.removeProvider(DummyProvider.NAME);
290 }
291 }
292
293
294 @Test
295 public void testKeyWithAlternatePasswordInvalid() throws Exception {
296 final URL resource1 = getResource("/test-keypasswd.p12");
297 final String storePassword = "nopassword";
298 final String keyPassword = "!password";
299 Assertions.assertThrows(UnrecoverableKeyException.class, () ->
300 SSLContextBuilder.create()
301 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
302 .loadTrustMaterial(resource1, storePassword.toCharArray())
303 .build());
304 }
305
306 @Test
307 public void testSSLHandshakeServerTrusted() throws Exception {
308 final URL resource1 = getResource("/test.p12");
309 final String storePassword = "nopassword";
310 final String keyPassword = "nopassword";
311 final SSLContext serverSslContext = SSLContextBuilder.create()
312 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
313 .build();
314 Assertions.assertNotNull(serverSslContext);
315 final SSLContext clientSslContext = SSLContextBuilder.create()
316 .loadTrustMaterial(resource1, storePassword.toCharArray())
317 .build();
318 Assertions.assertNotNull(clientSslContext);
319 final ServerSocket serverSocket = serverSslContext.getServerSocketFactory().createServerSocket();
320 serverSocket.bind(new InetSocketAddress(0));
321
322 this.executorService = Executors.newSingleThreadExecutor();
323 final Future<Boolean> future = this.executorService.submit(() -> {
324 try (Socket socket = serverSocket.accept()) {
325 final OutputStream outputStream = socket.getOutputStream();
326 outputStream.write(new byte[]{'H', 'i'});
327 outputStream.flush();
328 }
329 return Boolean.TRUE;
330 });
331
332 final int localPort = serverSocket.getLocalPort();
333 try (final Socket clientSocket = clientSslContext.getSocketFactory().createSocket()) {
334 clientSocket.connect(new InetSocketAddress("localhost", localPort), TIMEOUT.toMillisecondsIntBound());
335 clientSocket.setSoTimeout(TIMEOUT.toMillisecondsIntBound());
336 final InputStream inputStream = clientSocket.getInputStream();
337 Assertions.assertEquals('H', inputStream.read());
338 Assertions.assertEquals('i', inputStream.read());
339 Assertions.assertEquals(-1, inputStream.read());
340 }
341
342 final Boolean result = future.get(5, TimeUnit.SECONDS);
343 Assertions.assertNotNull(result);
344 }
345
346 @Test
347 public void testSSLHandshakeServerNotTrusted() throws Exception {
348 final URL resource1 = getResource("/test-server.p12");
349 final String storePassword = "nopassword";
350 final String keyPassword = "nopassword";
351 final SSLContext serverSslContext = SSLContextBuilder.create()
352 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
353 .build();
354 Assertions.assertNotNull(serverSslContext);
355 final URL resource2 = getResource("/test.p12");
356 final SSLContext clientSslContext = SSLContextBuilder.create()
357 .loadTrustMaterial(resource2, storePassword.toCharArray())
358 .build();
359 Assertions.assertNotNull(clientSslContext);
360 final ServerSocket serverSocket = serverSslContext.getServerSocketFactory().createServerSocket();
361 serverSocket.bind(new InetSocketAddress(0));
362
363 this.executorService = Executors.newSingleThreadExecutor();
364 this.executorService.submit(() -> {
365 try (SSLSocket socket = (SSLSocket) serverSocket.accept()) {
366 socket.getSession();
367 }
368 return Boolean.FALSE;
369 });
370 final int localPort = serverSocket.getLocalPort();
371 try (final SSLSocket clientSocket = (SSLSocket) clientSslContext.getSocketFactory().createSocket()) {
372 clientSocket.connect(new InetSocketAddress("localhost", localPort), TIMEOUT.toMillisecondsIntBound());
373 clientSocket.setSoTimeout(TIMEOUT.toMillisecondsIntBound());
374 Assertions.assertThrows(IOException.class, clientSocket::startHandshake);
375 }
376 }
377
378 @Test
379 public void testSSLHandshakeServerCustomTrustStrategy() throws Exception {
380 final URL resource1 = getResource("/test-server.p12");
381 final String storePassword = "nopassword";
382 final String keyPassword = "nopassword";
383 final SSLContext serverSslContext = SSLContextBuilder.create()
384 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
385 .build();
386 Assertions.assertNotNull(serverSslContext);
387
388 final AtomicReference<X509Certificate[]> certChainRef = new AtomicReference<>();
389
390 final TrustStrategy trustStrategy = (chain, authType) -> {
391 certChainRef.set(chain);
392 return true;
393 };
394
395 final SSLContext clientSslContext = SSLContextBuilder.create()
396 .loadTrustMaterial(trustStrategy)
397 .build();
398
399 Assertions.assertNotNull(clientSslContext);
400 final ServerSocket serverSocket = serverSslContext.getServerSocketFactory().createServerSocket();
401 serverSocket.bind(new InetSocketAddress(0));
402
403 this.executorService = Executors.newSingleThreadExecutor();
404 final Future<Boolean> future = this.executorService.submit(() -> {
405 try (Socket socket = serverSocket.accept()) {
406 final OutputStream outputStream = socket.getOutputStream();
407 outputStream.write(new byte[]{'H', 'i'});
408 outputStream.flush();
409 }
410 return Boolean.TRUE;
411 });
412
413 final int localPort = serverSocket.getLocalPort();
414 try (final SSLSocket clientSocket = (SSLSocket) clientSslContext.getSocketFactory().createSocket()) {
415 clientSocket.connect(new InetSocketAddress("localhost", localPort), TIMEOUT.toMillisecondsIntBound());
416 clientSocket.setSoTimeout(TIMEOUT.toMillisecondsIntBound());
417 final InputStream inputStream = clientSocket.getInputStream();
418 Assertions.assertEquals('H', inputStream.read());
419 Assertions.assertEquals('i', inputStream.read());
420 Assertions.assertEquals(-1, inputStream.read());
421 }
422
423 final Boolean result = future.get(5, TimeUnit.SECONDS);
424 Assertions.assertNotNull(result);
425
426 final X509Certificate[] certs = certChainRef.get();
427 Assertions.assertNotNull(certs);
428 Assertions.assertEquals(2, certs.length);
429 final X509Certificate cert1 = certs[0];
430 final Principal subjectDN1 = cert1.getSubjectDN();
431 Assertions.assertNotNull(subjectDN1);
432 Assertions.assertEquals("CN=Test Server, OU=HttpComponents Project, O=Apache Software Foundation", subjectDN1.getName());
433 final X509Certificate cert2 = certs[1];
434 final Principal subjectDN2 = cert2.getSubjectDN();
435 Assertions.assertNotNull(subjectDN2);
436 Assertions.assertEquals("EMAILADDRESS=dev@hc.apache.org, " +
437 "CN=Test CA, OU=HttpComponents Project, O=Apache Software Foundation", subjectDN2.getName());
438 final Principal issuerDN = cert2.getIssuerDN();
439 Assertions.assertNotNull(issuerDN);
440 Assertions.assertEquals("EMAILADDRESS=dev@hc.apache.org, " +
441 "CN=Test CA, OU=HttpComponents Project, O=Apache Software Foundation", issuerDN.getName());
442
443 }
444
445 @Test
446 public void testSSLHandshakeClientUnauthenticated() throws Exception {
447 final URL resource1 = getResource("/test-server.p12");
448 final String storePassword = "nopassword";
449 final String keyPassword = "nopassword";
450 final SSLContext serverSslContext = SSLContextBuilder.create()
451 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
452 .build();
453 Assertions.assertNotNull(serverSslContext);
454 final URL resource2 = getResource("/test-client.p12");
455 final SSLContext clientSslContext = SSLContextBuilder.create()
456 .loadTrustMaterial(resource2, storePassword.toCharArray())
457 .build();
458 Assertions.assertNotNull(clientSslContext);
459 final SSLServerSocket serverSocket = (SSLServerSocket) serverSslContext.getServerSocketFactory().createServerSocket();
460 serverSocket.setWantClientAuth(true);
461 serverSocket.bind(new InetSocketAddress(0));
462
463 this.executorService = Executors.newSingleThreadExecutor();
464 final Future<Principal> future = this.executorService.submit(() -> {
465 final SSLSocket socket = (SSLSocket) serverSocket.accept();
466 Principal clientPrincipal = null;
467 try {
468 final SSLSession session = socket.getSession();
469 try {
470 clientPrincipal = session.getPeerPrincipal();
471 } catch (final SSLPeerUnverifiedException ignore) {
472 }
473 final OutputStream outputStream = socket.getOutputStream();
474 outputStream.write(new byte [] {'H', 'i'});
475 outputStream.flush();
476 } finally {
477 socket.close();
478 }
479 return clientPrincipal;
480 });
481
482 final int localPort = serverSocket.getLocalPort();
483 try (final SSLSocket clientSocket = (SSLSocket) clientSslContext.getSocketFactory().createSocket()) {
484 clientSocket.connect(new InetSocketAddress("localhost", localPort), TIMEOUT.toMillisecondsIntBound());
485 clientSocket.setSoTimeout(TIMEOUT.toMillisecondsIntBound());
486 clientSocket.startHandshake();
487 final InputStream inputStream = clientSocket.getInputStream();
488 Assertions.assertEquals('H', inputStream.read());
489 Assertions.assertEquals('i', inputStream.read());
490 Assertions.assertEquals(-1, inputStream.read());
491 }
492
493 final Principal clientPrincipal = future.get(5, TimeUnit.SECONDS);
494 Assertions.assertNull(clientPrincipal);
495 }
496
497 @Test
498 public void testSSLHandshakeClientUnauthenticatedError() throws Exception {
499 final URL resource1 = getResource("/test-server.p12");
500 final String storePassword = "nopassword";
501 final String keyPassword = "nopassword";
502 final SSLContext serverSslContext = SSLContextBuilder.create()
503 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
504 .build();
505 Assertions.assertNotNull(serverSslContext);
506 final URL resource2 = getResource("/test-client.p12");
507 final SSLContext clientSslContext = SSLContextBuilder.create()
508 .loadTrustMaterial(resource2, storePassword.toCharArray())
509 .build();
510 Assertions.assertNotNull(clientSslContext);
511 final SSLServerSocket serverSocket = (SSLServerSocket) serverSslContext.getServerSocketFactory().createServerSocket();
512 serverSocket.setNeedClientAuth(true);
513 serverSocket.bind(new InetSocketAddress(0));
514
515 this.executorService = Executors.newSingleThreadExecutor();
516 this.executorService.submit(() -> {
517 try (SSLSocket socket = (SSLSocket) serverSocket.accept()) {
518 socket.getSession();
519 }
520 return Boolean.FALSE;
521 });
522
523 final int localPort = serverSocket.getLocalPort();
524 try (final SSLSocket clientSocket = (SSLSocket) clientSslContext.getSocketFactory().createSocket()) {
525 clientSocket.connect(new InetSocketAddress("localhost", localPort), TIMEOUT.toMillisecondsIntBound());
526 clientSocket.setSoTimeout(TIMEOUT.toMillisecondsIntBound());
527 Assertions.assertThrows(IOException.class, () -> {
528 clientSocket.startHandshake();
529 final InputStream inputStream = clientSocket.getInputStream();
530 inputStream.read();
531 });
532 }
533 }
534
535 @Test
536 public void testSSLHandshakeClientAuthenticated() throws Exception {
537 final URL resource1 = getResource("/test-server.p12");
538 final String storePassword = "nopassword";
539 final String keyPassword = "nopassword";
540 final SSLContext serverSslContext = SSLContextBuilder.create()
541 .loadTrustMaterial(resource1, storePassword.toCharArray())
542 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
543 .build();
544 Assertions.assertNotNull(serverSslContext);
545 final URL resource2 = getResource("/test-client.p12");
546 final SSLContext clientSslContext = SSLContextBuilder.create()
547 .loadTrustMaterial(resource2, storePassword.toCharArray())
548 .loadKeyMaterial(resource2, storePassword.toCharArray(), storePassword.toCharArray())
549 .build();
550 Assertions.assertNotNull(clientSslContext);
551 final SSLServerSocket serverSocket = (SSLServerSocket) serverSslContext.getServerSocketFactory().createServerSocket();
552 serverSocket.setNeedClientAuth(true);
553 serverSocket.bind(new InetSocketAddress(0));
554
555 this.executorService = Executors.newSingleThreadExecutor();
556 final Future<Principal> future = this.executorService.submit(() -> {
557 try (SSLSocket socket = (SSLSocket) serverSocket.accept()) {
558 final SSLSession session = socket.getSession();
559 final Principal clientPrincipal = session.getPeerPrincipal();
560 final OutputStream outputStream = socket.getOutputStream();
561 outputStream.write(new byte[]{'H', 'i'});
562 outputStream.flush();
563 return clientPrincipal;
564 }
565 });
566 final int localPort = serverSocket.getLocalPort();
567 try (final SSLSocket clientSocket = (SSLSocket) clientSslContext.getSocketFactory().createSocket()) {
568 clientSocket.connect(new InetSocketAddress("localhost", localPort), TIMEOUT.toMillisecondsIntBound());
569 clientSocket.setSoTimeout(TIMEOUT.toMillisecondsIntBound());
570 clientSocket.startHandshake();
571 final InputStream inputStream = clientSocket.getInputStream();
572 Assertions.assertEquals('H', inputStream.read());
573 Assertions.assertEquals('i', inputStream.read());
574 Assertions.assertEquals(-1, inputStream.read());
575 }
576
577 final Principal clientPrincipal = future.get(5, TimeUnit.SECONDS);
578 Assertions.assertNotNull(clientPrincipal);
579 }
580
581 @Test
582 public void testSSLHandshakeClientAuthenticatedPrivateKeyStrategy() throws Exception {
583 final URL resource1 = getResource("/test-server.p12");
584 final String storePassword = "nopassword";
585 final String keyPassword = "nopassword";
586 final SSLContext serverSslContext = SSLContextBuilder.create()
587 .loadTrustMaterial(resource1, storePassword.toCharArray())
588 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
589 .build();
590 Assertions.assertNotNull(serverSslContext);
591
592 final PrivateKeyStrategy privateKeyStrategy = (aliases, sslParameters) -> aliases.containsKey("client2") ? "client2" : null;
593
594 final URL resource2 = getResource("/test-client.p12");
595 final SSLContext clientSslContext = SSLContextBuilder.create()
596 .loadTrustMaterial(resource2, storePassword.toCharArray())
597 .loadKeyMaterial(resource2, storePassword.toCharArray(), storePassword.toCharArray(), privateKeyStrategy)
598 .build();
599 Assertions.assertNotNull(clientSslContext);
600 final SSLServerSocket serverSocket = (SSLServerSocket) serverSslContext.getServerSocketFactory().createServerSocket();
601 serverSocket.setNeedClientAuth(true);
602 serverSocket.bind(new InetSocketAddress(0));
603
604 this.executorService = Executors.newSingleThreadExecutor();
605 final Future<Principal> future = this.executorService.submit(() -> {
606 try (SSLSocket socket = (SSLSocket) serverSocket.accept()) {
607 final SSLSession session = socket.getSession();
608 final Principal clientPrincipal = session.getPeerPrincipal();
609 final OutputStream outputStream = socket.getOutputStream();
610 outputStream.write(new byte[]{'H', 'i'});
611 outputStream.flush();
612 return clientPrincipal;
613 }
614 });
615 final int localPort = serverSocket.getLocalPort();
616 try (final SSLSocket clientSocket = (SSLSocket) clientSslContext.getSocketFactory().createSocket()) {
617 clientSocket.connect(new InetSocketAddress("localhost", localPort), TIMEOUT.toMillisecondsIntBound());
618 clientSocket.setSoTimeout(TIMEOUT.toMillisecondsIntBound());
619 clientSocket.startHandshake();
620 final InputStream inputStream = clientSocket.getInputStream();
621 Assertions.assertEquals('H', inputStream.read());
622 Assertions.assertEquals('i', inputStream.read());
623 Assertions.assertEquals(-1, inputStream.read());
624 }
625
626 final Principal clientPrincipal = future.get(5, TimeUnit.SECONDS);
627 Assertions.assertNotNull(clientPrincipal);
628 Assertions.assertEquals("CN=Test Client 2,OU=HttpComponents Project,O=Apache Software Foundation", clientPrincipal.getName());
629 }
630
631
632 @Test
633 public void testSSLHandshakeProtocolMismatch1() throws Exception {
634 final URL resource1 = getResource("/test-server.p12");
635 final String storePassword = "nopassword";
636 final String keyPassword = "nopassword";
637 final SSLContext serverSslContext = SSLContextBuilder.create()
638 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
639 .build();
640 Assertions.assertNotNull(serverSslContext);
641 final URL resource2 = getResource("/test-client.p12");
642 final SSLContext clientSslContext = SSLContextBuilder.create()
643 .loadTrustMaterial(resource2, storePassword.toCharArray())
644 .build();
645 Assertions.assertNotNull(clientSslContext);
646 final SSLServerSocket serverSocket = (SSLServerSocket) serverSslContext.getServerSocketFactory().createServerSocket();
647 final Set<String> supportedServerProtocols = new LinkedHashSet<>(Arrays.asList(serverSocket.getSupportedProtocols()));
648 Assertions.assertTrue(supportedServerProtocols.contains("TLSv1"));
649 serverSocket.setEnabledProtocols(new String[] {"TLSv1"});
650 serverSocket.bind(new InetSocketAddress(0));
651
652 this.executorService = Executors.newSingleThreadExecutor();
653 this.executorService.submit(() -> {
654 try (SSLSocket socket = (SSLSocket) serverSocket.accept()) {
655 socket.getSession();
656 }
657 return Boolean.FALSE;
658 });
659
660 final int localPort = serverSocket.getLocalPort();
661 try (final SSLSocket clientSocket = (SSLSocket) clientSslContext.getSocketFactory().createSocket()) {
662 final Set<String> supportedClientProtocols = new LinkedHashSet<>(Arrays.asList(clientSocket.getSupportedProtocols()));
663 Assertions.assertTrue(supportedClientProtocols.contains("SSLv3"));
664 clientSocket.setEnabledProtocols(new String[] {"SSLv3"} );
665 clientSocket.connect(new InetSocketAddress("localhost", localPort), TIMEOUT.toMillisecondsIntBound());
666 clientSocket.setSoTimeout(TIMEOUT.toMillisecondsIntBound());
667 if (isWindows()) {
668 Assertions.assertThrows(IOException.class, clientSocket::startHandshake);
669 } else {
670 Assertions.assertThrows(SSLException.class, clientSocket::startHandshake);
671 }
672 }
673 }
674
675 @Test
676 public void testSSLHandshakeProtocolMismatch2() throws Exception {
677 final URL resource1 = getResource("/test-server.p12");
678 final String storePassword = "nopassword";
679 final String keyPassword = "nopassword";
680 final SSLContext serverSslContext = SSLContextBuilder.create()
681 .loadKeyMaterial(resource1, storePassword.toCharArray(), keyPassword.toCharArray())
682 .build();
683 Assertions.assertNotNull(serverSslContext);
684 final URL resource2 = getResource("/test-client.p12");
685 final SSLContext clientSslContext = SSLContextBuilder.create()
686 .loadTrustMaterial(resource2, storePassword.toCharArray())
687 .build();
688 Assertions.assertNotNull(clientSslContext);
689 final SSLServerSocket serverSocket = (SSLServerSocket) serverSslContext.getServerSocketFactory().createServerSocket();
690 final Set<String> supportedServerProtocols = new LinkedHashSet<>(Arrays.asList(serverSocket.getSupportedProtocols()));
691 Assertions.assertTrue(supportedServerProtocols.contains("SSLv3"));
692 serverSocket.setEnabledProtocols(new String[] {"SSLv3"});
693 serverSocket.bind(new InetSocketAddress(0));
694
695 this.executorService = Executors.newSingleThreadExecutor();
696 this.executorService.submit(() -> {
697 try (SSLSocket socket = (SSLSocket) serverSocket.accept()) {
698 socket.getSession();
699 }
700 return Boolean.FALSE;
701 });
702
703 final int localPort = serverSocket.getLocalPort();
704 try (final SSLSocket clientSocket = (SSLSocket) clientSslContext.getSocketFactory().createSocket()) {
705 final Set<String> supportedClientProtocols = new LinkedHashSet<>(
706 Arrays.asList(clientSocket.getSupportedProtocols()));
707 Assertions.assertTrue(supportedClientProtocols.contains("TLSv1"));
708 clientSocket.setEnabledProtocols(new String[]{"TLSv1"});
709 clientSocket.connect(new InetSocketAddress("localhost", localPort), TIMEOUT.toMillisecondsIntBound());
710 clientSocket.setSoTimeout(TIMEOUT.toMillisecondsIntBound());
711 if (isWindows()) {
712 Assertions.assertThrows(IOException.class, clientSocket::startHandshake);
713 } else {
714 Assertions.assertThrows(SSLException.class, clientSocket::startHandshake);
715 }
716 }
717 }
718
719 }