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.buffer.ByteBufAllocator;
19 import io.netty.internal.tcnative.CertificateCallback;
20 import io.netty.internal.tcnative.SSL;
21 import io.netty.internal.tcnative.SSLContext;
22 import io.netty.internal.tcnative.SniHostNameMatcher;
23 import io.netty.util.CharsetUtil;
24 import io.netty.util.internal.logging.InternalLogger;
25 import io.netty.util.internal.logging.InternalLoggerFactory;
26
27 import java.security.KeyStore;
28 import java.security.PrivateKey;
29 import java.security.cert.X509Certificate;
30 import java.util.Map;
31 import javax.net.ssl.KeyManagerFactory;
32 import javax.net.ssl.SSLException;
33 import javax.net.ssl.TrustManagerFactory;
34 import javax.net.ssl.X509ExtendedTrustManager;
35 import javax.net.ssl.X509TrustManager;
36
37 import static io.netty.util.internal.ObjectUtil.checkNotNull;
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, ResumptionController resumptionController,
59 Map.Entry<SslContextOption<?>, Object>... options) throws SSLException {
60 this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
61 cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
62 enableOcsp, keyStore, resumptionController, 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, ResumptionController resumptionController,
71 Map.Entry<SslContextOption<?>, Object>... options) throws SSLException {
72 super(ciphers, cipherFilter, apn, SSL.SSL_MODE_SERVER, keyCertChain,
73 clientAuth, protocols, startTls,
74 null,
75 enableOcsp, true, null, resumptionController, options);
76
77 boolean success = false;
78 try {
79 sessionContext = newSessionContext(this, ctx, engines, trustCertCollection, trustManagerFactory,
80 keyCertChain, key, keyPassword, keyManagerFactory, keyStore,
81 sessionCacheSize, sessionTimeout, resumptionController, isJdkSignatureFallbackEnabled(options));
82 if (SERVER_ENABLE_SESSION_TICKET) {
83 sessionContext.setTicketKeys();
84 }
85 success = true;
86 } finally {
87 if (!success) {
88 release();
89 }
90 }
91 }
92
93 @Override
94 public OpenSslServerSessionContext sessionContext() {
95 return sessionContext;
96 }
97
98 static OpenSslServerSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
99 Map<Long, ReferenceCountedOpenSslEngine> engines,
100 X509Certificate[] trustCertCollection,
101 TrustManagerFactory trustManagerFactory,
102 X509Certificate[] keyCertChain, PrivateKey key,
103 String keyPassword, KeyManagerFactory keyManagerFactory,
104 String keyStore, long sessionCacheSize, long sessionTimeout,
105 ResumptionController resumptionController,
106 boolean fallbackToJdkSignatureProviders)
107 throws SSLException {
108 OpenSslKeyMaterialProvider keyMaterialProvider = null;
109 try {
110 try {
111 SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
112
113
114
115 if (keyManagerFactory == null && key != null && key.getEncoded() == null) {
116 if (!fallbackToJdkSignatureProviders) {
117
118 throw new SSLException("Private key requiring alternative signature provider detected " +
119 "(such as hardware security key, smart card, or remote signing service) but " +
120 "alternative key fallback is disabled.");
121 }
122 keyMaterialProvider = setupSecurityProviderSignatureSource(thiz, ctx, keyCertChain, key,
123 manager -> new OpenSslServerCertificateCallback(engines, manager));
124 } else if (!OpenSsl.useKeyManagerFactory()) {
125 if (keyManagerFactory != null) {
126 throw new IllegalArgumentException(
127 "KeyManagerFactory not supported with external keys");
128 } else {
129 checkNotNull(keyCertChain, "keyCertChain");
130
131 setKeyMaterial(ctx, keyCertChain, key, keyPassword);
132 }
133 } else {
134
135
136 if (keyManagerFactory == null) {
137 keyManagerFactory = certChainToKeyManagerFactory(keyCertChain, key, keyPassword, keyStore);
138 }
139 keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
140
141 SSLContext.setCertificateCallback(ctx, new OpenSslServerCertificateCallback(
142 engines, new OpenSslKeyMaterialManager(keyMaterialProvider, thiz.hasTmpDhKeys)));
143 }
144 } catch (Exception e) {
145 throw new SSLException("failed to set certificate and key", e);
146 }
147 try {
148 if (trustCertCollection != null) {
149 trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
150 } else if (trustManagerFactory == null) {
151
152 trustManagerFactory = TrustManagerFactory.getInstance(
153 TrustManagerFactory.getDefaultAlgorithm());
154 trustManagerFactory.init((KeyStore) null);
155 }
156
157 final X509TrustManager manager = chooseTrustManager(
158 trustManagerFactory.getTrustManagers(), resumptionController);
159
160
161
162
163
164
165
166 setVerifyCallback(ctx, engines, manager);
167
168 X509Certificate[] issuers = manager.getAcceptedIssuers();
169 if (issuers != null && issuers.length > 0) {
170 long bio = 0;
171 try {
172 bio = toBIO(ByteBufAllocator.DEFAULT, issuers);
173 if (!SSLContext.setCACertificateBio(ctx, bio)) {
174 String msg = "unable to setup accepted issuers for trustmanager " + manager;
175 int error = SSL.getLastErrorNumber();
176 if (error != 0) {
177 msg += ". " + SSL.getErrorString(error);
178 }
179 throw new SSLException(msg);
180 }
181 } finally {
182 freeBio(bio);
183 }
184 }
185
186
187
188
189 SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engines));
190 } catch (SSLException e) {
191 throw e;
192 } catch (Exception e) {
193 throw new SSLException("unable to setup trustmanager", e);
194 }
195
196 OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider);
197 sessionContext.setSessionIdContext(ID);
198
199 sessionContext.setSessionCacheEnabled(SERVER_ENABLE_SESSION_CACHE);
200 if (sessionCacheSize > 0) {
201 sessionContext.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE));
202 }
203 if (sessionTimeout > 0) {
204 sessionContext.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE));
205 }
206
207 keyMaterialProvider = null;
208
209 return sessionContext;
210 } finally {
211 if (keyMaterialProvider != null) {
212 keyMaterialProvider.destroy();
213 }
214 }
215 }
216
217 private static void setVerifyCallback(long ctx,
218 Map<Long, ReferenceCountedOpenSslEngine> engines,
219 X509TrustManager manager) {
220
221 if (useExtendedTrustManager(manager)) {
222 SSLContext.setCertVerifyCallback(ctx, new ExtendedTrustManagerVerifyCallback(
223 engines, (X509ExtendedTrustManager) manager));
224 } else {
225 SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engines, manager));
226 }
227 }
228
229 private static final class OpenSslServerCertificateCallback implements CertificateCallback {
230 private final Map<Long, ReferenceCountedOpenSslEngine> engines;
231 private final OpenSslKeyMaterialManager keyManagerHolder;
232
233 OpenSslServerCertificateCallback(Map<Long, ReferenceCountedOpenSslEngine> engines,
234 OpenSslKeyMaterialManager keyManagerHolder) {
235 this.engines = engines;
236 this.keyManagerHolder = keyManagerHolder;
237 }
238
239 @Override
240 public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
241 final ReferenceCountedOpenSslEngine engine = engines.get(ssl);
242 if (engine == null) {
243
244 return;
245 }
246 try {
247
248
249 keyManagerHolder.setKeyMaterialServerSide(engine);
250 } catch (Throwable cause) {
251 engine.initHandshakeException(cause);
252
253 if (cause instanceof Exception) {
254 throw (Exception) cause;
255 }
256 throw new SSLException(cause);
257 }
258 }
259 }
260
261 private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
262 private final X509TrustManager manager;
263
264 TrustManagerVerifyCallback(Map<Long, ReferenceCountedOpenSslEngine> engines,
265 X509TrustManager manager) {
266 super(engines);
267 this.manager = manager;
268 }
269
270 @Override
271 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
272 throws Exception {
273 manager.checkClientTrusted(peerCerts, auth);
274 }
275 }
276
277 private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
278 private final X509ExtendedTrustManager manager;
279
280 ExtendedTrustManagerVerifyCallback(Map<Long, ReferenceCountedOpenSslEngine> engines,
281 X509ExtendedTrustManager manager) {
282 super(engines);
283 this.manager = manager;
284 }
285
286 @Override
287 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
288 throws Exception {
289 manager.checkClientTrusted(peerCerts, auth, engine);
290 }
291 }
292
293 private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher {
294 private final Map<Long, ReferenceCountedOpenSslEngine> engines;
295
296 OpenSslSniHostnameMatcher(Map<Long, ReferenceCountedOpenSslEngine> engines) {
297 this.engines = engines;
298 }
299
300 @Override
301 public boolean match(long ssl, String hostname) {
302 ReferenceCountedOpenSslEngine engine = engines.get(ssl);
303 if (engine != null) {
304
305 return engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8));
306 }
307 logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl);
308 return false;
309 }
310 }
311 }