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 private static final byte[] ID = {'n', 'e', 't', 't', 'y'};
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, engineMap, 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 engineMap,
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 OpenSslKeyMaterialProvider keyMaterialProvider = null;
110 try {
111 try {
112 SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
113 if (!OpenSsl.useKeyManagerFactory()) {
114 if (keyManagerFactory != null) {
115 throw new IllegalArgumentException(
116 "KeyManagerFactory not supported");
117 }
118 checkNotNull(keyCertChain, "keyCertChain");
119
120 setKeyMaterial(ctx, keyCertChain, key, keyPassword);
121 } else {
122
123
124 if (keyManagerFactory == null) {
125 char[] keyPasswordChars = keyStorePassword(keyPassword);
126 KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
127 if (ks.aliases().hasMoreElements()) {
128 keyManagerFactory = new OpenSslX509KeyManagerFactory();
129 } else {
130 keyManagerFactory = new OpenSslCachingX509KeyManagerFactory(
131 KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
132 }
133 keyManagerFactory.init(ks, keyPasswordChars);
134 }
135 keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
136
137 SSLContext.setCertificateCallback(ctx, new OpenSslServerCertificateCallback(
138 engineMap, new OpenSslKeyMaterialManager(keyMaterialProvider)));
139 }
140 } catch (Exception e) {
141 throw new SSLException("failed to set certificate and key", e);
142 }
143 try {
144 if (trustCertCollection != null) {
145 trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
146 } else if (trustManagerFactory == null) {
147
148 trustManagerFactory = TrustManagerFactory.getInstance(
149 TrustManagerFactory.getDefaultAlgorithm());
150 trustManagerFactory.init((KeyStore) null);
151 }
152
153 final X509TrustManager manager = chooseTrustManager(
154 trustManagerFactory.getTrustManagers(), resumptionController);
155
156
157
158
159
160
161
162 setVerifyCallback(ctx, engineMap, manager);
163
164 X509Certificate[] issuers = manager.getAcceptedIssuers();
165 if (issuers != null && issuers.length > 0) {
166 long bio = 0;
167 try {
168 bio = toBIO(ByteBufAllocator.DEFAULT, issuers);
169 if (!SSLContext.setCACertificateBio(ctx, bio)) {
170 String msg = "unable to setup accepted issuers for trustmanager " + manager;
171 int error = SSL.getLastErrorNumber();
172 if (error != 0) {
173 msg += ". " + SSL.getErrorString(error);
174 }
175 throw new SSLException(msg);
176 }
177 } finally {
178 freeBio(bio);
179 }
180 }
181
182 if (PlatformDependent.javaVersion() >= 8) {
183
184
185
186
187 SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap));
188 }
189 } catch (SSLException e) {
190 throw e;
191 } catch (Exception e) {
192 throw new SSLException("unable to setup trustmanager", e);
193 }
194
195 OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider);
196 sessionContext.setSessionIdContext(ID);
197
198 sessionContext.setSessionCacheEnabled(SERVER_ENABLE_SESSION_CACHE);
199 if (sessionCacheSize > 0) {
200 sessionContext.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE));
201 }
202 if (sessionTimeout > 0) {
203 sessionContext.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE));
204 }
205
206 keyMaterialProvider = null;
207
208 return sessionContext;
209 } finally {
210 if (keyMaterialProvider != null) {
211 keyMaterialProvider.destroy();
212 }
213 }
214 }
215
216 @SuppressJava6Requirement(reason = "Guarded by java version check")
217 private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap, X509TrustManager manager) {
218
219 if (useExtendedTrustManager(manager)) {
220 SSLContext.setCertVerifyCallback(ctx, new ExtendedTrustManagerVerifyCallback(
221 engineMap, (X509ExtendedTrustManager) manager));
222 } else {
223 SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
224 }
225 }
226
227 private static final class OpenSslServerCertificateCallback implements CertificateCallback {
228 private final OpenSslEngineMap engineMap;
229 private final OpenSslKeyMaterialManager keyManagerHolder;
230
231 OpenSslServerCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
232 this.engineMap = engineMap;
233 this.keyManagerHolder = keyManagerHolder;
234 }
235
236 @Override
237 public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
238 final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
239 if (engine == null) {
240
241 return;
242 }
243 try {
244
245
246 keyManagerHolder.setKeyMaterialServerSide(engine);
247 } catch (Throwable cause) {
248 engine.initHandshakeException(cause);
249
250 if (cause instanceof Exception) {
251 throw (Exception) cause;
252 }
253 throw new SSLException(cause);
254 }
255 }
256 }
257
258 private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
259 private final X509TrustManager manager;
260
261 TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
262 super(engineMap);
263 this.manager = manager;
264 }
265
266 @Override
267 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
268 throws Exception {
269 manager.checkClientTrusted(peerCerts, auth);
270 }
271 }
272
273 @SuppressJava6Requirement(reason = "Usage guarded by java version check")
274 private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
275 private final X509ExtendedTrustManager manager;
276
277 ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
278 super(engineMap);
279 this.manager = manager;
280 }
281
282 @Override
283 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
284 throws Exception {
285 manager.checkClientTrusted(peerCerts, auth, engine);
286 }
287 }
288
289 private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher {
290 private final OpenSslEngineMap engineMap;
291
292 OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) {
293 this.engineMap = engineMap;
294 }
295
296 @Override
297 public boolean match(long ssl, String hostname) {
298 ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
299 if (engine != null) {
300
301 return engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8));
302 }
303 logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl);
304 return false;
305 }
306 }
307 }