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