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