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