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.util.internal.logging.InternalLogger;
19 import io.netty.util.internal.logging.InternalLoggerFactory;
20 import io.netty.internal.tcnative.CertificateRequestedCallback;
21 import io.netty.internal.tcnative.SSL;
22 import io.netty.internal.tcnative.SSLContext;
23
24 import java.security.KeyStore;
25 import java.security.PrivateKey;
26 import java.security.cert.X509Certificate;
27 import java.util.HashSet;
28 import java.util.Set;
29
30 import javax.net.ssl.KeyManagerFactory;
31 import javax.net.ssl.SSLException;
32 import javax.net.ssl.SSLHandshakeException;
33 import javax.net.ssl.TrustManagerFactory;
34 import javax.net.ssl.X509ExtendedKeyManager;
35 import javax.net.ssl.X509ExtendedTrustManager;
36 import javax.net.ssl.X509KeyManager;
37 import javax.net.ssl.X509TrustManager;
38 import javax.security.auth.x500.X500Principal;
39
40
41
42
43
44
45
46
47
48 public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext {
49 private static final InternalLogger logger =
50 InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class);
51 private final OpenSslSessionContext sessionContext;
52
53 ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
54 X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
55 KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
56 CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
57 String[] protocols, long sessionCacheSize, long sessionTimeout,
58 boolean enableOcsp) throws SSLException {
59 super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
60 ClientAuth.NONE, protocols, false, enableOcsp, true);
61 boolean success = false;
62 try {
63 sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
64 keyCertChain, key, keyPassword, keyManagerFactory);
65 success = true;
66 } finally {
67 if (!success) {
68 release();
69 }
70 }
71 }
72
73 @Override
74 OpenSslKeyMaterialManager keyMaterialManager() {
75 return null;
76 }
77
78 @Override
79 public OpenSslSessionContext sessionContext() {
80 return sessionContext;
81 }
82
83 static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
84 OpenSslEngineMap engineMap,
85 X509Certificate[] trustCertCollection,
86 TrustManagerFactory trustManagerFactory,
87 X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
88 KeyManagerFactory keyManagerFactory) throws SSLException {
89 if (key == null && keyCertChain != null || key != null && keyCertChain == null) {
90 throw new IllegalArgumentException(
91 "Either both keyCertChain and key needs to be null or none of them");
92 }
93 try {
94 if (!OpenSsl.useKeyManagerFactory()) {
95 if (keyManagerFactory != null) {
96 throw new IllegalArgumentException(
97 "KeyManagerFactory not supported");
98 }
99 if (keyCertChain != null
100 setKeyMaterial(ctx, keyCertChain, key, keyPassword);
101 }
102 } else {
103
104 if (keyManagerFactory == null && keyCertChain != null) {
105 keyManagerFactory = buildKeyManagerFactory(
106 keyCertChain, key, keyPassword, keyManagerFactory);
107 }
108
109 if (keyManagerFactory != null) {
110 X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers());
111 OpenSslKeyMaterialManager materialManager = useExtendedKeyManager(keyManager) ?
112 new OpenSslExtendedKeyMaterialManager(
113 (X509ExtendedKeyManager) keyManager, keyPassword) :
114 new OpenSslKeyMaterialManager(keyManager, keyPassword);
115 SSLContext.setCertRequestedCallback(ctx, new OpenSslCertificateRequestedCallback(
116 engineMap, materialManager));
117 }
118 }
119 } catch (Exception e) {
120 throw new SSLException("failed to set certificate and key", e);
121 }
122
123 SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
124
125 try {
126 if (trustCertCollection != null) {
127 trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory);
128 } else if (trustManagerFactory == null) {
129 trustManagerFactory = TrustManagerFactory.getInstance(
130 TrustManagerFactory.getDefaultAlgorithm());
131 trustManagerFactory.init((KeyStore) null);
132 }
133 final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
134
135
136
137
138
139
140
141
142 if (useExtendedTrustManager(manager)) {
143 SSLContext.setCertVerifyCallback(ctx,
144 new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager));
145 } else {
146 SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
147 }
148 } catch (Exception e) {
149 throw new SSLException("unable to setup trustmanager", e);
150 }
151 return new OpenSslClientSessionContext(thiz);
152 }
153
154
155 static final class OpenSslClientSessionContext extends OpenSslSessionContext {
156 OpenSslClientSessionContext(ReferenceCountedOpenSslContext context) {
157 super(context);
158 }
159
160 @Override
161 public void setSessionTimeout(int seconds) {
162 if (seconds < 0) {
163 throw new IllegalArgumentException();
164 }
165 }
166
167 @Override
168 public int getSessionTimeout() {
169 return 0;
170 }
171
172 @Override
173 public void setSessionCacheSize(int size) {
174 if (size < 0) {
175 throw new IllegalArgumentException();
176 }
177 }
178
179 @Override
180 public int getSessionCacheSize() {
181 return 0;
182 }
183
184 @Override
185 public void setSessionCacheEnabled(boolean enabled) {
186
187 }
188
189 @Override
190 public boolean isSessionCacheEnabled() {
191 return false;
192 }
193 }
194
195 private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
196 private final X509TrustManager manager;
197
198 TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
199 super(engineMap);
200 this.manager = manager;
201 }
202
203 @Override
204 void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
205 throws Exception {
206 manager.checkServerTrusted(peerCerts, auth);
207 }
208 }
209
210 private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
211 private final X509ExtendedTrustManager manager;
212
213 ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager 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, engine);
222 }
223 }
224
225 private static final class OpenSslCertificateRequestedCallback implements CertificateRequestedCallback {
226 private final OpenSslEngineMap engineMap;
227 private final OpenSslKeyMaterialManager keyManagerHolder;
228
229 OpenSslCertificateRequestedCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
230 this.engineMap = engineMap;
231 this.keyManagerHolder = keyManagerHolder;
232 }
233
234 @Override
235 public KeyMaterial requested(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) {
236 final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
237 try {
238 final Set<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes);
239 final String[] keyTypes = keyTypesSet.toArray(new String[keyTypesSet.size()]);
240 final X500Principal[] issuers;
241 if (asn1DerEncodedPrincipals == null) {
242 issuers = null;
243 } else {
244 issuers = new X500Principal[asn1DerEncodedPrincipals.length];
245 for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
246 issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
247 }
248 }
249 return keyManagerHolder.keyMaterial(engine, keyTypes, issuers);
250 } catch (Throwable cause) {
251 logger.debug("request of key failed", cause);
252 SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem");
253 e.initCause(cause);
254 engine.handshakeException = e;
255 return null;
256 }
257 }
258
259
260
261
262
263
264
265
266
267 private static Set<String> supportedClientKeyTypes(byte[] clientCertificateTypes) {
268 Set<String> result = new HashSet<String>(clientCertificateTypes.length);
269 for (byte keyTypeCode : clientCertificateTypes) {
270 String keyType = clientKeyType(keyTypeCode);
271 if (keyType == null) {
272
273 continue;
274 }
275 result.add(keyType);
276 }
277 return result;
278 }
279
280 private static String clientKeyType(byte clientCertificateType) {
281
282 switch (clientCertificateType) {
283 case CertificateRequestedCallback.TLS_CT_RSA_SIGN:
284 return OpenSslKeyMaterialManager.KEY_TYPE_RSA;
285 case CertificateRequestedCallback.TLS_CT_RSA_FIXED_DH:
286 return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA;
287 case CertificateRequestedCallback.TLS_CT_ECDSA_SIGN:
288 return OpenSslKeyMaterialManager.KEY_TYPE_EC;
289 case CertificateRequestedCallback.TLS_CT_RSA_FIXED_ECDH:
290 return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA;
291 case CertificateRequestedCallback.TLS_CT_ECDSA_FIXED_ECDH:
292 return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC;
293 default:
294 return null;
295 }
296 }
297 }
298 }