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