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