1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.conn.ssl;
29
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.net.InetSocketAddress;
33 import java.net.Socket;
34 import java.net.SocketTimeoutException;
35 import java.security.KeyManagementException;
36 import java.security.KeyStoreException;
37 import java.security.NoSuchAlgorithmException;
38 import java.security.cert.CertificateException;
39 import java.security.cert.X509Certificate;
40 import java.util.concurrent.TimeUnit;
41
42 import javax.net.ssl.HostnameVerifier;
43 import javax.net.ssl.SSLContext;
44 import javax.net.ssl.SSLException;
45 import javax.net.ssl.SSLServerSocket;
46 import javax.net.ssl.SSLSession;
47 import javax.net.ssl.SSLSocket;
48
49 import org.apache.http.HttpHost;
50 import org.apache.http.impl.bootstrap.HttpServer;
51 import org.apache.http.impl.bootstrap.SSLServerSetupHandler;
52 import org.apache.http.impl.bootstrap.ServerBootstrap;
53 import org.apache.http.localserver.LocalServerTestBase;
54 import org.apache.http.localserver.SSLTestContexts;
55 import org.apache.http.protocol.BasicHttpContext;
56 import org.apache.http.protocol.HttpContext;
57 import org.apache.http.ssl.SSLContexts;
58 import org.hamcrest.CoreMatchers;
59 import org.junit.After;
60 import org.junit.Assert;
61 import org.junit.Test;
62
63
64
65
66 public class TestSSLSocketFactory {
67
68 private HttpServer server;
69
70 @After
71 public void shutDown() throws Exception {
72 if (this.server != null) {
73 this.server.shutdown(10, TimeUnit.SECONDS);
74 }
75 }
76
77 static class TestX509HostnameVerifier implements HostnameVerifier {
78
79 private boolean fired = false;
80
81 @Override
82 public boolean verify(final String host, final SSLSession session) {
83 this.fired = true;
84 return true;
85 }
86
87 public boolean isFired() {
88 return this.fired;
89 }
90
91 }
92
93 @Test
94 public void testBasicSSL() throws Exception {
95
96 this.server = ServerBootstrap.bootstrap()
97 .setServerInfo(LocalServerTestBase.ORIGIN)
98 .setSslContext(SSLTestContexts.createServerSSLContext())
99 .create();
100
101 this.server.start();
102
103 final HttpContext context = new BasicHttpContext();
104 final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
105 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
106 SSLTestContexts.createClientSSLContext(), hostVerifier);
107 final Socket socket = socketFactory.createSocket(context);
108 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
109 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
110 final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
111 context);
112 try {
113 final SSLSession sslsession = sslSocket.getSession();
114
115 Assert.assertNotNull(sslsession);
116 Assert.assertTrue(hostVerifier.isFired());
117 } finally {
118 sslSocket.close();
119 }
120 }
121
122 @Test
123 public void testBasicDefaultHostnameVerifier() throws Exception {
124
125 this.server = ServerBootstrap.bootstrap()
126 .setServerInfo(LocalServerTestBase.ORIGIN)
127 .setSslContext(SSLTestContexts.createServerSSLContext())
128 .create();
129
130 this.server.start();
131
132 final HttpContext context = new BasicHttpContext();
133 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
134 SSLTestContexts.createClientSSLContext(), SSLConnectionSocketFactory.getDefaultHostnameVerifier());
135 final Socket socket = socketFactory.createSocket(context);
136 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
137 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
138 final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
139 context);
140 try {
141 final SSLSession sslsession = sslSocket.getSession();
142
143 Assert.assertNotNull(sslsession);
144 } finally {
145 sslSocket.close();
146 }
147 }
148
149 @Test
150 public void testClientAuthSSL() throws Exception {
151
152 this.server = ServerBootstrap.bootstrap()
153 .setServerInfo(LocalServerTestBase.ORIGIN)
154 .setSslContext(SSLTestContexts.createServerSSLContext())
155 .create();
156
157 this.server.start();
158
159 final HttpContext context = new BasicHttpContext();
160 final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
161 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
162 SSLTestContexts.createClientSSLContext(), hostVerifier);
163 final Socket socket = socketFactory.createSocket(context);
164 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
165 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
166 final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
167 context);
168 try {
169 final SSLSession sslsession = sslSocket.getSession();
170
171 Assert.assertNotNull(sslsession);
172 Assert.assertTrue(hostVerifier.isFired());
173 } finally {
174 sslSocket.close();
175 }
176 }
177
178 @Test(expected = IOException.class)
179 public void testClientAuthSSLFailure() throws Exception {
180
181 this.server = ServerBootstrap.bootstrap()
182 .setServerInfo(LocalServerTestBase.ORIGIN)
183 .setSslContext(SSLTestContexts.createServerSSLContext())
184 .setSslSetupHandler(new SSLServerSetupHandler() {
185
186 @Override
187 public void initialize(final SSLServerSocket socket) throws SSLException {
188 socket.setNeedClientAuth(true);
189 }
190
191 })
192 .create();
193
194 this.server.start();
195
196 final HttpContext context = new BasicHttpContext();
197 final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
198 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
199 SSLTestContexts.createClientSSLContext(), hostVerifier);
200 final Socket socket = socketFactory.createSocket(context);
201 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
202 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
203 final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
204 context);
205 try {
206 final InputStream inputStream = sslSocket.getInputStream();
207 Assert.assertEquals(-1, inputStream.read());
208
209 final SSLSession sslsession = sslSocket.getSession();
210 Assert.assertNotNull(sslsession);
211 Assert.assertTrue(hostVerifier.isFired());
212 } finally {
213 sslSocket.close();
214 }
215 }
216
217 @Test(expected = SSLException.class)
218 public void testSSLTrustVerification() throws Exception {
219
220 this.server = ServerBootstrap.bootstrap()
221 .setServerInfo(LocalServerTestBase.ORIGIN)
222 .setSslContext(SSLTestContexts.createServerSSLContext())
223 .create();
224
225 this.server.start();
226
227 final HttpContext context = new BasicHttpContext();
228
229 final SSLContext defaultsslcontext = SSLContexts.createDefault();
230
231 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(defaultsslcontext,
232 NoopHostnameVerifier.INSTANCE);
233
234 final Socket socket = socketFactory.createSocket(context);
235 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
236 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
237 final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
238 context);
239 sslSocket.close();
240 }
241
242 @Test
243 public void testSSLTrustVerificationOverrideWithCustsom() throws Exception {
244 final TrustStrategy trustStrategy = new TrustStrategy() {
245
246 @Override
247 public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
248 return chain.length == 1;
249 }
250
251 };
252 testSSLTrustVerificationOverride(trustStrategy);
253 }
254
255 @Test
256 public void testSSLTrustVerificationOverrideWithTrustSelfSignedStrategy() throws Exception {
257 testSSLTrustVerificationOverride(TrustSelfSignedStrategy.INSTANCE);
258 }
259
260 @Test
261 public void testSSLTrustVerificationOverrideWithTrustAllStrategy() throws Exception {
262 testSSLTrustVerificationOverride(TrustAllStrategy.INSTANCE);
263 }
264
265 private void testSSLTrustVerificationOverride(final TrustStrategy trustStrategy)
266 throws Exception, IOException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
267
268 this.server = ServerBootstrap.bootstrap()
269 .setServerInfo(LocalServerTestBase.ORIGIN)
270 .setSslContext(SSLTestContexts.createServerSSLContext())
271 .create();
272
273 this.server.start();
274
275 final HttpContext context = new BasicHttpContext();
276
277
278 final SSLContext sslcontext = SSLContexts.custom()
279 .loadTrustMaterial(null, trustStrategy)
280 .build();
281
282 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslcontext,
283 NoopHostnameVerifier.INSTANCE);
284
285 final Socket socket = socketFactory.createSocket(context);
286 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
287 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
288 final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
289 context);
290 sslSocket.close();
291 }
292
293 @Test
294 public void testTLSOnly() throws Exception {
295
296 this.server = ServerBootstrap.bootstrap()
297 .setServerInfo(LocalServerTestBase.ORIGIN)
298 .setSslContext(SSLTestContexts.createServerSSLContext())
299 .setSslSetupHandler(new SSLServerSetupHandler() {
300
301 @Override
302 public void initialize(final SSLServerSocket socket) throws SSLException {
303 socket.setEnabledProtocols(new String[] {"TLSv1"});
304 }
305
306 })
307 .create();
308
309 this.server.start();
310
311 final HttpContext context = new BasicHttpContext();
312 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
313 SSLTestContexts.createClientSSLContext());
314 final Socket socket = socketFactory.createSocket(context);
315 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
316 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
317 final SSLSocket sslSocket = (SSLSocket) socketFactory.connectSocket(0, socket, target, remoteAddress, null,
318 context);
319 final SSLSession sslsession = sslSocket.getSession();
320 Assert.assertNotNull(sslsession);
321 }
322
323 @Test(expected = IOException.class)
324 public void testSSLDisabledByDefault() throws Exception {
325
326 this.server = ServerBootstrap.bootstrap()
327 .setServerInfo(LocalServerTestBase.ORIGIN)
328 .setSslContext(SSLTestContexts.createServerSSLContext())
329 .setSslSetupHandler(new SSLServerSetupHandler() {
330
331 @Override
332 public void initialize(final SSLServerSocket socket) throws SSLException {
333 socket.setEnabledProtocols(new String[] {"SSLv3"});
334 }
335
336 })
337 .create();
338
339 this.server.start();
340
341 final HttpContext context = new BasicHttpContext();
342 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
343 SSLTestContexts.createClientSSLContext());
344 final Socket socket = socketFactory.createSocket(context);
345 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
346 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
347 socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
348 }
349
350 @Test
351 public void testSSLTimeout() throws Exception {
352
353 this.server = ServerBootstrap.bootstrap()
354 .setServerInfo(LocalServerTestBase.ORIGIN)
355 .setSslContext(SSLTestContexts.createServerSSLContext())
356 .create();
357
358 this.server.start();
359
360 final HttpContext context = new BasicHttpContext();
361 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
362 SSLTestContexts.createClientSSLContext());
363 final Socket socket = socketFactory.createSocket(context);
364 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
365 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
366 final Socket sslSocket = socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
367 final InputStream inputStream = sslSocket.getInputStream();
368 try {
369 sslSocket.setSoTimeout(1);
370 inputStream.read();
371 Assert.fail("SocketTimeoutException expected");
372 } catch (final SocketTimeoutException ex){
373 Assert.assertThat(sslSocket.isClosed(), CoreMatchers.equalTo(false));
374 Assert.assertThat(socket.isClosed(), CoreMatchers.equalTo(false));
375 } finally {
376 inputStream.close();
377 }
378 }
379
380 @Test
381 public void testStrongCipherSuites() {
382 final String[] strongCipherSuites = {
383 "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
384 "TLS_RSA_WITH_AES_256_CBC_SHA256",
385 "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
386 "TLS_RSA_WITH_AES_128_CBC_SHA",
387 "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
388 "TLS_RSA_WITH_AES_256_GCM_SHA384"
389 };
390 for (final String cipherSuite : strongCipherSuites) {
391 Assert.assertFalse(SSLConnectionSocketFactory.isWeakCipherSuite(cipherSuite));
392 }
393 }
394
395 @Test
396 public void testWeakCiphersDisabledByDefault() {
397 final String[] weakCiphersSuites = {
398 "SSL_RSA_WITH_RC4_128_SHA",
399 "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
400 "TLS_DH_anon_WITH_AES_128_CBC_SHA",
401 "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
402 "SSL_RSA_WITH_NULL_SHA",
403 "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
404 "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
405 "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
406 "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
407 "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
408 "TLS_RSA_WITH_NULL_SHA256",
409 "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
410 "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
411
412 "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"
413 };
414 for (final String cipherSuite : weakCiphersSuites) {
415 Assert.assertTrue(SSLConnectionSocketFactory.isWeakCipherSuite(cipherSuite));
416 try {
417 testWeakCipherDisabledByDefault(cipherSuite);
418 Assert.fail("IOException expected");
419 } catch (final Exception e) {
420 Assert.assertTrue(e instanceof IOException || e instanceof IllegalArgumentException);
421 }
422 }
423 }
424
425 private void testWeakCipherDisabledByDefault(final String cipherSuite) throws Exception {
426
427 this.server = ServerBootstrap.bootstrap()
428 .setServerInfo(LocalServerTestBase.ORIGIN)
429 .setSslContext(SSLTestContexts.createServerSSLContext())
430 .setSslSetupHandler(new SSLServerSetupHandler() {
431
432 @Override
433 public void initialize(final SSLServerSocket socket) {
434 socket.setEnabledCipherSuites(new String[] {cipherSuite});
435 }
436
437 })
438 .create();
439
440 this.server.start();
441
442 final HttpContext context = new BasicHttpContext();
443 final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
444 SSLTestContexts.createClientSSLContext());
445 final Socket socket = socketFactory.createSocket(context);
446 try {
447 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", this.server.getLocalPort());
448 final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), "https");
449 socketFactory.connectSocket(0, socket, target, remoteAddress, null, context);
450 } finally {
451 socket.close();
452 }
453 }
454 }