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