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.logging.InternalLogger;
21 import io.netty.util.internal.logging.InternalLoggerFactory;
22
23 import java.lang.reflect.Field;
24 import java.security.AccessController;
25 import java.security.KeyManagementException;
26 import java.security.NoSuchAlgorithmException;
27 import java.security.NoSuchProviderException;
28 import java.security.PrivilegedAction;
29 import java.security.cert.CertificateException;
30 import java.security.cert.X509Certificate;
31 import javax.net.ssl.SSLContext;
32 import javax.net.ssl.TrustManager;
33 import javax.net.ssl.X509ExtendedTrustManager;
34 import javax.net.ssl.X509TrustManager;
35
36
37
38
39
40
41
42
43 final class OpenSslX509TrustManagerWrapper {
44 private static final InternalLogger LOGGER = InternalLoggerFactory
45 .getInstance(OpenSslX509TrustManagerWrapper.class);
46 private static final TrustManagerWrapper WRAPPER;
47
48 private static final TrustManagerWrapper DEFAULT = new TrustManagerWrapper() {
49 @Override
50 public X509TrustManager wrapIfNeeded(X509TrustManager manager) {
51 return manager;
52 }
53 };
54
55 static {
56
57 TrustManagerWrapper wrapper = DEFAULT;
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 | SecurityException e) {
128 return e;
129 }
130 }
131 });
132 if (maybeWrapper instanceof Throwable) {
133 LOGGER.debug("Unable to access wrapped TrustManager", (Throwable) maybeWrapper);
134 } else {
135 wrapper = (TrustManagerWrapper) maybeWrapper;
136 }
137 }
138 } else {
139 LOGGER.debug("Unable to access wrapped TrustManager", cause);
140 }
141 WRAPPER = wrapper;
142 }
143
144 static boolean isWrappingSupported() {
145 return WRAPPER != DEFAULT;
146 }
147
148 private OpenSslX509TrustManagerWrapper() { }
149
150 static X509TrustManager wrapIfNeeded(X509TrustManager trustManager) {
151 return WRAPPER.wrapIfNeeded(trustManager);
152 }
153
154 private interface TrustManagerWrapper {
155 X509TrustManager wrapIfNeeded(X509TrustManager manager);
156 }
157
158 private static SSLContext newSSLContext() throws NoSuchAlgorithmException, NoSuchProviderException {
159
160
161 return SSLContext.getInstance("TLS", "SunJSSE");
162 }
163
164 private static final class UnsafeTrustManagerWrapper implements TrustManagerWrapper {
165 private final long spiOffset;
166 private final long tmOffset;
167
168 UnsafeTrustManagerWrapper(long spiOffset, long tmOffset) {
169 this.spiOffset = spiOffset;
170 this.tmOffset = tmOffset;
171 }
172
173 @Override
174 public X509TrustManager wrapIfNeeded(X509TrustManager manager) {
175 if (!(manager instanceof X509ExtendedTrustManager)) {
176 try {
177 SSLContext ctx = newSSLContext();
178 ctx.init(null, new TrustManager[] { manager }, null);
179 Object spi = PlatformDependent.getObject(ctx, spiOffset);
180 if (spi != null) {
181 Object tm = PlatformDependent.getObject(spi, tmOffset);
182 if (tm instanceof X509ExtendedTrustManager) {
183 return (X509TrustManager) tm;
184 }
185 }
186 } catch (NoSuchAlgorithmException | NoSuchProviderException | KeyManagementException e) {
187
188
189 PlatformDependent.throwException(e);
190 }
191 }
192 return manager;
193 }
194 }
195 }