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