View Javadoc
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                 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 }