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.PlatformDependent;
25 import io.netty.util.internal.SuppressJava6Requirement;
26 import io.netty.util.internal.logging.InternalLogger;
27 import io.netty.util.internal.logging.InternalLoggerFactory;
28
29 import java.security.KeyStore;
30 import java.security.PrivateKey;
31 import java.security.cert.X509Certificate;
32 import java.util.Map;
33 import javax.net.ssl.KeyManagerFactory;
34 import javax.net.ssl.SSLException;
35 import javax.net.ssl.TrustManagerFactory;
36 import javax.net.ssl.X509ExtendedTrustManager;
37 import javax.net.ssl.X509TrustManager;
38
39 import static io.netty.util.internal.ObjectUtil.checkNotNull;
40
41
42
43
44
45
46
47
48
49 public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext {
50 private static final InternalLogger logger =
51 InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class);
52
53 private final OpenSslServerSessionContext sessionContext;
54
55 ReferenceCountedOpenSslServerContext(
56 X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
57 X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
58 Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
59 long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
60 boolean enableOcsp, String keyStore, ResumptionController resumptionController,
61 Map.Entry<SslContextOption<?>, Object>... options) throws SSLException {
62 this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
63 cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
64 enableOcsp, keyStore, resumptionController, options);
65 }
66
67 ReferenceCountedOpenSslServerContext(
68 X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
69 X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
70 Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
71 long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
72 boolean enableOcsp, String keyStore, ResumptionController resumptionController,
73 Map.Entry<SslContextOption<?>, Object>... options) throws SSLException {
74 super(ciphers, cipherFilter, apn, SSL.SSL_MODE_SERVER, keyCertChain,
75 clientAuth, protocols, startTls,
76 null,
77 enableOcsp, true, resumptionController, options);
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);
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 OpenSslEngineMap 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 throws SSLException {
109
110
111
112 final boolean opaqueConfiguration = keyCertChain == null || keyManagerFactory != null ||
113 (trustCertCollection == null && trustManagerFactory != null);
114 OpenSslKeyMaterialProvider keyMaterialProvider = null;
115 try {
116 try {
117 SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
118 if (!OpenSsl.useKeyManagerFactory()) {
119 if (keyManagerFactory != null) {
120 throw new IllegalArgumentException(
121 "KeyManagerFactory not supported");
122 }
123 checkNotNull(keyCertChain, "keyCertChain");
124
125 setKeyMaterial(ctx, keyCertChain, key, keyPassword);
126 } else {
127
128
129 if (keyManagerFactory == null) {
130 char[] keyPasswordChars = keyStorePassword(keyPassword);
131 KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
132 if (ks.aliases().hasMoreElements()) {
133 keyManagerFactory = new OpenSslX509KeyManagerFactory();
134 } else {
135 keyManagerFactory = new OpenSslCachingX509KeyManagerFactory(
136 KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
137 }
138 keyManagerFactory.init(ks, keyPasswordChars);
139 }
140 keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
141
142 SSLContext.setCertificateCallback(ctx, new OpenSslServerCertificateCallback(
143 engines, new OpenSslKeyMaterialManager(keyMaterialProvider, thiz.hasTmpDhKeys)));
144 }
145 } catch (Exception e) {
146 throw new SSLException("failed to set certificate and key", e);
147 }
148 try {
149 if (trustCertCollection != null) {
150 trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
151 } else if (trustManagerFactory == null) {
152
153 trustManagerFactory = TrustManagerFactory.getInstance(
154 TrustManagerFactory.getDefaultAlgorithm());
155 trustManagerFactory.init((KeyStore) null);
156 }
157
158 final X509TrustManager manager = chooseTrustManager(
159 trustManagerFactory.getTrustManagers(), resumptionController);
160
161
162
163
164
165
166
167 setVerifyCallback(ctx, engines, manager);
168
169 X509Certificate[] issuers = manager.getAcceptedIssuers();
170 if (issuers != null && issuers.length > 0) {
171 long bio = 0;
172 try {
173 bio = toBIO(ByteBufAllocator.DEFAULT, issuers);
174 if (!SSLContext.setCACertificateBio(ctx, bio)) {
175 String msg = "unable to setup accepted issuers for trustmanager " + manager;
176 int error = SSL.getLastErrorNumber();
177 if (error != 0) {
178 msg += ". " + SSL.getErrorString(error);
179 }
180 throw new SSLException(msg);
181 }
182 } finally {
183 freeBio(bio);
184 }
185 }
186
187 if (PlatformDependent.javaVersion() >= 8) {
188
189
190
191
192 SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engines));
193 }
194 } catch (SSLException e) {
195 throw e;
196 } catch (Exception e) {
197 throw new SSLException("unable to setup trustmanager", e);
198 }
199
200 OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider);
201
202
203
204 if (!sessionContext.setSessionIdContext(deriveSessionIdContext(
205 thiz.clientAuth, keyCertChain, trustCertCollection, opaqueConfiguration))) {
206
207 String msg = "failed to set session id context";
208 String lastError = SSL.getLastError();
209 if (lastError != null) {
210 msg += ": " + lastError;
211 }
212 throw new SSLException(msg);
213 }
214
215 sessionContext.setSessionCacheEnabled(SERVER_ENABLE_SESSION_CACHE);
216 if (sessionCacheSize > 0) {
217 sessionContext.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE));
218 }
219 if (sessionTimeout > 0) {
220 sessionContext.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE));
221 }
222
223 keyMaterialProvider = null;
224
225 return sessionContext;
226 } finally {
227 if (keyMaterialProvider != null) {
228 keyMaterialProvider.destroy();
229 }
230 }
231 }
232
233 @SuppressJava6Requirement(reason = "Guarded by java version check")
234 private static void setVerifyCallback(long ctx, OpenSslEngineMap engines, X509TrustManager manager) {
235
236 if (useExtendedTrustManager(manager)) {
237 SSLContext.setCertVerifyCallback(ctx, new ExtendedTrustManagerVerifyCallback(
238 engines, (X509ExtendedTrustManager) manager));
239 } else {
240 SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engines, manager));
241 }
242 }
243
244 private static final class OpenSslServerCertificateCallback implements CertificateCallback {
245 private final OpenSslEngineMap engines;
246 private final OpenSslKeyMaterialManager keyManagerHolder;
247
248 OpenSslServerCertificateCallback(OpenSslEngineMap engines,
249 OpenSslKeyMaterialManager keyManagerHolder) {
250 this.engines = engines;
251 this.keyManagerHolder = keyManagerHolder;
252 }
253
254 @Override
255 public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
256 final ReferenceCountedOpenSslEngine engine = engines.get(ssl);
257 if (engine == null) {
258
259 return;
260 }
261 try {
262
263
264 keyManagerHolder.setKeyMaterialServerSide(engine);
265 } catch (Throwable cause) {
266 engine.initHandshakeException(cause);
267
268 if (cause instanceof Exception) {
269 throw (Exception) cause;
270 }
271 throw new SSLException(cause);
272 }
273 }
274 }
275
276 private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
277 private final X509TrustManager manager;
278
279 TrustManagerVerifyCallback(OpenSslEngineMap engines,
280 X509TrustManager manager) {
281 super(engines);
282 this.manager = manager;
283 }
284
285 @Override
286 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
287 throws Exception {
288 manager.checkClientTrusted(peerCerts, auth);
289 }
290 }
291
292 @SuppressJava6Requirement(reason = "Usage guarded by java version check")
293 private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
294 private final X509ExtendedTrustManager manager;
295
296 ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engines,
297 X509ExtendedTrustManager manager) {
298 super(engines);
299 this.manager = manager;
300 }
301
302 @Override
303 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
304 throws Exception {
305 manager.checkClientTrusted(peerCerts, auth, engine);
306 }
307 }
308
309 private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher {
310 private final OpenSslEngineMap engines;
311
312 OpenSslSniHostnameMatcher(OpenSslEngineMap engines) {
313 this.engines = engines;
314 }
315
316 @Override
317 public boolean match(long ssl, String hostname) {
318 ReferenceCountedOpenSslEngine engine = engines.get(ssl);
319 if (engine != null) {
320
321 return engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8));
322 }
323 logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl);
324 return false;
325 }
326 }
327 }