1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import io.netty.util.internal.EmptyArrays;
19 import io.netty.util.internal.PlatformDependent;
20 import io.netty.util.internal.logging.InternalLogger;
21 import io.netty.util.internal.logging.InternalLoggerFactory;
22
23 import java.lang.reflect.InvocationHandler;
24 import java.lang.reflect.Method;
25 import java.lang.reflect.Proxy;
26 import java.security.AccessController;
27 import java.security.PrivilegedExceptionAction;
28 import java.util.List;
29 import java.util.function.BiFunction;
30 import javax.net.ssl.SSLContext;
31 import javax.net.ssl.SSLEngine;
32
33 import static io.netty.handler.ssl.SslUtils.getSSLContext;
34
35 final class BouncyCastleAlpnSslUtils {
36 private static final InternalLogger logger = InternalLoggerFactory.getInstance(BouncyCastleAlpnSslUtils.class);
37 private static final Method SET_PARAMETERS;
38 private static final Method GET_PARAMETERS;
39 private static final Method SET_APPLICATION_PROTOCOLS;
40 private static final Method GET_APPLICATION_PROTOCOL;
41 private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL;
42 private static final Method SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
43 private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
44 private static final Class BC_APPLICATION_PROTOCOL_SELECTOR;
45 private static final Method BC_APPLICATION_PROTOCOL_SELECTOR_SELECT;
46
47 static {
48 Class bcSslEngine;
49 Method getParameters;
50 Method setParameters;
51 Method setApplicationProtocols;
52 Method getApplicationProtocol;
53 Method getHandshakeApplicationProtocol;
54 Method setHandshakeApplicationProtocolSelector;
55 Method getHandshakeApplicationProtocolSelector;
56 Method bcApplicationProtocolSelectorSelect;
57 Class bcApplicationProtocolSelector;
58
59 try {
60 bcSslEngine = Class.forName("org.bouncycastle.jsse.BCSSLEngine");
61 final Class testBCSslEngine = bcSslEngine;
62
63 bcApplicationProtocolSelector =
64 Class.forName("org.bouncycastle.jsse.BCApplicationProtocolSelector");
65
66 final Class testBCApplicationProtocolSelector = bcApplicationProtocolSelector;
67
68 bcApplicationProtocolSelectorSelect = AccessController.doPrivileged(
69 new PrivilegedExceptionAction<Method>() {
70 @Override
71 public Method run() throws Exception {
72 return testBCApplicationProtocolSelector.getMethod("select", Object.class, List.class);
73 }
74 });
75
76 SSLContext context = getSSLContext("BCJSSE");
77 SSLEngine engine = context.createSSLEngine();
78
79 getParameters = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
80 @Override
81 public Method run() throws Exception {
82 return testBCSslEngine.getMethod("getParameters");
83 }
84 });
85
86 final Object bcSslParameters = getParameters.invoke(engine);
87 final Class<?> bCSslParametersClass = bcSslParameters.getClass();
88
89 setParameters = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
90 @Override
91 public Method run() throws Exception {
92 return testBCSslEngine.getMethod("setParameters", bCSslParametersClass);
93 }
94 });
95 setParameters.invoke(engine, bcSslParameters);
96
97 setApplicationProtocols = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
98 @Override
99 public Method run() throws Exception {
100 return bCSslParametersClass.getMethod("setApplicationProtocols", String[].class);
101 }
102 });
103 setApplicationProtocols.invoke(bcSslParameters, new Object[]{EmptyArrays.EMPTY_STRINGS});
104
105 getApplicationProtocol = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
106 @Override
107 public Method run() throws Exception {
108 return testBCSslEngine.getMethod("getApplicationProtocol");
109 }
110 });
111 getApplicationProtocol.invoke(engine);
112
113 getHandshakeApplicationProtocol = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
114 @Override
115 public Method run() throws Exception {
116 return testBCSslEngine.getMethod("getHandshakeApplicationProtocol");
117 }
118 });
119 getHandshakeApplicationProtocol.invoke(engine);
120
121 setHandshakeApplicationProtocolSelector =
122 AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
123 @Override
124 public Method run() throws Exception {
125 return testBCSslEngine.getMethod("setBCHandshakeApplicationProtocolSelector",
126 testBCApplicationProtocolSelector);
127 }
128 });
129
130 getHandshakeApplicationProtocolSelector =
131 AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
132 @Override
133 public Method run() throws Exception {
134 return testBCSslEngine.getMethod("getBCHandshakeApplicationProtocolSelector");
135 }
136 });
137 getHandshakeApplicationProtocolSelector.invoke(engine);
138
139 } catch (Throwable t) {
140 logger.error("Unable to initialize BouncyCastleAlpnSslUtils.", t);
141 setParameters = null;
142 getParameters = null;
143 setApplicationProtocols = null;
144 getApplicationProtocol = null;
145 getHandshakeApplicationProtocol = null;
146 setHandshakeApplicationProtocolSelector = null;
147 getHandshakeApplicationProtocolSelector = null;
148 bcApplicationProtocolSelectorSelect = null;
149 bcApplicationProtocolSelector = null;
150 }
151 SET_PARAMETERS = setParameters;
152 GET_PARAMETERS = getParameters;
153 SET_APPLICATION_PROTOCOLS = setApplicationProtocols;
154 GET_APPLICATION_PROTOCOL = getApplicationProtocol;
155 GET_HANDSHAKE_APPLICATION_PROTOCOL = getHandshakeApplicationProtocol;
156 SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = setHandshakeApplicationProtocolSelector;
157 GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = getHandshakeApplicationProtocolSelector;
158 BC_APPLICATION_PROTOCOL_SELECTOR_SELECT = bcApplicationProtocolSelectorSelect;
159 BC_APPLICATION_PROTOCOL_SELECTOR = bcApplicationProtocolSelector;
160 }
161
162 private BouncyCastleAlpnSslUtils() {
163 }
164
165 static String getApplicationProtocol(SSLEngine sslEngine) {
166 try {
167 return (String) GET_APPLICATION_PROTOCOL.invoke(sslEngine);
168 } catch (UnsupportedOperationException ex) {
169 throw ex;
170 } catch (Exception ex) {
171 throw new IllegalStateException(ex);
172 }
173 }
174
175 static void setApplicationProtocols(SSLEngine engine, List<String> supportedProtocols) {
176 String[] protocolArray = supportedProtocols.toArray(EmptyArrays.EMPTY_STRINGS);
177 try {
178 Object bcSslParameters = GET_PARAMETERS.invoke(engine);
179 SET_APPLICATION_PROTOCOLS.invoke(bcSslParameters, new Object[]{protocolArray});
180 SET_PARAMETERS.invoke(engine, bcSslParameters);
181 } catch (UnsupportedOperationException ex) {
182 throw ex;
183 } catch (Exception ex) {
184 throw new IllegalStateException(ex);
185 }
186 if (PlatformDependent.javaVersion() >= 9) {
187 JdkAlpnSslUtils.setApplicationProtocols(engine, supportedProtocols);
188 }
189 }
190
191 static String getHandshakeApplicationProtocol(SSLEngine sslEngine) {
192 try {
193 return (String) GET_HANDSHAKE_APPLICATION_PROTOCOL.invoke(sslEngine);
194 } catch (UnsupportedOperationException ex) {
195 throw ex;
196 } catch (Exception ex) {
197 throw new IllegalStateException(ex);
198 }
199 }
200
201 static void setHandshakeApplicationProtocolSelector(
202 SSLEngine engine, final BiFunction<SSLEngine, List<String>, String> selector) {
203 try {
204 Object selectorProxyInstance = Proxy.newProxyInstance(
205 BouncyCastleAlpnSslUtils.class.getClassLoader(),
206 new Class[]{BC_APPLICATION_PROTOCOL_SELECTOR},
207 new InvocationHandler() {
208 @Override
209 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
210 if (method.getName().equals("select")) {
211 try {
212 return selector.apply((SSLEngine) args[0], (List<String>) args[1]);
213 } catch (ClassCastException e) {
214 throw new RuntimeException("BCApplicationProtocolSelector select method " +
215 "parameter of invalid type.", e);
216 }
217 } else {
218 throw new UnsupportedOperationException(String.format("Method '%s' not supported.",
219 method.getName()));
220 }
221 }
222 });
223
224 SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invoke(engine, selectorProxyInstance);
225 } catch (UnsupportedOperationException ex) {
226 throw ex;
227 } catch (Exception ex) {
228 throw new IllegalStateException(ex);
229 }
230 }
231
232 @SuppressWarnings("unchecked")
233 static BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelector(SSLEngine engine) {
234 try {
235 final Object selector = GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invoke(engine);
236 return new BiFunction<SSLEngine, List<String>, String>() {
237
238 @Override
239 public String apply(SSLEngine sslEngine, List<String> strings) {
240 try {
241 return (String) BC_APPLICATION_PROTOCOL_SELECTOR_SELECT.invoke(selector, sslEngine,
242 strings);
243 } catch (Exception e) {
244 throw new RuntimeException("Could not call getHandshakeApplicationProtocolSelector", e);
245 }
246 }
247 };
248
249 } catch (UnsupportedOperationException ex) {
250 throw ex;
251 } catch (Exception ex) {
252 throw new IllegalStateException(ex);
253 }
254 }
255
256 }