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