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 }