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.EmptyArrays;
19 import io.netty.util.internal.PlatformDependent;
20 import io.netty.util.internal.SuppressJava6Requirement;
21 import io.netty.util.internal.logging.InternalLogger;
22 import io.netty.util.internal.logging.InternalLoggerFactory;
23
24 import javax.net.ssl.SSLContext;
25 import javax.net.ssl.TrustManager;
26 import javax.net.ssl.X509ExtendedTrustManager;
27 import javax.net.ssl.X509TrustManager;
28 import java.lang.reflect.Field;
29 import java.security.AccessController;
30 import java.security.KeyManagementException;
31 import java.security.NoSuchAlgorithmException;
32 import java.security.NoSuchProviderException;
33 import java.security.PrivilegedAction;
34 import java.security.cert.CertificateException;
35 import java.security.cert.X509Certificate;
36
37
38
39
40
41
42
43
44 @SuppressJava6Requirement(reason = "Usage guarded by java version check")
45 final class OpenSslX509TrustManagerWrapper {
46 private static final InternalLogger LOGGER = InternalLoggerFactory
47 .getInstance(OpenSslX509TrustManagerWrapper.class);
48 private static final TrustManagerWrapper WRAPPER;
49
50 private static final TrustManagerWrapper DEFAULT = new TrustManagerWrapper() {
51 @Override
52 public X509TrustManager wrapIfNeeded(X509TrustManager manager) {
53 return manager;
54 }
55 };
56
57 static {
58
59 TrustManagerWrapper wrapper = DEFAULT;
60
61 Throwable cause = null;
62 Throwable unsafeCause = PlatformDependent.getUnsafeUnavailabilityCause();
63 if (unsafeCause == null) {
64 SSLContext context;
65 try {
66 context = newSSLContext();
67
68
69
70
71
72
73
74 context.init(null, new TrustManager[] {
75 new X509TrustManager() {
76 @Override
77 public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
78 throws CertificateException {
79 throw new CertificateException();
80 }
81
82 @Override
83 public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
84 throws CertificateException {
85 throw new CertificateException();
86 }
87
88 @Override
89 public X509Certificate[] getAcceptedIssuers() {
90 return EmptyArrays.EMPTY_X509_CERTIFICATES;
91 }
92 }
93 }, null);
94 } catch (Throwable error) {
95 context = null;
96 cause = error;
97 }
98 if (cause != null) {
99 LOGGER.debug("Unable to access wrapped TrustManager", cause);
100 } else {
101 final SSLContext finalContext = context;
102 Object maybeWrapper = AccessController.doPrivileged(new PrivilegedAction<Object>() {
103 @Override
104 public Object run() {
105 try {
106 Field contextSpiField = SSLContext.class.getDeclaredField("contextSpi");
107 final long spiOffset = PlatformDependent.objectFieldOffset(contextSpiField);
108 Object spi = PlatformDependent.getObject(finalContext, spiOffset);
109 if (spi != null) {
110 Class<?> clazz = spi.getClass();
111
112
113
114 do {
115 try {
116 Field trustManagerField = clazz.getDeclaredField("trustManager");
117 final long tmOffset = PlatformDependent.objectFieldOffset(trustManagerField);
118 Object trustManager = PlatformDependent.getObject(spi, tmOffset);
119 if (trustManager instanceof X509ExtendedTrustManager) {
120 return new UnsafeTrustManagerWrapper(spiOffset, tmOffset);
121 }
122 } catch (NoSuchFieldException ignore) {
123
124 }
125 clazz = clazz.getSuperclass();
126 } while (clazz != null);
127 }
128 throw new NoSuchFieldException();
129 } catch (NoSuchFieldException e) {
130 return e;
131 } catch (SecurityException e) {
132 return e;
133 }
134 }
135 });
136 if (maybeWrapper instanceof Throwable) {
137 LOGGER.debug("Unable to access wrapped TrustManager", (Throwable) maybeWrapper);
138 } else {
139 wrapper = (TrustManagerWrapper) maybeWrapper;
140 }
141 }
142 } else {
143 LOGGER.debug("Unable to access wrapped TrustManager", cause);
144 }
145 WRAPPER = wrapper;
146 }
147
148 static boolean isWrappingSupported() {
149 return WRAPPER != DEFAULT;
150 }
151
152 private OpenSslX509TrustManagerWrapper() { }
153
154 static X509TrustManager wrapIfNeeded(X509TrustManager trustManager) {
155 return WRAPPER.wrapIfNeeded(trustManager);
156 }
157
158 private interface TrustManagerWrapper {
159 X509TrustManager wrapIfNeeded(X509TrustManager manager);
160 }
161
162 private static SSLContext newSSLContext() throws NoSuchAlgorithmException, NoSuchProviderException {
163
164
165 return SSLContext.getInstance("TLS", "SunJSSE");
166 }
167
168 private static final class UnsafeTrustManagerWrapper implements TrustManagerWrapper {
169 private final long spiOffset;
170 private final long tmOffset;
171
172 UnsafeTrustManagerWrapper(long spiOffset, long tmOffset) {
173 this.spiOffset = spiOffset;
174 this.tmOffset = tmOffset;
175 }
176
177 @SuppressJava6Requirement(reason = "Usage guarded by java version check")
178 @Override
179 public X509TrustManager wrapIfNeeded(X509TrustManager manager) {
180 if (!(manager instanceof X509ExtendedTrustManager)) {
181 try {
182 SSLContext ctx = newSSLContext();
183 ctx.init(null, new TrustManager[] { manager }, null);
184 Object spi = PlatformDependent.getObject(ctx, spiOffset);
185 if (spi != null) {
186 Object tm = PlatformDependent.getObject(spi, tmOffset);
187 if (tm instanceof X509ExtendedTrustManager) {
188 return (X509TrustManager) tm;
189 }
190 }
191 } catch (NoSuchAlgorithmException e) {
192
193
194 PlatformDependent.throwException(e);
195 } catch (KeyManagementException e) {
196
197
198 PlatformDependent.throwException(e);
199 } catch (NoSuchProviderException e) {
200
201
202 PlatformDependent.throwException(e);
203 }
204 }
205 return manager;
206 }
207 }
208 }