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 package io.netty.handler.ssl;
17
18 import io.netty.buffer.ByteBufAllocator;
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
33     private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
34
35     /**
36      * Create a new instance.
37      * @param protocols The order of iteration determines the preference of support for protocols.
38      */

39     public JdkAlpnApplicationProtocolNegotiator(Iterable<String> protocols) {
40         this(false, protocols);
41     }
42
43     /**
44      * Create a new instance.
45      * @param protocols The order of iteration determines the preference of support for protocols.
46      */

47     public JdkAlpnApplicationProtocolNegotiator(String... protocols) {
48         this(false, protocols);
49     }
50
51     /**
52      * Create a new instance.
53      * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
54      * @param protocols The order of iteration determines the preference of support for protocols.
55      */

56     public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) {
57         this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
58     }
59
60     /**
61      * Create a new instance.
62      * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
63      * @param protocols The order of iteration determines the preference of support for protocols.
64      */

65     public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
66         this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
67     }
68
69     /**
70      * Create a new instance.
71      * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
72      * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
73      * @param protocols The order of iteration determines the preference of support for protocols.
74      */

75     public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
76             boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
77         this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
78                 clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
79                 protocols);
80     }
81
82     /**
83      * Create a new instance.
84      * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
85      * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
86      * @param protocols The order of iteration determines the preference of support for protocols.
87      */

88     public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
89             boolean serverFailIfNoCommonProtocols, String... protocols) {
90         this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
91                 clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
92                 protocols);
93     }
94
95     /**
96      * Create a new instance.
97      * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
98      * @param listenerFactory The factory which provides to be notified of which protocol was selected.
99      * @param protocols The order of iteration determines the preference of support for protocols.
100      */

101     public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
102             ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) {
103         super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
104     }
105
106     /**
107      * Create a new instance.
108      * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
109      * @param listenerFactory The factory which provides to be notified of which protocol was selected.
110      * @param protocols The order of iteration determines the preference of support for protocols.
111      */

112     public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
113             ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
114         super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
115     }
116
117     private static final class FailureWrapper extends AllocatorAwareSslEngineWrapperFactory {
118         @Override
119         public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
120                                        JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
121             throw new RuntimeException("ALPN unsupported. Is your classpath configured correctly?"
122                     + " For Conscrypt, add the appropriate Conscrypt JAR to classpath and set the security provider."
123                     + " For Jetty-ALPN, see "
124                     + "http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting");
125         }
126     }
127
128     private static final class AlpnWrapper extends AllocatorAwareSslEngineWrapperFactory {
129         @Override
130         public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
131                                        JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
132             if (Conscrypt.isEngineSupported(engine)) {
133                 return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator)
134                         : ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
135             }
136             // ALPN support was recently backported to Java8 as
137             // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8230977.
138             // Because of this lets not do a Java version runtime check but just depend on if the required methods are
139             // present
140             if (JdkAlpnSslUtils.supportsAlpn()) {
141                 return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
142             }
143             if (JettyAlpnSslEngine.isAvailable()) {
144                 return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
145                         : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
146             }
147             throw new UnsupportedOperationException("ALPN not supported. Unable to wrap SSLEngine of type '"
148                     + engine.getClass().getName() + "')");
149         }
150     }
151
152     static boolean isAlpnSupported() {
153         return AVAILABLE;
154     }
155 }
156