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