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  package io.netty.handler.ssl;
17  
18  import io.netty.buffer.ByteBufAllocator;
19  import io.netty.handler.ssl.util.BouncyCastleUtil;
20  
21  import javax.net.ssl.SSLEngine;
22  
23  /**
24   * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
25   *
26   * @deprecated use {@link ApplicationProtocolConfig}.
27   */
28  @Deprecated
29  public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
30      private static final boolean AVAILABLE = Conscrypt.isAvailable() ||
31                                               JdkAlpnSslUtils.supportsAlpn() ||
32                                               JettyAlpnSslEngine.isAvailable() ||
33              (BouncyCastleUtil.isBcTlsAvailable() && BouncyCastleAlpnSslUtils.isAlpnSupported());
34  
35      private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
36  
37      /**
38       * Create a new instance.
39       * @param protocols The order of iteration determines the preference of support for protocols.
40       */
41      public JdkAlpnApplicationProtocolNegotiator(Iterable<String> protocols) {
42          this(false, protocols);
43      }
44  
45      /**
46       * Create a new instance.
47       * @param protocols The order of iteration determines the preference of support for protocols.
48       */
49      public JdkAlpnApplicationProtocolNegotiator(String... protocols) {
50          this(false, protocols);
51      }
52  
53      /**
54       * Create a new instance.
55       * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
56       * @param protocols The order of iteration determines the preference of support for protocols.
57       */
58      public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) {
59          this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
60      }
61  
62      /**
63       * Create a new instance.
64       * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
65       * @param protocols The order of iteration determines the preference of support for protocols.
66       */
67      public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
68          this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
69      }
70  
71      /**
72       * Create a new instance.
73       * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
74       * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
75       * @param protocols The order of iteration determines the preference of support for protocols.
76       */
77      public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
78              boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
79          this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
80                  clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
81                  protocols);
82      }
83  
84      /**
85       * Create a new instance.
86       * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
87       * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
88       * @param protocols The order of iteration determines the preference of support for protocols.
89       */
90      public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
91              boolean serverFailIfNoCommonProtocols, String... protocols) {
92          this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
93                  clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
94                  protocols);
95      }
96  
97      /**
98       * Create a new instance.
99       * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
100      * @param listenerFactory The factory which provides to be notified of which protocol was selected.
101      * @param protocols The order of iteration determines the preference of support for protocols.
102      */
103     public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
104             ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) {
105         super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
106     }
107 
108     /**
109      * Create a new instance.
110      * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
111      * @param listenerFactory The factory which provides to be notified of which protocol was selected.
112      * @param protocols The order of iteration determines the preference of support for protocols.
113      */
114     public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
115             ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
116         super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
117     }
118 
119     private static final class FailureWrapper extends AllocatorAwareSslEngineWrapperFactory {
120         @Override
121         public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
122                                        JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
123             throw new RuntimeException("ALPN unsupported. Is your classpath configured correctly?"
124                     + " For Conscrypt, add the appropriate Conscrypt JAR to classpath and set the security provider."
125                     + " For Jetty-ALPN, see "
126                     + "https://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting");
127         }
128     }
129 
130     private static final class AlpnWrapper extends AllocatorAwareSslEngineWrapperFactory {
131         @Override
132         public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
133                                        JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
134             if (Conscrypt.isEngineSupported(engine)) {
135                 return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator)
136                         : ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
137             }
138             if (BouncyCastleUtil.isBcJsseInUse(engine) && BouncyCastleAlpnSslUtils.isAlpnSupported()) {
139                 return new BouncyCastleAlpnSslEngine(engine, applicationNegotiator, isServer);
140             }
141             // ALPN support was recently backported to Java8 as
142             // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8230977.
143             // Because of this lets not do a Java version runtime check but just depend on if the required methods are
144             // present
145             if (JdkAlpnSslUtils.supportsAlpn()) {
146                 return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
147             }
148             if (JettyAlpnSslEngine.isAvailable()) {
149                 return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
150                         : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
151             }
152             throw new UnsupportedOperationException("ALPN not supported. Unable to wrap SSLEngine of type '"
153                     + engine.getClass().getName() + "')");
154         }
155     }
156 
157     static boolean isAlpnSupported() {
158         return AVAILABLE;
159     }
160 }