1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.handler.ssl;
17
18 import io.netty5.util.internal.EmptyArrays;
19 import io.netty5.util.internal.PlatformDependent;
20 import io.netty5.util.internal.logging.InternalLogger;
21 import io.netty5.util.internal.logging.InternalLoggerFactory;
22
23 import javax.net.ssl.SSLContext;
24 import javax.net.ssl.SSLEngine;
25 import javax.net.ssl.SSLParameters;
26 import java.lang.invoke.MethodHandle;
27 import java.lang.invoke.MethodHandles;
28 import java.lang.invoke.MethodType;
29 import java.security.AccessController;
30 import java.security.PrivilegedExceptionAction;
31 import java.util.List;
32 import java.util.function.BiFunction;
33
34 final class JdkAlpnSslUtils {
35 private static final InternalLogger logger = InternalLoggerFactory.getInstance(JdkAlpnSslUtils.class);
36 private static final MethodHandle SET_APPLICATION_PROTOCOLS;
37 private static final MethodHandle GET_APPLICATION_PROTOCOL;
38 private static final MethodHandle GET_HANDSHAKE_APPLICATION_PROTOCOL;
39 private static final MethodHandle SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
40 private static final MethodHandle GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
41
42 static {
43 MethodHandle getHandshakeApplicationProtocol;
44 MethodHandle getApplicationProtocol;
45 MethodHandle setApplicationProtocols;
46 MethodHandle setHandshakeApplicationProtocolSelector;
47 MethodHandle getHandshakeApplicationProtocolSelector;
48
49 try {
50 SSLContext context = SSLContext.getInstance(JdkSslContext.PROTOCOL);
51 context.init(null, null, null);
52 SSLEngine engine = context.createSSLEngine();
53 MethodHandles.Lookup lookup = MethodHandles.lookup();
54 getHandshakeApplicationProtocol =
55 AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
56 lookup.findVirtual(SSLEngine.class, "getHandshakeApplicationProtocol",
57 MethodType.methodType(String.class)));
58
59 String getHandshakeApplicationProtocolRes = (String) getHandshakeApplicationProtocol.invokeExact(engine);
60
61 getApplicationProtocol = AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
62 lookup.findVirtual(SSLEngine.class, "getApplicationProtocol",
63 MethodType.methodType(String.class)));
64
65 String getApplicationProtocolRes = (String) getApplicationProtocol.invokeExact(engine);
66
67 setApplicationProtocols = AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
68 lookup.findVirtual(SSLParameters.class, "setApplicationProtocols",
69 MethodType.methodType(void.class, String[].class)));
70 setApplicationProtocols.invokeExact(engine.getSSLParameters(), EmptyArrays.EMPTY_STRINGS);
71
72 setHandshakeApplicationProtocolSelector =
73 AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
74 lookup.findVirtual(SSLEngine.class, "setHandshakeApplicationProtocolSelector",
75 MethodType.methodType(void.class, BiFunction.class)));
76 setHandshakeApplicationProtocolSelector.invokeExact(engine,
77 (BiFunction<SSLEngine, List<String>, String>) (sslEngine, strings) -> null);
78
79 getHandshakeApplicationProtocolSelector =
80 AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
81 lookup.findVirtual(SSLEngine.class, "getHandshakeApplicationProtocolSelector",
82 MethodType.methodType(BiFunction.class)));
83
84 @SuppressWarnings("unchecked")
85 BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelectorRes =
86 (BiFunction<SSLEngine, List<String>, String>)
87 getHandshakeApplicationProtocolSelector.invokeExact(engine);
88 } catch (Throwable t) {
89
90 int version = PlatformDependent.javaVersion();
91 logger.error("Unable to initialize JdkAlpnSslUtils. Detected java version was: {}", version, t);
92 getHandshakeApplicationProtocol = null;
93 getApplicationProtocol = null;
94 setApplicationProtocols = null;
95 setHandshakeApplicationProtocolSelector = null;
96 getHandshakeApplicationProtocolSelector = null;
97 }
98 GET_HANDSHAKE_APPLICATION_PROTOCOL = getHandshakeApplicationProtocol;
99 GET_APPLICATION_PROTOCOL = getApplicationProtocol;
100 SET_APPLICATION_PROTOCOLS = setApplicationProtocols;
101 SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = setHandshakeApplicationProtocolSelector;
102 GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = getHandshakeApplicationProtocolSelector;
103 }
104
105 private JdkAlpnSslUtils() {
106 }
107
108 static boolean supportsAlpn() {
109 return GET_APPLICATION_PROTOCOL != null;
110 }
111
112 static String getApplicationProtocol(SSLEngine sslEngine) {
113 try {
114 return (String) GET_APPLICATION_PROTOCOL.invokeExact(sslEngine);
115 } catch (UnsupportedOperationException ex) {
116 throw ex;
117 } catch (Throwable ex) {
118 throw new IllegalStateException(ex);
119 }
120 }
121
122 static String getHandshakeApplicationProtocol(SSLEngine sslEngine) {
123 try {
124 return (String) GET_HANDSHAKE_APPLICATION_PROTOCOL.invokeExact(sslEngine);
125 } catch (UnsupportedOperationException ex) {
126 throw ex;
127 } catch (Throwable ex) {
128 throw new IllegalStateException(ex);
129 }
130 }
131
132 static void setApplicationProtocols(SSLEngine engine, List<String> supportedProtocols) {
133 SSLParameters parameters = engine.getSSLParameters();
134
135 String[] protocolArray = supportedProtocols.toArray(EmptyArrays.EMPTY_STRINGS);
136 try {
137 SET_APPLICATION_PROTOCOLS.invokeExact(parameters, protocolArray);
138 } catch (UnsupportedOperationException ex) {
139 throw ex;
140 } catch (Throwable ex) {
141 throw new IllegalStateException(ex);
142 }
143 engine.setSSLParameters(parameters);
144 }
145
146 static void setHandshakeApplicationProtocolSelector(
147 SSLEngine engine, BiFunction<SSLEngine, List<String>, String> selector) {
148 try {
149 SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invokeExact(engine, selector);
150 } catch (UnsupportedOperationException ex) {
151 throw ex;
152 } catch (Throwable ex) {
153 throw new IllegalStateException(ex);
154 }
155 }
156
157 @SuppressWarnings("unchecked")
158 static BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelector(SSLEngine engine) {
159 try {
160 return (BiFunction<SSLEngine, List<String>, String>)
161 GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invokeExact(engine);
162 } catch (UnsupportedOperationException ex) {
163 throw ex;
164 } catch (Throwable ex) {
165 throw new IllegalStateException(ex);
166 }
167 }
168 }