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.netty.internal.tcnative.CertificateCallback;
19 import io.netty.internal.tcnative.SSL;
20 import io.netty.internal.tcnative.SSLContext;
21 import io.netty.internal.tcnative.SniHostNameMatcher;
22 import io.netty5.buffer.api.DefaultBufferAllocators;
23 import io.netty5.util.CharsetUtil;
24 import io.netty5.util.internal.logging.InternalLogger;
25 import io.netty5.util.internal.logging.InternalLoggerFactory;
26
27 import javax.net.ssl.KeyManagerFactory;
28 import javax.net.ssl.SSLException;
29 import javax.net.ssl.TrustManagerFactory;
30 import javax.net.ssl.X509ExtendedTrustManager;
31 import javax.net.ssl.X509TrustManager;
32 import java.security.KeyStore;
33 import java.security.PrivateKey;
34 import java.security.cert.X509Certificate;
35 import java.util.Map;
36
37 import static java.util.Objects.requireNonNull;
38
39
40
41
42
43
44
45
46
47 public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext {
48 private static final InternalLogger logger =
49 InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class);
50 private static final byte[] ID = {'n', 'e', 't', 't', 'y'};
51 private final OpenSslServerSessionContext sessionContext;
52
53 ReferenceCountedOpenSslServerContext(
54 X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
55 X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
56 Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
57 long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
58 boolean enableOcsp, String keyStore, Map.Entry<SslContextOption<?>, Object>... options)
59 throws SSLException {
60 this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
61 cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
62 enableOcsp, keyStore, options);
63 }
64
65 ReferenceCountedOpenSslServerContext(
66 X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
67 X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
68 Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
69 long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
70 boolean enableOcsp, String keyStore, Map.Entry<SslContextOption<?>, Object>... options)
71 throws SSLException {
72 super(ciphers, cipherFilter, apn, SSL.SSL_MODE_SERVER, keyCertChain,
73 clientAuth, protocols, startTls, enableOcsp, true, options);
74
75 boolean success = false;
76 try {
77 sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
78 keyCertChain, key, keyPassword, keyManagerFactory, keyStore,
79 sessionCacheSize, sessionTimeout);
80 if (SERVER_ENABLE_SESSION_TICKET) {
81 sessionContext.setTicketKeys();
82 }
83 success = true;
84 } finally {
85 if (!success) {
86 release();
87 }
88 }
89 }
90
91 @Override
92 public OpenSslServerSessionContext sessionContext() {
93 return sessionContext;
94 }
95
96 static OpenSslServerSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
97 OpenSslEngineMap engineMap,
98 X509Certificate[] trustCertCollection,
99 TrustManagerFactory trustManagerFactory,
100 X509Certificate[] keyCertChain, PrivateKey key,
101 String keyPassword, KeyManagerFactory keyManagerFactory,
102 String keyStore, long sessionCacheSize, long sessionTimeout)
103 throws SSLException {
104 OpenSslKeyMaterialProvider keyMaterialProvider = null;
105 try {
106 try {
107 SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
108 if (!OpenSsl.supportsKeyManagerFactory()) {
109 if (keyManagerFactory != null) {
110 throw new IllegalArgumentException(
111 "KeyManagerFactory not supported");
112 }
113 requireNonNull(keyCertChain, "keyCertChain");
114
115 setKeyMaterial(ctx, keyCertChain, key, keyPassword);
116 } else {
117
118
119 if (keyManagerFactory == null) {
120 char[] keyPasswordChars = keyStorePassword(keyPassword);
121 KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
122 if (ks.aliases().hasMoreElements()) {
123 keyManagerFactory = new OpenSslX509KeyManagerFactory();
124 } else {
125 keyManagerFactory = new OpenSslCachingX509KeyManagerFactory(
126 KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
127 }
128 keyManagerFactory.init(ks, keyPasswordChars);
129 }
130 keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
131
132 SSLContext.setCertificateCallback(ctx, new OpenSslServerCertificateCallback(
133 engineMap, new OpenSslKeyMaterialManager(keyMaterialProvider)));
134 }
135 } catch (Exception e) {
136 throw new SSLException("failed to set certificate and key", e);
137 }
138 try {
139 if (trustCertCollection != null) {
140 trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
141 } else if (trustManagerFactory == null) {
142
143 trustManagerFactory = TrustManagerFactory.getInstance(
144 TrustManagerFactory.getDefaultAlgorithm());
145 trustManagerFactory.init((KeyStore) null);
146 }
147
148 final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
149
150
151
152
153
154
155
156
157 if (useExtendedTrustManager(manager)) {
158 SSLContext.setCertVerifyCallback(ctx, new ExtendedTrustManagerVerifyCallback(
159 engineMap, (X509ExtendedTrustManager) manager));
160 } else {
161 SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
162 }
163
164 X509Certificate[] issuers = manager.getAcceptedIssuers();
165 if (issuers != null && issuers.length > 0) {
166 long bio = 0;
167 try {
168 bio = toBIO(DefaultBufferAllocators.offHeapAllocator(), issuers);
169 if (!SSLContext.setCACertificateBio(ctx, bio)) {
170 throw new SSLException("unable to setup accepted issuers for trustmanager " + manager);
171 }
172 } finally {
173 freeBio(bio);
174 }
175 }
176
177
178
179
180 SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap));
181 } catch (SSLException e) {
182 throw e;
183 } catch (Exception e) {
184 throw new SSLException("unable to setup trustmanager", e);
185 }
186
187 OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider);
188 sessionContext.setSessionIdContext(ID);
189
190 sessionContext.setSessionCacheEnabled(SERVER_ENABLE_SESSION_CACHE);
191 if (sessionCacheSize > 0) {
192 sessionContext.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE));
193 }
194 if (sessionTimeout > 0) {
195 sessionContext.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE));
196 }
197
198 keyMaterialProvider = null;
199
200 return sessionContext;
201 } finally {
202 if (keyMaterialProvider != null) {
203 keyMaterialProvider.destroy();
204 }
205 }
206 }
207
208 private static final class OpenSslServerCertificateCallback implements CertificateCallback {
209 private final OpenSslEngineMap engineMap;
210 private final OpenSslKeyMaterialManager keyManagerHolder;
211
212 OpenSslServerCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
213 this.engineMap = engineMap;
214 this.keyManagerHolder = keyManagerHolder;
215 }
216
217 @Override
218 public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
219 final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
220 if (engine == null) {
221
222 return;
223 }
224 try {
225
226
227 keyManagerHolder.setKeyMaterialServerSide(engine);
228 } catch (Throwable cause) {
229 engine.initHandshakeException(cause);
230
231 if (cause instanceof Exception) {
232 throw (Exception) cause;
233 }
234 throw new SSLException(cause);
235 }
236 }
237 }
238
239 private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
240 private final X509TrustManager manager;
241
242 TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
243 super(engineMap);
244 this.manager = manager;
245 }
246
247 @Override
248 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
249 throws Exception {
250 manager.checkClientTrusted(peerCerts, auth);
251 }
252 }
253
254 private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
255 private final X509ExtendedTrustManager manager;
256
257 ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
258 super(engineMap);
259 this.manager = manager;
260 }
261
262 @Override
263 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
264 throws Exception {
265 manager.checkClientTrusted(peerCerts, auth, engine);
266 }
267 }
268
269 private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher {
270 private final OpenSslEngineMap engineMap;
271
272 OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) {
273 this.engineMap = engineMap;
274 }
275
276 @Override
277 public boolean match(long ssl, String hostname) {
278 ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
279 if (engine != null) {
280
281 return engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8));
282 }
283 logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl);
284 return false;
285 }
286 }
287 }