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.internal.tcnative.CertificateCallback;
19 import io.netty.internal.tcnative.SSL;
20 import io.netty.internal.tcnative.SSLContext;
21 import io.netty.util.internal.EmptyArrays;
22
23 import javax.net.ssl.KeyManagerFactory;
24 import javax.net.ssl.SNIServerName;
25 import javax.net.ssl.SSLException;
26 import javax.net.ssl.TrustManagerFactory;
27 import javax.net.ssl.X509ExtendedTrustManager;
28 import javax.net.ssl.X509TrustManager;
29 import javax.security.auth.x500.X500Principal;
30 import java.security.KeyStore;
31 import java.security.PrivateKey;
32 import java.security.cert.X509Certificate;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37
38
39
40
41
42
43
44
45
46 public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext {
47
48 private static final String[] SUPPORTED_KEY_TYPES = {
49 OpenSslKeyMaterialManager.KEY_TYPE_RSA,
50 OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA,
51 OpenSslKeyMaterialManager.KEY_TYPE_EC,
52 OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA,
53 OpenSslKeyMaterialManager.KEY_TYPE_EC_EC
54 };
55
56 private final OpenSslSessionContext sessionContext;
57
58 ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
59 X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
60 KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
61 CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
62 String[] protocols, long sessionCacheSize, long sessionTimeout,
63 boolean enableOcsp, String keyStore, String endpointIdentificationAlgorithm,
64 List<SNIServerName> serverNames,
65 ResumptionController resumptionController,
66 Map.Entry<SslContextOption<?>, Object>[] options,
67 List<OpenSslCredential> credentials) throws SSLException {
68 this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
69 cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, false, enableOcsp, keyStore,
70 endpointIdentificationAlgorithm, serverNames, resumptionController, options, credentials);
71 }
72
73 ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
74 X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
75 KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
76 CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
77 String[] protocols, long sessionCacheSize, long sessionTimeout,
78 boolean startTls, boolean enableOcsp, String keyStore,
79 String endpointIdentificationAlgorithm, List<SNIServerName> serverNames,
80 ResumptionController resumptionController,
81 Map.Entry<SslContextOption<?>, Object>[] options,
82 List<OpenSslCredential> credentials) throws SSLException {
83 super(ciphers, cipherFilter, toNegotiator(apn), SSL.SSL_MODE_CLIENT, keyCertChain,
84 ClientAuth.NONE, protocols, startTls, endpointIdentificationAlgorithm, enableOcsp, true,
85 serverNames, resumptionController, options, credentials);
86 boolean success = false;
87 try {
88 sessionContext = newSessionContext(this, ctx, engines, trustCertCollection, trustManagerFactory,
89 keyCertChain, key, keyPassword, keyManagerFactory, keyStore,
90 sessionCacheSize, sessionTimeout, resumptionController,
91 isJdkSignatureFallbackEnabled(options));
92 success = true;
93 } finally {
94 if (!success) {
95 release();
96 }
97 }
98 }
99
100 @Override
101 public OpenSslSessionContext sessionContext() {
102 return sessionContext;
103 }
104
105 static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
106 Map<Long, ReferenceCountedOpenSslEngine> engines,
107 X509Certificate[] trustCertCollection,
108 TrustManagerFactory trustManagerFactory,
109 X509Certificate[] keyCertChain, PrivateKey key,
110 String keyPassword, KeyManagerFactory keyManagerFactory,
111 String keyStore, long sessionCacheSize, long sessionTimeout,
112 ResumptionController resumptionController,
113 boolean fallbackToJdkProviders)
114 throws SSLException {
115 if (key == null && keyCertChain != null || key != null && keyCertChain == null) {
116 throw new IllegalArgumentException(
117 "Either both keyCertChain and key needs to be null or none of them");
118 }
119 OpenSslKeyMaterialProvider keyMaterialProvider = null;
120 try {
121 try {
122
123
124 if (keyManagerFactory == null && key != null && key.getEncoded() == null) {
125 if (!fallbackToJdkProviders) {
126 throw new SSLException("Private key requiring alternative signature provider detected " +
127 "(such as hardware security key, smart card, or remote signing service) but " +
128 "alternative key fallback is disabled.");
129 }
130 keyMaterialProvider = setupSecurityProviderSignatureSource(thiz, ctx, keyCertChain, key,
131 materialManager -> new OpenSslClientCertificateCallback(
132 engines, materialManager));
133 } else if (!OpenSsl.useKeyManagerFactory()) {
134 if (keyManagerFactory != null) {
135 throw new IllegalArgumentException(
136 "KeyManagerFactory not supported");
137 }
138 if (keyCertChain != null) {
139 setKeyMaterial(ctx, keyCertChain, key, keyPassword);
140 }
141 } else {
142
143 if (keyManagerFactory == null && keyCertChain != null) {
144 keyManagerFactory = certChainToKeyManagerFactory(keyCertChain, key, keyPassword, keyStore);
145 }
146 if (keyManagerFactory != null) {
147 keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
148 }
149
150 if (keyMaterialProvider != null) {
151 OpenSslKeyMaterialManager materialManager =
152 new OpenSslKeyMaterialManager(keyMaterialProvider, thiz.hasTmpDhKeys);
153 SSLContext.setCertificateCallback(ctx, new OpenSslClientCertificateCallback(
154 engines, materialManager));
155 }
156 }
157 } catch (Exception e) {
158 throw new SSLException("failed to set certificate and key", e);
159 }
160
161
162
163
164
165
166
167 SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_OPTIONAL, VERIFY_DEPTH);
168
169 try {
170 if (trustCertCollection != null) {
171 trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
172 } else if (trustManagerFactory == null) {
173 trustManagerFactory = TrustManagerFactory.getInstance(
174 TrustManagerFactory.getDefaultAlgorithm());
175 trustManagerFactory.init((KeyStore) null);
176 }
177 final X509TrustManager manager = chooseTrustManager(
178 trustManagerFactory.getTrustManagers(), resumptionController);
179
180
181
182
183
184
185
186 setVerifyCallback(ctx, engines, manager);
187 } catch (Exception e) {
188 if (keyMaterialProvider != null) {
189 keyMaterialProvider.destroy();
190 }
191 throw new SSLException("unable to setup trustmanager", e);
192 }
193 OpenSslClientSessionContext context = new OpenSslClientSessionContext(thiz, keyMaterialProvider);
194 context.setSessionCacheEnabled(CLIENT_ENABLE_SESSION_CACHE);
195 if (sessionCacheSize > 0) {
196 context.setSessionCacheSize((int) Math.min(sessionCacheSize, Integer.MAX_VALUE));
197 }
198 if (sessionTimeout > 0) {
199 context.setSessionTimeout((int) Math.min(sessionTimeout, Integer.MAX_VALUE));
200 }
201
202 if (CLIENT_ENABLE_SESSION_TICKET) {
203 context.setTicketKeys();
204 }
205
206 keyMaterialProvider = null;
207 return context;
208 } finally {
209 if (keyMaterialProvider != null) {
210 keyMaterialProvider.destroy();
211 }
212 }
213 }
214
215 private static void setVerifyCallback(long ctx,
216 Map<Long, ReferenceCountedOpenSslEngine> engines,
217 X509TrustManager manager) {
218
219 if (useExtendedTrustManager(manager)) {
220 SSLContext.setCertVerifyCallback(ctx,
221 new ExtendedTrustManagerVerifyCallback(engines, (X509ExtendedTrustManager) manager));
222 } else {
223 SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engines, manager));
224 }
225 }
226
227 static final class OpenSslClientSessionContext extends OpenSslSessionContext {
228 OpenSslClientSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) {
229 super(context, provider, SSL.SSL_SESS_CACHE_CLIENT, new OpenSslClientSessionCache(context.engines));
230 }
231 }
232
233 private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
234 private final X509TrustManager manager;
235
236 TrustManagerVerifyCallback(Map<Long, ReferenceCountedOpenSslEngine> engines, X509TrustManager manager) {
237 super(engines);
238 this.manager = manager;
239 }
240
241 @Override
242 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
243 throws Exception {
244 manager.checkServerTrusted(peerCerts, auth);
245 }
246 }
247
248 private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
249 private final X509ExtendedTrustManager manager;
250
251 ExtendedTrustManagerVerifyCallback(Map<Long, ReferenceCountedOpenSslEngine> engines,
252 X509ExtendedTrustManager manager) {
253 super(engines);
254 this.manager = manager;
255 }
256
257 @Override
258 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
259 throws Exception {
260 manager.checkServerTrusted(peerCerts, auth, engine);
261 }
262 }
263
264 private static final class OpenSslClientCertificateCallback implements CertificateCallback {
265 private final Map<Long, ReferenceCountedOpenSslEngine> engines;
266 private final OpenSslKeyMaterialManager keyManagerHolder;
267
268 OpenSslClientCertificateCallback(Map<Long, ReferenceCountedOpenSslEngine> engines,
269 OpenSslKeyMaterialManager keyManagerHolder) {
270 this.engines = engines;
271 this.keyManagerHolder = keyManagerHolder;
272 }
273
274 @Override
275 public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
276 final ReferenceCountedOpenSslEngine engine = engines.get(ssl);
277
278 if (engine == null) {
279 return;
280 }
281 try {
282 final String[] keyTypes = supportedClientKeyTypes(keyTypeBytes);
283 final X500Principal[] issuers;
284 if (asn1DerEncodedPrincipals == null) {
285 issuers = null;
286 } else {
287 issuers = new X500Principal[asn1DerEncodedPrincipals.length];
288 for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
289 issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
290 }
291 }
292 keyManagerHolder.setKeyMaterialClientSide(engine, keyTypes, issuers);
293 } catch (Throwable cause) {
294 engine.initHandshakeException(cause);
295 if (cause instanceof Exception) {
296 throw (Exception) cause;
297 }
298 throw new SSLException(cause);
299 }
300 }
301
302
303
304
305
306
307
308
309
310 private static String[] supportedClientKeyTypes(byte[] clientCertificateTypes) {
311 if (clientCertificateTypes == null) {
312
313 return SUPPORTED_KEY_TYPES.clone();
314 }
315 Set<String> result = new HashSet<>(clientCertificateTypes.length);
316 for (byte keyTypeCode : clientCertificateTypes) {
317 String keyType = clientKeyType(keyTypeCode);
318 if (keyType == null) {
319
320 continue;
321 }
322 result.add(keyType);
323 }
324 return result.toArray(EmptyArrays.EMPTY_STRINGS);
325 }
326
327 private static String clientKeyType(byte clientCertificateType) {
328
329 switch (clientCertificateType) {
330 case CertificateCallback.TLS_CT_RSA_SIGN:
331 return OpenSslKeyMaterialManager.KEY_TYPE_RSA;
332 case CertificateCallback.TLS_CT_RSA_FIXED_DH:
333 return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA;
334 case CertificateCallback.TLS_CT_ECDSA_SIGN:
335 return OpenSslKeyMaterialManager.KEY_TYPE_EC;
336 case CertificateCallback.TLS_CT_RSA_FIXED_ECDH:
337 return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA;
338 case CertificateCallback.TLS_CT_ECDSA_FIXED_ECDH:
339 return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC;
340 default:
341 return null;
342 }
343 }
344 }
345 }