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