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