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 * https://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 io.netty.handler.ssl;
18
19 import io.netty.util.CharsetUtil;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.File;
23 import java.io.IOException;
24 import java.security.InvalidAlgorithmParameterException;
25 import java.security.KeyException;
26 import java.security.KeyStore;
27 import java.security.KeyStoreException;
28 import java.security.NoSuchAlgorithmException;
29 import java.security.PrivateKey;
30 import java.security.Provider;
31 import java.security.SecureRandom;
32 import java.security.UnrecoverableKeyException;
33 import java.security.cert.CertificateException;
34 import java.security.cert.X509Certificate;
35 import java.security.spec.InvalidKeySpecException;
36 import javax.crypto.NoSuchPaddingException;
37 import javax.net.ssl.KeyManager;
38 import javax.net.ssl.KeyManagerFactory;
39 import javax.net.ssl.SSLContext;
40 import javax.net.ssl.SSLException;
41 import javax.net.ssl.SSLSessionContext;
42 import javax.net.ssl.TrustManager;
43 import javax.net.ssl.TrustManagerFactory;
44 import javax.net.ssl.X509ExtendedTrustManager;
45
46 import static io.netty.handler.ssl.SslUtils.PROBING_CERT;
47 import static io.netty.handler.ssl.SslUtils.PROBING_KEY;
48
49 /**
50 * A server-side {@link SslContext} which uses JDK's SSL/TLS implementation.
51 *
52 * @deprecated Use {@link SslContextBuilder} to create {@link JdkSslContext} instances and only
53 * use {@link JdkSslContext} in your code.
54 */
55 @Deprecated
56 public final class JdkSslServerContext extends JdkSslContext {
57
58 private static final boolean WRAP_TRUST_MANAGER;
59 static {
60 boolean wrapTrustManager = false;
61 try {
62 checkIfWrappingTrustManagerIsSupported();
63 wrapTrustManager = true;
64 } catch (Throwable ignore) {
65 // Just don't wrap as we might not be able to do so because of FIPS:
66 // See https://github.com/netty/netty/issues/13840
67 }
68 WRAP_TRUST_MANAGER = wrapTrustManager;
69 }
70
71 // Package-private for testing.
72 static void checkIfWrappingTrustManagerIsSupported() throws CertificateException,
73 InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException,
74 InvalidKeySpecException, IOException, KeyException, KeyStoreException, UnrecoverableKeyException {
75 X509Certificate[] certs = toX509Certificates(
76 new ByteArrayInputStream(PROBING_CERT.getBytes(CharsetUtil.US_ASCII)));
77 PrivateKey privateKey = toPrivateKey(new ByteArrayInputStream(
78 PROBING_KEY.getBytes(CharsetUtil.UTF_8)), null);
79 char[] keyStorePassword = keyStorePassword(null);
80 KeyStore ks = buildKeyStore(certs, privateKey, keyStorePassword, null);
81 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
82 kmf.init(ks, keyStorePassword);
83
84 SSLContext ctx = SSLContext.getInstance(PROTOCOL);
85 TrustManagerFactory tm = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
86 tm.init((KeyStore) null);
87 TrustManager[] managers = tm.getTrustManagers();
88
89 ctx.init(kmf.getKeyManagers(), wrapTrustManagerIfNeeded(managers, null), null);
90 }
91
92 /**
93 * Creates a new instance.
94 *
95 * @param certChainFile an X.509 certificate chain file in PEM format
96 * @param keyFile a PKCS#8 private key file in PEM format
97 * @deprecated use {@link SslContextBuilder}
98 */
99 @Deprecated
100 public JdkSslServerContext(File certChainFile, File keyFile) throws SSLException {
101 this(null, certChainFile, keyFile, null, null, IdentityCipherSuiteFilter.INSTANCE,
102 JdkDefaultApplicationProtocolNegotiator.INSTANCE, 0, 0, null);
103 }
104
105 /**
106 * Creates a new instance.
107 *
108 * @param certChainFile an X.509 certificate chain file in PEM format
109 * @param keyFile a PKCS#8 private key file in PEM format
110 * @param keyPassword the password of the {@code keyFile}.
111 * {@code null} if it's not password-protected.
112 * @deprecated use {@link SslContextBuilder}
113 */
114 @Deprecated
115 public JdkSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException {
116 this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE,
117 JdkDefaultApplicationProtocolNegotiator.INSTANCE, 0, 0);
118 }
119
120 /**
121 * Creates a new instance.
122 *
123 * @param certChainFile an X.509 certificate chain file in PEM format
124 * @param keyFile a PKCS#8 private key file in PEM format
125 * @param keyPassword the password of the {@code keyFile}.
126 * {@code null} if it's not password-protected.
127 * @param ciphers the cipher suites to enable, in the order of preference.
128 * {@code null} to use the default cipher suites.
129 * @param nextProtocols the application layer protocols to accept, in the order of preference.
130 * {@code null} to disable TLS NPN/ALPN extension.
131 * @param sessionCacheSize the size of the cache used for storing SSL session objects.
132 * {@code 0} to use the default value.
133 * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
134 * {@code 0} to use the default value.
135 * @deprecated use {@link SslContextBuilder}
136 */
137 @Deprecated
138 public JdkSslServerContext(
139 File certChainFile, File keyFile, String keyPassword,
140 Iterable<String> ciphers, Iterable<String> nextProtocols,
141 long sessionCacheSize, long sessionTimeout) throws SSLException {
142 this(null, certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE,
143 toNegotiator(toApplicationProtocolConfig(nextProtocols), true), sessionCacheSize,
144 sessionTimeout, KeyStore.getDefaultType());
145 }
146
147 /**
148 * Creates a new instance.
149 *
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 * @param ciphers the cipher suites to enable, in the order of preference.
155 * {@code null} to use the default cipher suites.
156 * @param cipherFilter a filter to apply over the supplied list of ciphers
157 * @param apn Provides a means to configure parameters related to application protocol negotiation.
158 * @param sessionCacheSize the size of the cache used for storing SSL session objects.
159 * {@code 0} to use the default value.
160 * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
161 * {@code 0} to use the default value.
162 * @deprecated use {@link SslContextBuilder}
163 */
164 @Deprecated
165 public JdkSslServerContext(
166 File certChainFile, File keyFile, String keyPassword,
167 Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
168 long sessionCacheSize, long sessionTimeout) throws SSLException {
169 this(null, certChainFile, keyFile, keyPassword, ciphers, cipherFilter,
170 toNegotiator(apn, true), sessionCacheSize, sessionTimeout, KeyStore.getDefaultType());
171 }
172
173 /**
174 * Creates a new instance.
175 *
176 * @param certChainFile an X.509 certificate chain file in PEM format
177 * @param keyFile a PKCS#8 private key file in PEM format
178 * @param keyPassword the password of the {@code keyFile}.
179 * {@code null} if it's not password-protected.
180 * @param ciphers the cipher suites to enable, in the order of preference.
181 * {@code null} to use the default cipher suites.
182 * @param cipherFilter a filter to apply over the supplied list of ciphers
183 * @param apn Application Protocol Negotiator object.
184 * @param sessionCacheSize the size of the cache used for storing SSL session objects.
185 * {@code 0} to use the default value.
186 * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
187 * {@code 0} to use the default value.
188 * @deprecated use {@link SslContextBuilder}
189 */
190 @Deprecated
191 public JdkSslServerContext(
192 File certChainFile, File keyFile, String keyPassword,
193 Iterable<String> ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn,
194 long sessionCacheSize, long sessionTimeout) throws SSLException {
195 this(null, certChainFile, keyFile, keyPassword, ciphers, cipherFilter, apn,
196 sessionCacheSize, sessionTimeout, KeyStore.getDefaultType());
197 }
198
199 JdkSslServerContext(Provider provider,
200 File certChainFile, File keyFile, String keyPassword,
201 Iterable<String> ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn,
202 long sessionCacheSize, long sessionTimeout, String keyStore) throws SSLException {
203 super(newSSLContext(provider, null, null,
204 toX509CertificatesInternal(certChainFile), toPrivateKeyInternal(keyFile, keyPassword),
205 keyPassword, null, sessionCacheSize, sessionTimeout, null, keyStore, null), false,
206 ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
207 }
208
209 /**
210 * Creates a new instance.
211 * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
212 * This provides the certificate collection used for mutual authentication.
213 * {@code null} to use the system default
214 * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
215 * that verifies the certificates sent from clients.
216 * {@code null} to use the default or the results of parsing
217 * {@code trustCertCollectionFile}.
218 * @param keyCertChainFile an X.509 certificate chain file in PEM format
219 * @param keyFile a PKCS#8 private key file in PEM format
220 * @param keyPassword the password of the {@code keyFile}.
221 * {@code null} if it's not password-protected.
222 * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
223 * that is used to encrypt data being sent to clients.
224 * {@code null} to use the default or the results of parsing
225 * {@code keyCertChainFile} and {@code keyFile}.
226 * @param ciphers the cipher suites to enable, in the order of preference.
227 * {@code null} to use the default cipher suites.
228 * @param cipherFilter a filter to apply over the supplied list of ciphers
229 * Only required if {@code provider} is {@link SslProvider#JDK}
230 * @param apn Provides a means to configure parameters related to application protocol negotiation.
231 * @param sessionCacheSize the size of the cache used for storing SSL session objects.
232 * {@code 0} to use the default value.
233 * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
234 * {@code 0} to use the default value.
235 * @deprecated use {@link SslContextBuilder}
236 */
237 @Deprecated
238 public JdkSslServerContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
239 File keyCertChainFile, File keyFile, String keyPassword,
240 KeyManagerFactory keyManagerFactory,
241 Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
242 long sessionCacheSize, long sessionTimeout) throws SSLException {
243 super(newSSLContext(null, toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
244 toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
245 keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout, null, null, null), false,
246 ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
247 }
248
249 /**
250 * Creates a new instance.
251 * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
252 * This provides the certificate collection used for mutual authentication.
253 * {@code null} to use the system default
254 * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
255 * that verifies the certificates sent from clients.
256 * {@code null} to use the default or the results of parsing
257 * {@code trustCertCollectionFile}
258 * @param keyCertChainFile an X.509 certificate chain file in PEM format
259 * @param keyFile a PKCS#8 private key file in PEM format
260 * @param keyPassword the password of the {@code keyFile}.
261 * {@code null} if it's not password-protected.
262 * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
263 * that is used to encrypt data being sent to clients.
264 * {@code null} to use the default or the results of parsing
265 * {@code keyCertChainFile} and {@code keyFile}.
266 * @param ciphers the cipher suites to enable, in the order of preference.
267 * {@code null} to use the default cipher suites.
268 * @param cipherFilter a filter to apply over the supplied list of ciphers
269 * Only required if {@code provider} is {@link SslProvider#JDK}
270 * @param apn Application Protocol Negotiator object.
271 * @param sessionCacheSize the size of the cache used for storing SSL session objects.
272 * {@code 0} to use the default value.
273 * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
274 * {@code 0} to use the default value
275 * @deprecated use {@link SslContextBuilder}
276 */
277 @Deprecated
278 public JdkSslServerContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
279 File keyCertChainFile, File keyFile, String keyPassword,
280 KeyManagerFactory keyManagerFactory,
281 Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
282 JdkApplicationProtocolNegotiator apn,
283 long sessionCacheSize, long sessionTimeout) throws SSLException {
284 super(newSSLContext(null, toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
285 toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
286 keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout,
287 null, KeyStore.getDefaultType(), null), false,
288 ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
289 }
290
291 JdkSslServerContext(Provider provider,
292 X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
293 X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
294 KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
295 ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout,
296 ClientAuth clientAuth, String[] protocols, boolean startTls,
297 SecureRandom secureRandom, String keyStore, ResumptionController resumptionController)
298 throws SSLException {
299 super(newSSLContext(provider, trustCertCollection, trustManagerFactory, keyCertChain, key,
300 keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout, secureRandom, keyStore,
301 resumptionController),
302 false, ciphers, cipherFilter, toNegotiator(apn, true), clientAuth, protocols, startTls, null,
303 null, resumptionController);
304 }
305
306 private static SSLContext newSSLContext(Provider sslContextProvider, X509Certificate[] trustCertCollection,
307 TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain,
308 PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
309 long sessionCacheSize, long sessionTimeout, SecureRandom secureRandom,
310 String keyStore, ResumptionController resumptionController)
311 throws SSLException {
312 if (key == null && keyManagerFactory == null) {
313 throw new NullPointerException("key, keyManagerFactory");
314 }
315
316 try {
317 if (trustCertCollection != null) {
318 trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
319 } else if (trustManagerFactory == null) {
320 // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
321 trustManagerFactory = TrustManagerFactory.getInstance(
322 TrustManagerFactory.getDefaultAlgorithm());
323 trustManagerFactory.init((KeyStore) null);
324 }
325
326 if (key != null) {
327 keyManagerFactory = buildKeyManagerFactory(keyCertChain, null,
328 key, keyPassword, keyManagerFactory, null);
329 }
330
331 // Initialize the SSLContext to work with our key managers.
332 SSLContext ctx = sslContextProvider == null ? SSLContext.getInstance(PROTOCOL)
333 : SSLContext.getInstance(PROTOCOL, sslContextProvider);
334 ctx.init(keyManagerFactory.getKeyManagers(),
335 wrapTrustManagerIfNeeded(trustManagerFactory.getTrustManagers(), resumptionController),
336 secureRandom);
337
338 SSLSessionContext sessCtx = ctx.getServerSessionContext();
339 if (sessionCacheSize > 0) {
340 sessCtx.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE));
341 }
342 if (sessionTimeout > 0) {
343 sessCtx.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE));
344 }
345 return ctx;
346 } catch (Exception e) {
347 if (e instanceof SSLException) {
348 throw (SSLException) e;
349 }
350 throw new SSLException("failed to initialize the server-side SSL context", e);
351 }
352 }
353
354 private static TrustManager[] wrapTrustManagerIfNeeded(
355 TrustManager[] trustManagers, ResumptionController resumptionController) {
356 if (WRAP_TRUST_MANAGER) {
357 for (int i = 0; i < trustManagers.length; i++) {
358 TrustManager tm = trustManagers[i];
359 if (resumptionController != null) {
360 tm = resumptionController.wrapIfNeeded(tm);
361 }
362 if (tm instanceof X509ExtendedTrustManager) {
363 // Wrap the TrustManager to provide a better exception message for users to debug hostname
364 // validation failures.
365 trustManagers[i] = new EnhancingX509ExtendedTrustManager((X509ExtendedTrustManager) tm);
366 }
367 }
368 }
369 return trustManagers;
370 }
371 }