View Javadoc
1   /*
2    * Copyright 2017 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  
19  import javax.net.ssl.SSLContext;
20  import javax.net.ssl.SSLEngine;
21  import javax.net.ssl.SSLParameters;
22  import java.lang.reflect.Method;
23  import java.security.AccessController;
24  import java.security.PrivilegedExceptionAction;
25  import java.util.List;
26  import java.util.function.BiFunction;
27  
28  import io.netty.util.internal.EmptyArrays;
29  import io.netty.util.internal.PlatformDependent;
30  import io.netty.util.internal.logging.InternalLogger;
31  import io.netty.util.internal.logging.InternalLoggerFactory;
32  
33  final class Java9SslUtils {
34      private static final InternalLogger logger = InternalLoggerFactory.getInstance(Java9SslUtils.class);
35      private static final Method SET_APPLICATION_PROTOCOLS;
36      private static final Method GET_APPLICATION_PROTOCOL;
37      private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL;
38      private static final Method SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
39      private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
40  
41      static {
42          Method getHandshakeApplicationProtocol = null;
43          Method getApplicationProtocol = null;
44          Method setApplicationProtocols = null;
45          Method setHandshakeApplicationProtocolSelector = null;
46          Method getHandshakeApplicationProtocolSelector = null;
47  
48          try {
49              SSLContext context = SSLContext.getInstance(JdkSslContext.PROTOCOL);
50              context.init(null, null, null);
51              SSLEngine engine = context.createSSLEngine();
52              getHandshakeApplicationProtocol = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
53                  @Override
54                  public Method run() throws Exception {
55                      return SSLEngine.class.getMethod("getHandshakeApplicationProtocol");
56                  }
57              });
58              getHandshakeApplicationProtocol.invoke(engine);
59              getApplicationProtocol = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
60                  @Override
61                  public Method run() throws Exception {
62                      return SSLEngine.class.getMethod("getApplicationProtocol");
63                  }
64              });
65              getApplicationProtocol.invoke(engine);
66  
67              setApplicationProtocols = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
68                  @Override
69                  public Method run() throws Exception {
70                      return SSLParameters.class.getMethod("setApplicationProtocols", String[].class);
71                  }
72              });
73              setApplicationProtocols.invoke(engine.getSSLParameters(), new Object[]{EmptyArrays.EMPTY_STRINGS});
74  
75              setHandshakeApplicationProtocolSelector =
76                      AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
77                  @Override
78                  public Method run() throws Exception {
79                      return SSLEngine.class.getMethod("setHandshakeApplicationProtocolSelector", BiFunction.class);
80                  }
81              });
82              setHandshakeApplicationProtocolSelector.invoke(engine, new BiFunction<SSLEngine, List<String>, String>() {
83                  @Override
84                  public String apply(SSLEngine sslEngine, List<String> strings) {
85                      return null;
86                  }
87              });
88  
89              getHandshakeApplicationProtocolSelector =
90                      AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
91                  @Override
92                  public Method run() throws Exception {
93                      return SSLEngine.class.getMethod("getHandshakeApplicationProtocolSelector");
94                  }
95              });
96              getHandshakeApplicationProtocolSelector.invoke(engine);
97          } catch (Throwable t) {
98              logger.error("Unable to initialize Java9SslUtils, but the detected javaVersion was: {}",
99                      PlatformDependent.javaVersion(), t);
100             getHandshakeApplicationProtocol = null;
101             getApplicationProtocol = null;
102             setApplicationProtocols = null;
103             setHandshakeApplicationProtocolSelector = null;
104             getHandshakeApplicationProtocolSelector = null;
105         }
106         GET_HANDSHAKE_APPLICATION_PROTOCOL = getHandshakeApplicationProtocol;
107         GET_APPLICATION_PROTOCOL = getApplicationProtocol;
108         SET_APPLICATION_PROTOCOLS = setApplicationProtocols;
109         SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = setHandshakeApplicationProtocolSelector;
110         GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = getHandshakeApplicationProtocolSelector;
111     }
112 
113     private Java9SslUtils() {
114     }
115 
116     static boolean supportsAlpn() {
117         return GET_APPLICATION_PROTOCOL != null;
118     }
119 
120     static String getApplicationProtocol(SSLEngine sslEngine) {
121         try {
122             return (String) GET_APPLICATION_PROTOCOL.invoke(sslEngine);
123         } catch (UnsupportedOperationException ex) {
124             throw ex;
125         } catch (Exception ex) {
126             throw new IllegalStateException(ex);
127         }
128     }
129 
130     static String getHandshakeApplicationProtocol(SSLEngine sslEngine) {
131         try {
132             return (String) GET_HANDSHAKE_APPLICATION_PROTOCOL.invoke(sslEngine);
133         } catch (UnsupportedOperationException ex) {
134             throw ex;
135         } catch (Exception ex) {
136             throw new IllegalStateException(ex);
137         }
138     }
139 
140     static void setApplicationProtocols(SSLEngine engine, List<String> supportedProtocols) {
141         SSLParameters parameters = engine.getSSLParameters();
142 
143         String[] protocolArray = supportedProtocols.toArray(EmptyArrays.EMPTY_STRINGS);
144         try {
145             SET_APPLICATION_PROTOCOLS.invoke(parameters, new Object[]{protocolArray});
146         } catch (UnsupportedOperationException ex) {
147             throw ex;
148         } catch (Exception ex) {
149             throw new IllegalStateException(ex);
150         }
151         engine.setSSLParameters(parameters);
152     }
153 
154     static void setHandshakeApplicationProtocolSelector(
155             SSLEngine engine, BiFunction<SSLEngine, List<String>, String> selector) {
156         try {
157             SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invoke(engine, selector);
158         } catch (UnsupportedOperationException ex) {
159             throw ex;
160         } catch (Exception ex) {
161             throw new IllegalStateException(ex);
162         }
163     }
164 
165     static BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelector(SSLEngine engine) {
166         try {
167             return (BiFunction<SSLEngine, List<String>, String>)
168                     GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invoke(engine);
169         } catch (UnsupportedOperationException ex) {
170             throw ex;
171         } catch (Exception ex) {
172             throw new IllegalStateException(ex);
173         }
174     }
175 }