1 /*
2 * Copyright 2014 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17 package org.jboss.netty.handler.ssl;
18
19 import org.jboss.netty.channel.ChannelPipeline;
20 import org.jboss.netty.channel.ChannelPipelineFactory;
21 import org.jboss.netty.channel.Channels;
22
23 import javax.net.ssl.SSLContext;
24 import javax.net.ssl.SSLEngine;
25 import javax.net.ssl.SSLException;
26 import javax.net.ssl.TrustManager;
27 import javax.net.ssl.TrustManagerFactory;
28 import java.io.File;
29 import java.util.List;
30
31 /**
32 * A secure socket protocol implementation which acts as a factory for {@link SSLEngine} and {@link SslHandler}.
33 * Internally, it is implemented via JDK's {@link SSLContext} or OpenSSL's {@code SSL_CTX}.
34 *
35 * <h3>Making your server support SSL/TLS</h3>
36 * <pre>
37 * // In your {@link ChannelPipelineFactory}:
38 * {@link ChannelPipeline} p = {@link Channels#pipeline()};
39 * {@link SslContext} sslCtx = {@link #newServerContext(File, File) SslContext.newServerContext(...)};
40 * p.addLast("ssl", {@link #newEngine() sslCtx.newEngine()});
41 * ...
42 * </pre>
43 *
44 * <h3>Making your client support SSL/TLS</h3>
45 * <pre>
46 * // In your {@link ChannelPipelineFactory}:
47 * {@link ChannelPipeline} p = {@link Channels#pipeline()};
48 * {@link SslContext} sslCtx = {@link #newClientContext(File) SslContext.newClientContext(...)};
49 * p.addLast("ssl", {@link #newEngine(String, int) sslCtx.newEngine(host, port)});
50 * ...
51 * </pre>
52 */
53 public abstract class SslContext {
54
55 /**
56 * Returns the default server-side implementation provider currently in use.
57 *
58 * @return {@link SslProvider#OPENSSL} if OpenSSL is available. {@link SslProvider#JDK} otherwise.
59 */
60 public static SslProvider defaultServerProvider() {
61 if (OpenSsl.isAvailable()) {
62 return SslProvider.OPENSSL;
63 } else {
64 return SslProvider.JDK;
65 }
66 }
67
68 /**
69 * Returns the default client-side implementation provider currently in use.
70 *
71 * @return {@link SslProvider#JDK}, because it is the only implementation at the moment
72 */
73 public static SslProvider defaultClientProvider() {
74 return SslProvider.JDK;
75 }
76
77 /**
78 * Creates a new server-side {@link SslContext}.
79 *
80 * @param certChainFile an X.509 certificate chain file in PEM format
81 * @param keyFile a PKCS#8 private key file in PEM format
82 * @return a new server-side {@link SslContext}
83 */
84 public static SslContext newServerContext(File certChainFile, File keyFile) throws SSLException {
85 return newServerContext(null, null, certChainFile, keyFile, null, null, null, 0, 0);
86 }
87
88 /**
89 * Creates a new server-side {@link SslContext}.
90 *
91 * @param certChainFile an X.509 certificate chain file in PEM format
92 * @param keyFile a PKCS#8 private key file in PEM format
93 * @param keyPassword the password of the {@code keyFile}.
94 * {@code null} if it's not password-protected.
95 * @return a new server-side {@link SslContext}
96 */
97 public static SslContext newServerContext(
98 File certChainFile, File keyFile, String keyPassword) throws SSLException {
99 return newServerContext(null, null, certChainFile, keyFile, keyPassword, null, null, 0, 0);
100 }
101
102 /**
103 * Creates a new server-side {@link SslContext}.
104 *
105 * @param bufPool the buffer pool which will be used by the returned {@link SslContext}.
106 * {@code null} to use the default buffer pool.
107 * @param certChainFile an X.509 certificate chain file in PEM format
108 * @param keyFile a PKCS#8 private key file in PEM format
109 * @param keyPassword the password of the {@code keyFile}.
110 * {@code null} if it's not password-protected.
111 * @param ciphers the cipher suites to enable, in the order of preference.
112 * {@code null} to use the default cipher suites.
113 * @param nextProtocols the application layer protocols to accept, in the order of preference.
114 * {@code null} to disable TLS NPN/ALPN extension.
115 * @param sessionCacheSize the size of the cache used for storing SSL session objects.
116 * {@code 0} to use the default value.
117 * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
118 * {@code 0} to use the default value.
119 * @return a new server-side {@link SslContext}
120 */
121 public static SslContext newServerContext(
122 SslBufferPool bufPool,
123 File certChainFile, File keyFile, String keyPassword,
124 Iterable<String> ciphers, Iterable<String> nextProtocols,
125 long sessionCacheSize, long sessionTimeout) throws SSLException {
126 return newServerContext(
127 null, bufPool, certChainFile, keyFile, keyPassword,
128 ciphers, nextProtocols, sessionCacheSize, sessionTimeout);
129 }
130
131 /**
132 * Creates a new server-side {@link SslContext}.
133 *
134 * @param provider the {@link SslContext} implementation to use.
135 * {@code null} to use the current default one.
136 * @param certChainFile an X.509 certificate chain file in PEM format
137 * @param keyFile a PKCS#8 private key file in PEM format
138 * @return a new server-side {@link SslContext}
139 */
140 public static SslContext newServerContext(
141 SslProvider provider, File certChainFile, File keyFile) throws SSLException {
142 return newServerContext(provider, null, certChainFile, keyFile, null, null, null, 0, 0);
143 }
144
145 /**
146 * Creates a new server-side {@link SslContext}.
147 *
148 * @param provider the {@link SslContext} implementation to use.
149 * {@code null} to use the current default one.
150 * @param certChainFile an X.509 certificate chain file in PEM format
151 * @param keyFile a PKCS#8 private key file in PEM format
152 * @param keyPassword the password of the {@code keyFile}.
153 * {@code null} if it's not password-protected.
154 * @return a new server-side {@link SslContext}
155 */
156 public static SslContext newServerContext(
157 SslProvider provider, File certChainFile, File keyFile, String keyPassword) throws SSLException {
158 return newServerContext(provider, null, certChainFile, keyFile, keyPassword, null, null, 0, 0);
159 }
160
161 /**
162 * Creates a new server-side {@link SslContext}.
163 *
164 * @param provider the {@link SslContext} implementation to use.
165 * {@code null} to use the current default one.
166 * @param bufPool the buffer pool which will be used by the returned {@link SslContext}.
167 * {@code null} to use the default buffer pool.
168 * @param certChainFile an X.509 certificate chain file in PEM format
169 * @param keyFile a PKCS#8 private key file in PEM format
170 * @param keyPassword the password of the {@code keyFile}.
171 * {@code null} if it's not password-protected.
172 * @param ciphers the cipher suites to enable, in the order of preference.
173 * {@code null} to use the default cipher suites.
174 * @param nextProtocols the application layer protocols to accept, in the order of preference.
175 * {@code null} to disable TLS NPN/ALPN extension.
176 * @param sessionCacheSize the size of the cache used for storing SSL session objects.
177 * {@code 0} to use the default value.
178 * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
179 * {@code 0} to use the default value.
180 * @return a new server-side {@link SslContext}
181 */
182 public static SslContext newServerContext(
183 SslProvider provider, SslBufferPool bufPool,
184 File certChainFile, File keyFile, String keyPassword,
185 Iterable<String> ciphers, Iterable<String> nextProtocols,
186 long sessionCacheSize, long sessionTimeout) throws SSLException {
187
188 if (provider == null) {
189 provider = OpenSsl.isAvailable()? SslProvider.OPENSSL : SslProvider.JDK;
190 }
191
192 switch (provider) {
193 case JDK:
194 return new JdkSslServerContext(
195 bufPool, certChainFile, keyFile, keyPassword,
196 ciphers, nextProtocols, sessionCacheSize, sessionTimeout);
197 case OPENSSL:
198 return new OpenSslServerContext(
199 bufPool, certChainFile, keyFile, keyPassword,
200 ciphers, nextProtocols, sessionCacheSize, sessionTimeout);
201 default:
202 throw new Error(provider.toString());
203 }
204 }
205
206 /**
207 * Creates a new client-side {@link SslContext}.
208 *
209 * @return a new client-side {@link SslContext}
210 */
211 public static SslContext newClientContext() throws SSLException {
212 return newClientContext(null, null, null, null, null, null, 0, 0);
213 }
214
215 /**
216 * Creates a new client-side {@link SslContext}.
217 *
218 * @param certChainFile an X.509 certificate chain file in PEM format
219 *
220 * @return a new client-side {@link SslContext}
221 */
222 public static SslContext newClientContext(File certChainFile) throws SSLException {
223 return newClientContext(null, null, certChainFile, null, null, null, 0, 0);
224 }
225
226 /**
227 * Creates a new client-side {@link SslContext}.
228 *
229 * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
230 * that verifies the certificates sent from servers.
231 * {@code null} to use the default.
232 *
233 * @return a new client-side {@link SslContext}
234 */
235 public static SslContext newClientContext(TrustManagerFactory trustManagerFactory) throws SSLException {
236 return newClientContext(null, null, null, trustManagerFactory, null, null, 0, 0);
237 }
238
239 /**
240 * Creates a new client-side {@link SslContext}.
241 *
242 * @param certChainFile an X.509 certificate chain file in PEM format.
243 * {@code null} to use the system default
244 * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
245 * that verifies the certificates sent from servers.
246 * {@code null} to use the default.
247 *
248 * @return a new client-side {@link SslContext}
249 */
250 public static SslContext newClientContext(
251 File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
252 return newClientContext(null, null, certChainFile, trustManagerFactory, null, null, 0, 0);
253 }
254
255 /**
256 * Creates a new client-side {@link SslContext}.
257 *
258 * @param bufPool the buffer pool which will be used by the returned {@link SslContext}.
259 * {@code null} to use the default buffer pool.
260 * @param certChainFile an X.509 certificate chain file in PEM format.
261 * {@code null} to use the system default
262 * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
263 * that verifies the certificates sent from servers.
264 * {@code null} to use the default.
265 * @param ciphers the cipher suites to enable, in the order of preference.
266 * {@code null} to use the default cipher suites.
267 * @param nextProtocols the application layer protocols to accept, in the order of preference.
268 * {@code null} to disable TLS NPN/ALPN extension.
269 * @param sessionCacheSize the size of the cache used for storing SSL session objects.
270 * {@code 0} to use the default value.
271 * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
272 * {@code 0} to use the default value.
273 *
274 * @return a new client-side {@link SslContext}
275 */
276 public static SslContext newClientContext(
277 SslBufferPool bufPool,
278 File certChainFile, TrustManagerFactory trustManagerFactory,
279 Iterable<String> ciphers, Iterable<String> nextProtocols,
280 long sessionCacheSize, long sessionTimeout) throws SSLException {
281 return newClientContext(
282 null, bufPool, certChainFile, trustManagerFactory,
283 ciphers, nextProtocols, sessionCacheSize, sessionTimeout);
284 }
285
286 /**
287 * Creates a new client-side {@link SslContext}.
288 *
289 * @param provider the {@link SslContext} implementation to use.
290 * {@code null} to use the current default one.
291 *
292 * @return a new client-side {@link SslContext}
293 */
294 public static SslContext newClientContext(SslProvider provider) throws SSLException {
295 return newClientContext(provider, null, null, null, null, null, 0, 0);
296 }
297
298 /**
299 * Creates a new client-side {@link SslContext}.
300 *
301 * @param provider the {@link SslContext} implementation to use.
302 * {@code null} to use the current default one.
303 * @param certChainFile an X.509 certificate chain file in PEM format.
304 * {@code null} to use the system default
305 *
306 * @return a new client-side {@link SslContext}
307 */
308 public static SslContext newClientContext(SslProvider provider, File certChainFile) throws SSLException {
309 return newClientContext(provider, null, certChainFile, null, null, null, 0, 0);
310 }
311
312 /**
313 * Creates a new client-side {@link SslContext}.
314 *
315 * @param provider the {@link SslContext} implementation to use.
316 * {@code null} to use the current default one.
317 * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
318 * that verifies the certificates sent from servers.
319 * {@code null} to use the default.
320 *
321 * @return a new client-side {@link SslContext}
322 */
323 public static SslContext newClientContext(
324 SslProvider provider, TrustManagerFactory trustManagerFactory) throws SSLException {
325 return newClientContext(provider, null, null, trustManagerFactory, null, null, 0, 0);
326 }
327
328 /**
329 * Creates a new client-side {@link SslContext}.
330 *
331 * @param provider the {@link SslContext} implementation to use.
332 * {@code null} to use the current default one.
333 * @param certChainFile an X.509 certificate chain file in PEM format.
334 * {@code null} to use the system default
335 * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
336 * that verifies the certificates sent from servers.
337 * {@code null} to use the default.
338 *
339 * @return a new client-side {@link SslContext}
340 */
341 public static SslContext newClientContext(
342 SslProvider provider, File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
343 return newClientContext(provider, null, certChainFile, trustManagerFactory, null, null, 0, 0);
344 }
345
346 /**
347 * Creates a new client-side {@link SslContext}.
348 *
349 * @param provider the {@link SslContext} implementation to use.
350 * {@code null} to use the current default one.
351 * @param bufPool the buffer pool which will be used by the returned {@link SslContext}.
352 * {@code null} to use the default buffer pool.
353 * @param certChainFile an X.509 certificate chain file in PEM format.
354 * {@code null} to use the system default
355 * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
356 * that verifies the certificates sent from servers.
357 * {@code null} to use the default.
358 * @param ciphers the cipher suites to enable, in the order of preference.
359 * {@code null} to use the default cipher suites.
360 * @param nextProtocols the application layer protocols to accept, in the order of preference.
361 * {@code null} to disable TLS NPN/ALPN extension.
362 * @param sessionCacheSize the size of the cache used for storing SSL session objects.
363 * {@code 0} to use the default value.
364 * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
365 * {@code 0} to use the default value.
366 *
367 * @return a new client-side {@link SslContext}
368 */
369 public static SslContext newClientContext(
370 SslProvider provider, SslBufferPool bufPool,
371 File certChainFile, TrustManagerFactory trustManagerFactory,
372 Iterable<String> ciphers, Iterable<String> nextProtocols,
373 long sessionCacheSize, long sessionTimeout) throws SSLException {
374
375 if (provider != null && provider != SslProvider.JDK) {
376 throw new SSLException("client context unsupported for: " + provider);
377 }
378
379 return new JdkSslClientContext(
380 bufPool, certChainFile, trustManagerFactory,
381 ciphers, nextProtocols, sessionCacheSize, sessionTimeout);
382 }
383
384 private final SslBufferPool bufferPool;
385
386 SslContext(SslBufferPool bufferPool) {
387 this.bufferPool = bufferPool == null? newBufferPool() : bufferPool;
388 }
389
390 SslBufferPool newBufferPool() {
391 return new SslBufferPool(false, false);
392 }
393
394 /**
395 * Returns {@code true} if and only if this context is for server-side.
396 */
397 public final boolean isServer() {
398 return !isClient();
399 }
400
401 /**
402 * Returns the {@link SslBufferPool} used by the {@link SSLEngine} and {@link SslHandler} created by this context.
403 */
404 public final SslBufferPool bufferPool() {
405 return bufferPool;
406 }
407
408 /**
409 * Returns the {@code true} if and only if this context is for client-side.
410 */
411 public abstract boolean isClient();
412
413 /**
414 * Returns the list of enabled cipher suites, in the order of preference.
415 */
416 public abstract List<String> cipherSuites();
417
418 /**
419 * Returns the size of the cache used for storing SSL session objects.
420 */
421 public abstract long sessionCacheSize();
422
423 /**
424 * Returns the timeout for the cached SSL session objects, in seconds.
425 */
426 public abstract long sessionTimeout();
427
428 /**
429 * Returns the list of application layer protocols for the TLS NPN/ALPN extension, in the order of preference.
430 *
431 * @return the list of application layer protocols.
432 * {@code null} if NPN/ALPN extension has been disabled.
433 */
434 public abstract List<String> nextProtocols();
435
436 /**
437 * Creates a new {@link SSLEngine}.
438 *
439 * @return a new {@link SSLEngine}
440 */
441 public abstract SSLEngine newEngine();
442
443 /**
444 * Creates a new {@link SSLEngine} using advisory peer information.
445 *
446 * @param peerHost the non-authoritative name of the host
447 * @param peerPort the non-authoritative port
448 *
449 * @return a new {@link SSLEngine}
450 */
451 public abstract SSLEngine newEngine(String peerHost, int peerPort);
452
453 /**
454 * Creates a new {@link SslHandler}.
455 *
456 * @return a new {@link SslHandler}
457 */
458 public final SslHandler newHandler() {
459 return newHandler(newEngine());
460 }
461
462 /**
463 * Creates a new {@link SslHandler} with advisory peer information.
464 *
465 * @param peerHost the non-authoritative name of the host
466 * @param peerPort the non-authoritative port
467 *
468 * @return a new {@link SslHandler}
469 */
470 public final SslHandler newHandler(String peerHost, int peerPort) {
471 return newHandler(newEngine(peerHost, peerPort));
472 }
473
474 private SslHandler newHandler(SSLEngine engine) {
475 SslHandler handler = new SslHandler(engine, bufferPool());
476 if (isClient()) {
477 handler.setIssueHandshake(true);
478 }
479 handler.setCloseOnSSLException(true);
480 return handler;
481 }
482 }