1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.handler.ssl;
18
19 import io.netty.handler.ssl.util.KeyManagerFactoryWrapper;
20 import io.netty.handler.ssl.util.TrustManagerFactoryWrapper;
21 import io.netty.util.internal.UnstableApi;
22
23 import javax.net.ssl.KeyManager;
24 import javax.net.ssl.KeyManagerFactory;
25 import javax.net.ssl.SSLEngine;
26 import javax.net.ssl.SSLException;
27 import javax.net.ssl.TrustManager;
28 import javax.net.ssl.TrustManagerFactory;
29 import java.io.File;
30 import java.io.InputStream;
31 import java.security.KeyStore;
32 import java.security.PrivateKey;
33 import java.security.Provider;
34 import java.security.cert.X509Certificate;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39
40 import static io.netty.util.internal.EmptyArrays.EMPTY_STRINGS;
41 import static io.netty.util.internal.EmptyArrays.EMPTY_X509_CERTIFICATES;
42 import static io.netty.util.internal.ObjectUtil.checkNotNull;
43 import static io.netty.util.internal.ObjectUtil.checkNotNullWithIAE;
44 import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
45
46
47
48
49 public final class SslContextBuilder {
50 @SuppressWarnings("rawtypes")
51 private static final Map.Entry[] EMPTY_ENTRIES = new Map.Entry[0];
52
53
54
55
56 public static SslContextBuilder forClient() {
57 return new SslContextBuilder(false);
58 }
59
60
61
62
63
64
65
66
67 public static SslContextBuilder forServer(File keyCertChainFile, File keyFile) {
68 return new SslContextBuilder(true).keyManager(keyCertChainFile, keyFile);
69 }
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public static SslContextBuilder forServer(InputStream keyCertChainInputStream, InputStream keyInputStream) {
84 return new SslContextBuilder(true).keyManager(keyCertChainInputStream, keyInputStream);
85 }
86
87
88
89
90
91
92
93
94 public static SslContextBuilder forServer(PrivateKey key, X509Certificate... keyCertChain) {
95 return new SslContextBuilder(true).keyManager(key, keyCertChain);
96 }
97
98
99
100
101
102
103
104
105 public static SslContextBuilder forServer(PrivateKey key, Iterable<? extends X509Certificate> keyCertChain) {
106 return forServer(key, toArray(keyCertChain, EMPTY_X509_CERTIFICATES));
107 }
108
109
110
111
112
113
114
115
116
117
118 public static SslContextBuilder forServer(
119 File keyCertChainFile, File keyFile, String keyPassword) {
120 return new SslContextBuilder(true).keyManager(keyCertChainFile, keyFile, keyPassword);
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 public static SslContextBuilder forServer(
137 InputStream keyCertChainInputStream, InputStream keyInputStream, String keyPassword) {
138 return new SslContextBuilder(true).keyManager(keyCertChainInputStream, keyInputStream, keyPassword);
139 }
140
141
142
143
144
145
146
147
148
149
150 public static SslContextBuilder forServer(
151 PrivateKey key, String keyPassword, X509Certificate... keyCertChain) {
152 return new SslContextBuilder(true).keyManager(key, keyPassword, keyCertChain);
153 }
154
155
156
157
158
159
160
161
162
163
164 public static SslContextBuilder forServer(
165 PrivateKey key, String keyPassword, Iterable<? extends X509Certificate> keyCertChain) {
166 return forServer(key, keyPassword, toArray(keyCertChain, EMPTY_X509_CERTIFICATES));
167 }
168
169
170
171
172
173
174
175
176
177
178 public static SslContextBuilder forServer(KeyManagerFactory keyManagerFactory) {
179 return new SslContextBuilder(true).keyManager(keyManagerFactory);
180 }
181
182
183
184
185
186
187 public static SslContextBuilder forServer(KeyManager keyManager) {
188 return new SslContextBuilder(true).keyManager(keyManager);
189 }
190
191 private final boolean forServer;
192 private SslProvider provider;
193 private Provider sslContextProvider;
194 private X509Certificate[] trustCertCollection;
195 private TrustManagerFactory trustManagerFactory;
196 private X509Certificate[] keyCertChain;
197 private PrivateKey key;
198 private String keyPassword;
199 private KeyManagerFactory keyManagerFactory;
200 private Iterable<String> ciphers;
201 private CipherSuiteFilter cipherFilter = IdentityCipherSuiteFilter.INSTANCE;
202 private ApplicationProtocolConfig apn;
203 private long sessionCacheSize;
204 private long sessionTimeout;
205 private ClientAuth clientAuth = ClientAuth.NONE;
206 private String[] protocols;
207 private boolean startTls;
208 private boolean enableOcsp;
209 private String keyStoreType = KeyStore.getDefaultType();
210 private final Map<SslContextOption<?>, Object> options = new HashMap<SslContextOption<?>, Object>();
211
212 private SslContextBuilder(boolean forServer) {
213 this.forServer = forServer;
214 }
215
216
217
218
219 public <T> SslContextBuilder option(SslContextOption<T> option, T value) {
220 if (value == null) {
221 options.remove(option);
222 } else {
223 options.put(option, value);
224 }
225 return this;
226 }
227
228
229
230
231 public SslContextBuilder sslProvider(SslProvider provider) {
232 this.provider = provider;
233 return this;
234 }
235
236
237
238
239 public SslContextBuilder keyStoreType(String keyStoreType) {
240 this.keyStoreType = keyStoreType;
241 return this;
242 }
243
244
245
246
247
248 public SslContextBuilder sslContextProvider(Provider sslContextProvider) {
249 this.sslContextProvider = sslContextProvider;
250 return this;
251 }
252
253
254
255
256
257 public SslContextBuilder trustManager(File trustCertCollectionFile) {
258 try {
259 return trustManager(SslContext.toX509Certificates(trustCertCollectionFile));
260 } catch (Exception e) {
261 throw new IllegalArgumentException("File does not contain valid certificates: "
262 + trustCertCollectionFile, e);
263 }
264 }
265
266
267
268
269
270
271
272 public SslContextBuilder trustManager(InputStream trustCertCollectionInputStream) {
273 try {
274 return trustManager(SslContext.toX509Certificates(trustCertCollectionInputStream));
275 } catch (Exception e) {
276 throw new IllegalArgumentException("Input stream does not contain valid certificates.", e);
277 }
278 }
279
280
281
282
283 public SslContextBuilder trustManager(X509Certificate... trustCertCollection) {
284 this.trustCertCollection = trustCertCollection != null ? trustCertCollection.clone() : null;
285 trustManagerFactory = null;
286 return this;
287 }
288
289
290
291
292 public SslContextBuilder trustManager(Iterable<? extends X509Certificate> trustCertCollection) {
293 return trustManager(toArray(trustCertCollection, EMPTY_X509_CERTIFICATES));
294 }
295
296
297
298
299 public SslContextBuilder trustManager(TrustManagerFactory trustManagerFactory) {
300 trustCertCollection = null;
301 this.trustManagerFactory = trustManagerFactory;
302 return this;
303 }
304
305
306
307
308
309
310
311
312 public SslContextBuilder trustManager(TrustManager trustManager) {
313 this.trustManagerFactory = new TrustManagerFactoryWrapper(trustManager);
314 trustCertCollection = null;
315 return this;
316 }
317
318
319
320
321
322
323
324
325 public SslContextBuilder keyManager(File keyCertChainFile, File keyFile) {
326 return keyManager(keyCertChainFile, keyFile, null);
327 }
328
329
330
331
332
333
334
335
336
337
338
339
340 public SslContextBuilder keyManager(InputStream keyCertChainInputStream, InputStream keyInputStream) {
341 return keyManager(keyCertChainInputStream, keyInputStream, null);
342 }
343
344
345
346
347
348
349
350
351 public SslContextBuilder keyManager(PrivateKey key, X509Certificate... keyCertChain) {
352 return keyManager(key, null, keyCertChain);
353 }
354
355
356
357
358
359
360
361
362 public SslContextBuilder keyManager(PrivateKey key, Iterable<? extends X509Certificate> keyCertChain) {
363 return keyManager(key, toArray(keyCertChain, EMPTY_X509_CERTIFICATES));
364 }
365
366
367
368
369
370
371
372
373
374
375 public SslContextBuilder keyManager(File keyCertChainFile, File keyFile, String keyPassword) {
376 X509Certificate[] keyCertChain;
377 PrivateKey key;
378 try {
379 keyCertChain = SslContext.toX509Certificates(keyCertChainFile);
380 } catch (Exception e) {
381 throw new IllegalArgumentException("File does not contain valid certificates: " + keyCertChainFile, e);
382 }
383 try {
384 key = SslContext.toPrivateKey(keyFile, keyPassword);
385 } catch (Exception e) {
386 throw new IllegalArgumentException("File does not contain valid private key: " + keyFile, e);
387 }
388 return keyManager(key, keyPassword, keyCertChain);
389 }
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404 public SslContextBuilder keyManager(InputStream keyCertChainInputStream, InputStream keyInputStream,
405 String keyPassword) {
406 X509Certificate[] keyCertChain;
407 PrivateKey key;
408 try {
409 keyCertChain = SslContext.toX509Certificates(keyCertChainInputStream);
410 } catch (Exception e) {
411 throw new IllegalArgumentException("Input stream not contain valid certificates.", e);
412 }
413 try {
414 key = SslContext.toPrivateKey(keyInputStream, keyPassword);
415 } catch (Exception e) {
416 throw new IllegalArgumentException("Input stream does not contain valid private key.", e);
417 }
418 return keyManager(key, keyPassword, keyCertChain);
419 }
420
421
422
423
424
425
426
427
428
429
430 public SslContextBuilder keyManager(PrivateKey key, String keyPassword, X509Certificate... keyCertChain) {
431 if (forServer) {
432 checkNonEmpty(keyCertChain, "keyCertChain");
433 checkNotNull(key, "key required for servers");
434 }
435 if (keyCertChain == null || keyCertChain.length == 0) {
436 this.keyCertChain = null;
437 } else {
438 for (X509Certificate cert: keyCertChain) {
439 checkNotNullWithIAE(cert, "cert");
440 }
441 this.keyCertChain = keyCertChain.clone();
442 }
443 this.key = key;
444 this.keyPassword = keyPassword;
445 keyManagerFactory = null;
446 return this;
447 }
448
449
450
451
452
453
454
455
456
457
458 public SslContextBuilder keyManager(PrivateKey key, String keyPassword,
459 Iterable<? extends X509Certificate> keyCertChain) {
460 return keyManager(key, keyPassword, toArray(keyCertChain, EMPTY_X509_CERTIFICATES));
461 }
462
463
464
465
466
467
468
469
470
471
472
473
474 public SslContextBuilder keyManager(KeyManagerFactory keyManagerFactory) {
475 if (forServer) {
476 checkNotNull(keyManagerFactory, "keyManagerFactory required for servers");
477 }
478 keyCertChain = null;
479 key = null;
480 keyPassword = null;
481 this.keyManagerFactory = keyManagerFactory;
482 return this;
483 }
484
485
486
487
488
489
490
491
492 public SslContextBuilder keyManager(KeyManager keyManager) {
493 if (forServer) {
494 checkNotNull(keyManager, "keyManager required for servers");
495 }
496 if (keyManager != null) {
497 this.keyManagerFactory = new KeyManagerFactoryWrapper(keyManager);
498 } else {
499 this.keyManagerFactory = null;
500 }
501 keyCertChain = null;
502 key = null;
503 keyPassword = null;
504 return this;
505 }
506
507
508
509
510
511 public SslContextBuilder ciphers(Iterable<String> ciphers) {
512 return ciphers(ciphers, IdentityCipherSuiteFilter.INSTANCE);
513 }
514
515
516
517
518
519
520 public SslContextBuilder ciphers(Iterable<String> ciphers, CipherSuiteFilter cipherFilter) {
521 this.cipherFilter = checkNotNull(cipherFilter, "cipherFilter");
522 this.ciphers = ciphers;
523 return this;
524 }
525
526
527
528
529 public SslContextBuilder applicationProtocolConfig(ApplicationProtocolConfig apn) {
530 this.apn = apn;
531 return this;
532 }
533
534
535
536
537
538 public SslContextBuilder sessionCacheSize(long sessionCacheSize) {
539 this.sessionCacheSize = sessionCacheSize;
540 return this;
541 }
542
543
544
545
546
547 public SslContextBuilder sessionTimeout(long sessionTimeout) {
548 this.sessionTimeout = sessionTimeout;
549 return this;
550 }
551
552
553
554
555 public SslContextBuilder clientAuth(ClientAuth clientAuth) {
556 this.clientAuth = checkNotNull(clientAuth, "clientAuth");
557 return this;
558 }
559
560
561
562
563
564
565 public SslContextBuilder protocols(String... protocols) {
566 this.protocols = protocols == null ? null : protocols.clone();
567 return this;
568 }
569
570
571
572
573
574
575 public SslContextBuilder protocols(Iterable<String> protocols) {
576 return protocols(toArray(protocols, EMPTY_STRINGS));
577 }
578
579
580
581
582 public SslContextBuilder startTls(boolean startTls) {
583 this.startTls = startTls;
584 return this;
585 }
586
587
588
589
590
591
592
593 @UnstableApi
594 public SslContextBuilder enableOcsp(boolean enableOcsp) {
595 this.enableOcsp = enableOcsp;
596 return this;
597 }
598
599
600
601
602
603
604 public SslContext build() throws SSLException {
605 if (forServer) {
606 return SslContext.newServerContextInternal(provider, sslContextProvider, trustCertCollection,
607 trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
608 ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
609 enableOcsp, keyStoreType, toArray(options.entrySet(), EMPTY_ENTRIES));
610 } else {
611 return SslContext.newClientContextInternal(provider, sslContextProvider, trustCertCollection,
612 trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
613 ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, enableOcsp, keyStoreType,
614 toArray(options.entrySet(), EMPTY_ENTRIES));
615 }
616 }
617
618 private static <T> T[] toArray(Iterable<? extends T> iterable, T[] prototype) {
619 if (iterable == null) {
620 return null;
621 }
622 final List<T> list = new ArrayList<T>();
623 for (T element : iterable) {
624 list.add(element);
625 }
626 return list.toArray(prototype);
627 }
628 }