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.ssl;
29
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.net.Socket;
35 import java.net.URL;
36 import java.security.KeyManagementException;
37 import java.security.KeyStore;
38 import java.security.KeyStoreException;
39 import java.security.NoSuchAlgorithmException;
40 import java.security.Principal;
41 import java.security.PrivateKey;
42 import java.security.Provider;
43 import java.security.SecureRandom;
44 import java.security.Security;
45 import java.security.UnrecoverableKeyException;
46 import java.security.cert.CertificateException;
47 import java.security.cert.X509Certificate;
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.HashMap;
51 import java.util.LinkedHashSet;
52 import java.util.Map;
53 import java.util.Set;
54
55 import javax.net.ssl.KeyManager;
56 import javax.net.ssl.KeyManagerFactory;
57 import javax.net.ssl.SSLContext;
58 import javax.net.ssl.SSLEngine;
59 import javax.net.ssl.TrustManager;
60 import javax.net.ssl.TrustManagerFactory;
61 import javax.net.ssl.X509ExtendedKeyManager;
62 import javax.net.ssl.X509TrustManager;
63
64 import org.apache.http.util.Args;
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public class SSLContextBuilder {
81
82 static final String TLS = "TLS";
83
84 private String protocol;
85 private final Set<KeyManager> keyManagers;
86 private String keyManagerFactoryAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
87 private String keyStoreType = KeyStore.getDefaultType();
88 private final Set<TrustManager> trustManagers;
89 private String trustManagerFactoryAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
90 private SecureRandom secureRandom;
91 private Provider provider;
92
93 public static SSLContextBuilder create() {
94 return new SSLContextBuilder();
95 }
96
97 public SSLContextBuilder() {
98 super();
99 this.keyManagers = new LinkedHashSet<KeyManager>();
100 this.trustManagers = new LinkedHashSet<TrustManager>();
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 @Deprecated
119 public SSLContextBuilder useProtocol(final String protocol) {
120 this.protocol = protocol;
121 return this;
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 public SSLContextBuilder setProtocol(final String protocol) {
140 this.protocol = protocol;
141 return this;
142 }
143
144 public SSLContextBuilder setSecureRandom(final SecureRandom secureRandom) {
145 this.secureRandom = secureRandom;
146 return this;
147 }
148
149 public SSLContextBuilder setProvider(final Provider provider) {
150 this.provider = provider;
151 return this;
152 }
153
154 public SSLContextBuilder setProvider(final String name) {
155 this.provider = Security.getProvider(name);
156 return this;
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 public SSLContextBuilder setKeyStoreType(final String keyStoreType) {
175 this.keyStoreType = keyStoreType;
176 return this;
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 public SSLContextBuilder setKeyManagerFactoryAlgorithm(final String keyManagerFactoryAlgorithm) {
195 this.keyManagerFactoryAlgorithm = keyManagerFactoryAlgorithm;
196 return this;
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214 public SSLContextBuilder setTrustManagerFactoryAlgorithm(final String trustManagerFactoryAlgorithm) {
215 this.trustManagerFactoryAlgorithm = trustManagerFactoryAlgorithm;
216 return this;
217 }
218
219 public SSLContextBuilder loadTrustMaterial(
220 final KeyStore truststore,
221 final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
222 final TrustManagerFactory tmfactory = TrustManagerFactory
223 .getInstance(trustManagerFactoryAlgorithm == null ? TrustManagerFactory.getDefaultAlgorithm()
224 : trustManagerFactoryAlgorithm);
225 tmfactory.init(truststore);
226 final TrustManager[] tms = tmfactory.getTrustManagers();
227 if (tms != null) {
228 if (trustStrategy != null) {
229 for (int i = 0; i < tms.length; i++) {
230 final TrustManager tm = tms[i];
231 if (tm instanceof X509TrustManager) {
232 tms[i] = new TrustManagerDelegate((X509TrustManager) tm, trustStrategy);
233 }
234 }
235 }
236 Collections.addAll(this.trustManagers, tms);
237 }
238 return this;
239 }
240
241 public SSLContextBuilder loadTrustMaterial(
242 final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
243 return loadTrustMaterial(null, trustStrategy);
244 }
245
246 public SSLContextBuilder loadTrustMaterial(
247 final File file,
248 final char[] storePassword,
249 final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
250 Args.notNull(file, "Truststore file");
251 final KeyStore trustStore = KeyStore.getInstance(keyStoreType);
252 final FileInputStream inStream = new FileInputStream(file);
253 try {
254 trustStore.load(inStream, storePassword);
255 } finally {
256 inStream.close();
257 }
258 return loadTrustMaterial(trustStore, trustStrategy);
259 }
260
261 public SSLContextBuilder loadTrustMaterial(
262 final File file,
263 final char[] storePassword) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
264 return loadTrustMaterial(file, storePassword, null);
265 }
266
267 public SSLContextBuilder loadTrustMaterial(
268 final File file) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
269 return loadTrustMaterial(file, null);
270 }
271
272 public SSLContextBuilder loadTrustMaterial(
273 final URL url,
274 final char[] storePassword,
275 final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
276 Args.notNull(url, "Truststore URL");
277 final KeyStore trustStore = KeyStore.getInstance(keyStoreType);
278 final InputStream inStream = url.openStream();
279 try {
280 trustStore.load(inStream, storePassword);
281 } finally {
282 inStream.close();
283 }
284 return loadTrustMaterial(trustStore, trustStrategy);
285 }
286
287 public SSLContextBuilder loadTrustMaterial(
288 final URL url,
289 final char[] storePassword) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
290 return loadTrustMaterial(url, storePassword, null);
291 }
292
293 public SSLContextBuilder loadKeyMaterial(
294 final KeyStore keystore,
295 final char[] keyPassword,
296 final PrivateKeyStrategy aliasStrategy)
297 throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
298 final KeyManagerFactory kmfactory = KeyManagerFactory
299 .getInstance(keyManagerFactoryAlgorithm == null ? KeyManagerFactory.getDefaultAlgorithm()
300 : keyManagerFactoryAlgorithm);
301 kmfactory.init(keystore, keyPassword);
302 final KeyManager[] kms = kmfactory.getKeyManagers();
303 if (kms != null) {
304 if (aliasStrategy != null) {
305 for (int i = 0; i < kms.length; i++) {
306 final KeyManager km = kms[i];
307 if (km instanceof X509ExtendedKeyManager) {
308 kms[i] = new KeyManagerDelegate((X509ExtendedKeyManager) km, aliasStrategy);
309 }
310 }
311 }
312 Collections.addAll(keyManagers, kms);
313 }
314 return this;
315 }
316
317 public SSLContextBuilder loadKeyMaterial(
318 final KeyStore keystore,
319 final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
320 return loadKeyMaterial(keystore, keyPassword, null);
321 }
322
323 public SSLContextBuilder loadKeyMaterial(
324 final File file,
325 final char[] storePassword,
326 final char[] keyPassword,
327 final PrivateKeyStrategy aliasStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
328 Args.notNull(file, "Keystore file");
329 final KeyStore identityStore = KeyStore.getInstance(keyStoreType);
330 final FileInputStream inStream = new FileInputStream(file);
331 try {
332 identityStore.load(inStream, storePassword);
333 } finally {
334 inStream.close();
335 }
336 return loadKeyMaterial(identityStore, keyPassword, aliasStrategy);
337 }
338
339 public SSLContextBuilder loadKeyMaterial(
340 final File file,
341 final char[] storePassword,
342 final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
343 return loadKeyMaterial(file, storePassword, keyPassword, null);
344 }
345
346 public SSLContextBuilder loadKeyMaterial(
347 final URL url,
348 final char[] storePassword,
349 final char[] keyPassword,
350 final PrivateKeyStrategy aliasStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
351 Args.notNull(url, "Keystore URL");
352 final KeyStore identityStore = KeyStore.getInstance(keyStoreType);
353 final InputStream inStream = url.openStream();
354 try {
355 identityStore.load(inStream, storePassword);
356 } finally {
357 inStream.close();
358 }
359 return loadKeyMaterial(identityStore, keyPassword, aliasStrategy);
360 }
361
362 public SSLContextBuilder loadKeyMaterial(
363 final URL url,
364 final char[] storePassword,
365 final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
366 return loadKeyMaterial(url, storePassword, keyPassword, null);
367 }
368
369 protected void initSSLContext(
370 final SSLContext sslContext,
371 final Collection<KeyManager> keyManagers,
372 final Collection<TrustManager> trustManagers,
373 final SecureRandom secureRandom) throws KeyManagementException {
374 sslContext.init(
375 !keyManagers.isEmpty() ? keyManagers.toArray(new KeyManager[keyManagers.size()]) : null,
376 !trustManagers.isEmpty() ? trustManagers.toArray(new TrustManager[trustManagers.size()]) : null,
377 secureRandom);
378 }
379
380 public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
381 final SSLContext sslContext;
382 final String protocolStr = this.protocol != null ? this.protocol : TLS;
383 if (this.provider != null) {
384 sslContext = SSLContext.getInstance(protocolStr, this.provider);
385 } else {
386 sslContext = SSLContext.getInstance(protocolStr);
387 }
388 initSSLContext(sslContext, keyManagers, trustManagers, secureRandom);
389 return sslContext;
390 }
391
392 static class TrustManagerDelegate implements X509TrustManager {
393
394 private final X509TrustManager trustManager;
395 private final TrustStrategy trustStrategy;
396
397 TrustManagerDelegate(final X509TrustManager trustManager, final TrustStrategy trustStrategy) {
398 super();
399 this.trustManager = trustManager;
400 this.trustStrategy = trustStrategy;
401 }
402
403 @Override
404 public void checkClientTrusted(
405 final X509Certificate[] chain, final String authType) throws CertificateException {
406 this.trustManager.checkClientTrusted(chain, authType);
407 }
408
409 @Override
410 public void checkServerTrusted(
411 final X509Certificate[] chain, final String authType) throws CertificateException {
412 if (!this.trustStrategy.isTrusted(chain, authType)) {
413 this.trustManager.checkServerTrusted(chain, authType);
414 }
415 }
416
417 @Override
418 public X509Certificate[] getAcceptedIssuers() {
419 return this.trustManager.getAcceptedIssuers();
420 }
421
422 }
423
424 static class KeyManagerDelegate extends X509ExtendedKeyManager {
425
426 private final X509ExtendedKeyManager keyManager;
427 private final PrivateKeyStrategy aliasStrategy;
428
429 KeyManagerDelegate(final X509ExtendedKeyManager keyManager, final PrivateKeyStrategy aliasStrategy) {
430 super();
431 this.keyManager = keyManager;
432 this.aliasStrategy = aliasStrategy;
433 }
434
435 @Override
436 public String[] getClientAliases(
437 final String keyType, final Principal[] issuers) {
438 return this.keyManager.getClientAliases(keyType, issuers);
439 }
440
441 public Map<String, PrivateKeyDetails> getClientAliasMap(
442 final String[] keyTypes, final Principal[] issuers) {
443 final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>();
444 for (final String keyType: keyTypes) {
445 final String[] aliases = this.keyManager.getClientAliases(keyType, issuers);
446 if (aliases != null) {
447 for (final String alias: aliases) {
448 validAliases.put(alias,
449 new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
450 }
451 }
452 }
453 return validAliases;
454 }
455
456 public Map<String, PrivateKeyDetails> getServerAliasMap(
457 final String keyType, final Principal[] issuers) {
458 final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>();
459 final String[] aliases = this.keyManager.getServerAliases(keyType, issuers);
460 if (aliases != null) {
461 for (final String alias: aliases) {
462 validAliases.put(alias,
463 new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
464 }
465 }
466 return validAliases;
467 }
468
469 @Override
470 public String chooseClientAlias(
471 final String[] keyTypes, final Principal[] issuers, final Socket socket) {
472 final Map<String, PrivateKeyDetails> validAliases = getClientAliasMap(keyTypes, issuers);
473 return this.aliasStrategy.chooseAlias(validAliases, socket);
474 }
475
476 @Override
477 public String[] getServerAliases(
478 final String keyType, final Principal[] issuers) {
479 return this.keyManager.getServerAliases(keyType, issuers);
480 }
481
482 @Override
483 public String chooseServerAlias(
484 final String keyType, final Principal[] issuers, final Socket socket) {
485 final Map<String, PrivateKeyDetails> validAliases = getServerAliasMap(keyType, issuers);
486 return this.aliasStrategy.chooseAlias(validAliases, socket);
487 }
488
489 @Override
490 public X509Certificate[] getCertificateChain(final String alias) {
491 return this.keyManager.getCertificateChain(alias);
492 }
493
494 @Override
495 public PrivateKey getPrivateKey(final String alias) {
496 return this.keyManager.getPrivateKey(alias);
497 }
498
499 @Override
500 public String chooseEngineClientAlias(
501 final String[] keyTypes, final Principal[] issuers, final SSLEngine sslEngine) {
502 final Map<String, PrivateKeyDetails> validAliases = getClientAliasMap(keyTypes, issuers);
503 return this.aliasStrategy.chooseAlias(validAliases, null);
504 }
505
506 @Override
507 public String chooseEngineServerAlias(
508 final String keyType, final Principal[] issuers, final SSLEngine sslEngine) {
509 final Map<String, PrivateKeyDetails> validAliases = getServerAliasMap(keyType, issuers);
510 return this.aliasStrategy.chooseAlias(validAliases, null);
511 }
512
513 }
514
515 @Override
516 public String toString() {
517 return "[provider=" + provider + ", protocol=" + protocol + ", keyStoreType=" + keyStoreType
518 + ", keyManagerFactoryAlgorithm=" + keyManagerFactoryAlgorithm + ", keyManagers=" + keyManagers
519 + ", trustManagerFactoryAlgorithm=" + trustManagerFactoryAlgorithm + ", trustManagers=" + trustManagers
520 + ", secureRandom=" + secureRandom + "]";
521 }
522
523 }