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.net.InetAddress;
32 import java.net.InetSocketAddress;
33 import java.net.Socket;
34 import java.net.SocketTimeoutException;
35 import java.net.UnknownHostException;
36 import java.security.KeyManagementException;
37 import java.security.KeyStore;
38 import java.security.KeyStoreException;
39 import java.security.NoSuchAlgorithmException;
40 import java.security.SecureRandom;
41 import java.security.UnrecoverableKeyException;
42
43 import javax.net.SocketFactory;
44 import javax.net.ssl.SSLContext;
45 import javax.net.ssl.SSLSocket;
46
47 import org.apache.http.HttpHost;
48 import org.apache.http.annotation.Contract;
49 import org.apache.http.annotation.ThreadingBehavior;
50 import org.apache.http.conn.ConnectTimeoutException;
51 import org.apache.http.conn.HttpInetSocketAddress;
52 import org.apache.http.conn.scheme.HostNameResolver;
53 import org.apache.http.conn.scheme.LayeredSchemeSocketFactory;
54 import org.apache.http.conn.scheme.LayeredSocketFactory;
55 import org.apache.http.conn.scheme.SchemeLayeredSocketFactory;
56 import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
57 import org.apache.http.params.HttpConnectionParams;
58 import org.apache.http.params.HttpParams;
59 import org.apache.http.protocol.HttpContext;
60 import org.apache.http.util.Args;
61 import org.apache.http.util.Asserts;
62 import org.apache.http.util.TextUtils;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
146 @Deprecated
147 public class SSLSocketFactory implements LayeredConnectionSocketFactory, SchemeLayeredSocketFactory,
148 LayeredSchemeSocketFactory, LayeredSocketFactory {
149
150 public static final String TLS = "TLS";
151 public static final String SSL = "SSL";
152 public static final String SSLV2 = "SSLv2";
153
154 public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
155 = new AllowAllHostnameVerifier();
156
157 public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
158 = new BrowserCompatHostnameVerifier();
159
160 public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
161 = new StrictHostnameVerifier();
162
163
164
165
166
167
168
169
170 public static SSLSocketFactory getSocketFactory() throws SSLInitializationException {
171 return new SSLSocketFactory(
172 SSLContexts.createDefault(),
173 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
174 }
175
176 private static String[] split(final String s) {
177 if (TextUtils.isBlank(s)) {
178 return null;
179 }
180 return s.split(" *, *");
181 }
182
183
184
185
186
187
188
189
190
191
192 public static SSLSocketFactory getSystemSocketFactory() throws SSLInitializationException {
193 return new SSLSocketFactory(
194 (javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
195 split(System.getProperty("https.protocols")),
196 split(System.getProperty("https.cipherSuites")),
197 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
198 }
199
200 private final javax.net.ssl.SSLSocketFactory socketfactory;
201 private final HostNameResolver nameResolver;
202
203 private volatile X509HostnameVerifier hostnameVerifier;
204 private final String[] supportedProtocols;
205 private final String[] supportedCipherSuites;
206
207 public SSLSocketFactory(
208 final String algorithm,
209 final KeyStore keystore,
210 final String keyPassword,
211 final KeyStore truststore,
212 final SecureRandom random,
213 final HostNameResolver nameResolver)
214 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
215 this(SSLContexts.custom()
216 .useProtocol(algorithm)
217 .setSecureRandom(random)
218 .loadKeyMaterial(keystore, keyPassword != null ? keyPassword.toCharArray() : null)
219 .loadTrustMaterial(truststore)
220 .build(),
221 nameResolver);
222 }
223
224
225
226
227 public SSLSocketFactory(
228 final String algorithm,
229 final KeyStore keystore,
230 final String keyPassword,
231 final KeyStore truststore,
232 final SecureRandom random,
233 final TrustStrategy trustStrategy,
234 final X509HostnameVerifier hostnameVerifier)
235 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
236 this(SSLContexts.custom()
237 .useProtocol(algorithm)
238 .setSecureRandom(random)
239 .loadKeyMaterial(keystore, keyPassword != null ? keyPassword.toCharArray() : null)
240 .loadTrustMaterial(truststore, trustStrategy)
241 .build(),
242 hostnameVerifier);
243 }
244
245
246
247
248 public SSLSocketFactory(
249 final String algorithm,
250 final KeyStore keystore,
251 final String keyPassword,
252 final KeyStore truststore,
253 final SecureRandom random,
254 final X509HostnameVerifier hostnameVerifier)
255 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
256 this(SSLContexts.custom()
257 .useProtocol(algorithm)
258 .setSecureRandom(random)
259 .loadKeyMaterial(keystore, keyPassword != null ? keyPassword.toCharArray() : null)
260 .loadTrustMaterial(truststore)
261 .build(),
262 hostnameVerifier);
263 }
264
265 public SSLSocketFactory(
266 final KeyStore keystore,
267 final String keystorePassword,
268 final KeyStore truststore)
269 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
270 this(SSLContexts.custom()
271 .loadKeyMaterial(keystore, keystorePassword != null ? keystorePassword.toCharArray() : null)
272 .loadTrustMaterial(truststore)
273 .build(),
274 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
275 }
276
277 public SSLSocketFactory(
278 final KeyStore keystore,
279 final String keystorePassword)
280 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException{
281 this(SSLContexts.custom()
282 .loadKeyMaterial(keystore, keystorePassword != null ? keystorePassword.toCharArray() : null)
283 .build(),
284 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
285 }
286
287 public SSLSocketFactory(
288 final KeyStore truststore)
289 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
290 this(SSLContexts.custom()
291 .loadTrustMaterial(truststore)
292 .build(),
293 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
294 }
295
296
297
298
299 public SSLSocketFactory(
300 final TrustStrategy trustStrategy,
301 final X509HostnameVerifier hostnameVerifier)
302 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
303 this(SSLContexts.custom()
304 .loadTrustMaterial(null, trustStrategy)
305 .build(),
306 hostnameVerifier);
307 }
308
309
310
311
312 public SSLSocketFactory(
313 final TrustStrategy trustStrategy)
314 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
315 this(SSLContexts.custom()
316 .loadTrustMaterial(null, trustStrategy)
317 .build(),
318 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
319 }
320
321 public SSLSocketFactory(final SSLContext sslContext) {
322 this(sslContext, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
323 }
324
325 public SSLSocketFactory(
326 final SSLContext sslContext, final HostNameResolver nameResolver) {
327 super();
328 this.socketfactory = sslContext.getSocketFactory();
329 this.hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
330 this.nameResolver = nameResolver;
331 this.supportedProtocols = null;
332 this.supportedCipherSuites = null;
333 }
334
335
336
337
338 public SSLSocketFactory(
339 final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
340 this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
341 null, null, hostnameVerifier);
342 }
343
344
345
346
347 public SSLSocketFactory(
348 final SSLContext sslContext,
349 final String[] supportedProtocols,
350 final String[] supportedCipherSuites,
351 final X509HostnameVerifier hostnameVerifier) {
352 this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
353 supportedProtocols, supportedCipherSuites, hostnameVerifier);
354 }
355
356
357
358
359 public SSLSocketFactory(
360 final javax.net.ssl.SSLSocketFactory socketfactory,
361 final X509HostnameVerifier hostnameVerifier) {
362 this(socketfactory, null, null, hostnameVerifier);
363 }
364
365
366
367
368 public SSLSocketFactory(
369 final javax.net.ssl.SSLSocketFactory socketfactory,
370 final String[] supportedProtocols,
371 final String[] supportedCipherSuites,
372 final X509HostnameVerifier hostnameVerifier) {
373 this.socketfactory = Args.notNull(socketfactory, "SSL socket factory");
374 this.supportedProtocols = supportedProtocols;
375 this.supportedCipherSuites = supportedCipherSuites;
376 this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
377 this.nameResolver = null;
378 }
379
380
381
382
383
384
385 @Override
386 public Socket createSocket(final HttpParams params) throws IOException {
387 return createSocket((HttpContext) null);
388 }
389
390 @Override
391 public Socket createSocket() throws IOException {
392 return createSocket((HttpContext) null);
393 }
394
395
396
397
398 @Override
399 public Socket connectSocket(
400 final Socket socket,
401 final InetSocketAddress remoteAddress,
402 final InetSocketAddress localAddress,
403 final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
404 Args.notNull(remoteAddress, "Remote address");
405 Args.notNull(params, "HTTP parameters");
406 final HttpHost host;
407 if (remoteAddress instanceof HttpInetSocketAddress) {
408 host = ((HttpInetSocketAddress) remoteAddress).getHttpHost();
409 } else {
410 host = new HttpHost(remoteAddress.getHostName(), remoteAddress.getPort(), "https");
411 }
412 final int socketTimeout = HttpConnectionParams.getSoTimeout(params);
413 final int connectTimeout = HttpConnectionParams.getConnectionTimeout(params);
414 socket.setSoTimeout(socketTimeout);
415 return connectSocket(connectTimeout, socket, host, remoteAddress, localAddress, null);
416 }
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433 @Override
434 public boolean isSecure(final Socket sock) throws IllegalArgumentException {
435 Args.notNull(sock, "Socket");
436 Asserts.check(sock instanceof SSLSocket, "Socket not created by this factory");
437 Asserts.check(!sock.isClosed(), "Socket is closed");
438 return true;
439 }
440
441
442
443
444 @Override
445 public Socket createLayeredSocket(
446 final Socket socket,
447 final String host,
448 final int port,
449 final HttpParams params) throws IOException, UnknownHostException {
450 return createLayeredSocket(socket, host, port, (HttpContext) null);
451 }
452
453 @Override
454 public Socket createLayeredSocket(
455 final Socket socket,
456 final String host,
457 final int port,
458 final boolean autoClose) throws IOException, UnknownHostException {
459 return createLayeredSocket(socket, host, port, (HttpContext) null);
460 }
461
462 public void setHostnameVerifier(final X509HostnameVerifier hostnameVerifier) {
463 Args.notNull(hostnameVerifier, "Hostname verifier");
464 this.hostnameVerifier = hostnameVerifier;
465 }
466
467 public X509HostnameVerifier getHostnameVerifier() {
468 return this.hostnameVerifier;
469 }
470
471 @Override
472 public Socket connectSocket(
473 final Socket socket,
474 final String host, final int port,
475 final InetAddress local, final int localPort,
476 final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
477 final InetAddress remote;
478 if (this.nameResolver != null) {
479 remote = this.nameResolver.resolve(host);
480 } else {
481 remote = InetAddress.getByName(host);
482 }
483 InetSocketAddress localAddress = null;
484 if (local != null || localPort > 0) {
485 localAddress = new InetSocketAddress(local, localPort > 0 ? localPort : 0);
486 }
487 final InetSocketAddress remoteAddress = new HttpInetSocketAddress(
488 new HttpHost(host, port), remote, port);
489 return connectSocket(socket, remoteAddress, localAddress, params);
490 }
491
492 @Override
493 public Socket createSocket(
494 final Socket socket,
495 final String host, final int port,
496 final boolean autoClose) throws IOException, UnknownHostException {
497 return createLayeredSocket(socket, host, port, autoClose);
498 }
499
500
501
502
503
504
505
506
507
508
509
510 protected void prepareSocket(final SSLSocket socket) throws IOException {
511 }
512
513 private void internalPrepareSocket(final SSLSocket socket) throws IOException {
514 if (supportedProtocols != null) {
515 socket.setEnabledProtocols(supportedProtocols);
516 }
517 if (supportedCipherSuites != null) {
518 socket.setEnabledCipherSuites(supportedCipherSuites);
519 }
520 prepareSocket(socket);
521 }
522
523 @Override
524 public Socket createSocket(final HttpContext context) throws IOException {
525 return SocketFactory.getDefault().createSocket();
526 }
527
528 @Override
529 public Socket connectSocket(
530 final int connectTimeout,
531 final Socket socket,
532 final HttpHost host,
533 final InetSocketAddress remoteAddress,
534 final InetSocketAddress localAddress,
535 final HttpContext context) throws IOException {
536 Args.notNull(host, "HTTP host");
537 Args.notNull(remoteAddress, "Remote address");
538 final Socket sock = socket != null ? socket : createSocket(context);
539 if (localAddress != null) {
540 sock.bind(localAddress);
541 }
542 try {
543 sock.connect(remoteAddress, connectTimeout);
544 } catch (final SocketTimeoutException ex) {
545 throw new ConnectTimeoutException("Connect to " + remoteAddress + " timed out");
546 }
547
548 if (sock instanceof SSLSocket) {
549 final SSLSocket sslsock = (SSLSocket) sock;
550 sslsock.startHandshake();
551 verifyHostname(sslsock, host.getHostName());
552 return sock;
553 } else {
554 return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context);
555 }
556 }
557
558 @Override
559 public Socket createLayeredSocket(
560 final Socket socket,
561 final String target,
562 final int port,
563 final HttpContext context) throws IOException {
564 final SSLSocket sslsock = (SSLSocket) this.socketfactory.createSocket(
565 socket,
566 target,
567 port,
568 true);
569 internalPrepareSocket(sslsock);
570 sslsock.startHandshake();
571 verifyHostname(sslsock, target);
572 return sslsock;
573 }
574
575 private void verifyHostname(final SSLSocket sslsock, final String hostname) throws IOException {
576 try {
577 this.hostnameVerifier.verify(hostname, sslsock);
578
579 } catch (final IOException iox) {
580
581 try { sslsock.close(); } catch (final Exception x) { }
582 throw iox;
583 }
584 }
585
586 }