1 /* 2 * Copyright 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.conscrypt; 18 19 import static android.system.OsConstants.SOL_SOCKET; 20 import static android.system.OsConstants.SO_SNDTIMEO; 21 22 import android.system.ErrnoException; 23 import android.system.Os; 24 import android.system.StructTimeval; 25 import dalvik.system.BlockGuard; 26 import dalvik.system.CloseGuard; 27 import java.io.FileDescriptor; 28 import java.lang.reflect.Field; 29 import java.lang.reflect.InvocationTargetException; 30 import java.lang.reflect.Method; 31 import java.net.InetAddress; 32 import java.net.InetSocketAddress; 33 import java.net.Socket; 34 import java.net.SocketException; 35 import java.net.SocketImpl; 36 import java.security.NoSuchAlgorithmException; 37 import java.security.PrivateKey; 38 import java.security.cert.CertificateException; 39 import java.security.cert.X509Certificate; 40 import java.security.spec.AlgorithmParameterSpec; 41 import java.security.spec.ECParameterSpec; 42 import java.util.Collections; 43 import java.util.List; 44 import javax.crypto.spec.GCMParameterSpec; 45 import javax.net.ssl.SNIHostName; 46 import javax.net.ssl.SNIServerName; 47 import javax.net.ssl.SSLEngine; 48 import javax.net.ssl.SSLParameters; 49 import javax.net.ssl.SSLSession; 50 import javax.net.ssl.SSLSocketFactory; 51 import javax.net.ssl.StandardConstants; 52 import javax.net.ssl.X509ExtendedTrustManager; 53 import javax.net.ssl.X509TrustManager; 54 import libcore.net.NetworkSecurityPolicy; 55 import sun.security.x509.AlgorithmId; 56 57 class Platform { 58 private static class NoPreloadHolder { 59 public static final Platform MAPPER = new Platform(); 60 } 61 62 /** 63 * Runs all the setup for the platform that only needs to run once. 64 */ 65 public static void setup() { 66 NoPreloadHolder.MAPPER.ping(); 67 } 68 69 /** 70 * Just a placeholder to make sure the class is initialized. 71 */ 72 private void ping() { 73 } 74 75 private Platform() { 76 } 77 78 public static FileDescriptor getFileDescriptor(Socket s) { 79 return s.getFileDescriptor$(); 80 } 81 82 public static FileDescriptor getFileDescriptorFromSSLSocket(OpenSSLSocketImpl openSSLSocketImpl) { 83 try { 84 Field f_impl = Socket.class.getDeclaredField("impl"); 85 f_impl.setAccessible(true); 86 Object socketImpl = f_impl.get(openSSLSocketImpl); 87 Field f_fd = SocketImpl.class.getDeclaredField("fd"); 88 f_fd.setAccessible(true); 89 return (FileDescriptor) f_fd.get(socketImpl); 90 } catch (Exception e) { 91 throw new RuntimeException("Can't get FileDescriptor from socket", e); 92 } 93 } 94 95 public static String getCurveName(ECParameterSpec spec) { 96 return spec.getCurveName(); 97 } 98 99 public static void setCurveName(ECParameterSpec spec, String curveName) { 100 spec.setCurveName(curveName); 101 } 102 103 public static void setSocketWriteTimeout(Socket s, long timeoutMillis) throws SocketException { 104 StructTimeval tv = StructTimeval.fromMillis(timeoutMillis); 105 try { 106 Os.setsockoptTimeval(s.getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv); 107 } catch (ErrnoException errnoException) { 108 throw errnoException.rethrowAsSocketException(); 109 } 110 } 111 112 public static void setSSLParameters(SSLParameters params, SSLParametersImpl impl, 113 OpenSSLSocketImpl socket) { 114 impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); 115 impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); 116 List<SNIServerName> serverNames = params.getServerNames(); 117 if (serverNames != null) { 118 for (SNIServerName serverName : serverNames) { 119 if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { 120 socket.setHostname(((SNIHostName) serverName).getAsciiName()); 121 break; 122 } 123 } 124 } 125 } 126 127 public static void getSSLParameters(SSLParameters params, SSLParametersImpl impl, 128 OpenSSLSocketImpl socket) { 129 params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); 130 params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); 131 if (impl.getUseSni() && AddressUtils.isValidSniHostname(socket.getHostname())) { 132 params.setServerNames(Collections.<SNIServerName> singletonList( 133 new SNIHostName(socket.getHostname()))); 134 } 135 } 136 137 public static void setSSLParameters( 138 SSLParameters params, SSLParametersImpl impl, OpenSSLEngineImpl engine) { 139 impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); 140 impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); 141 List<SNIServerName> serverNames = params.getServerNames(); 142 if (serverNames != null) { 143 for (SNIServerName serverName : serverNames) { 144 if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { 145 engine.setSniHostname(((SNIHostName) serverName).getAsciiName()); 146 break; 147 } 148 } 149 } 150 } 151 152 public static void getSSLParameters( 153 SSLParameters params, SSLParametersImpl impl, OpenSSLEngineImpl engine) { 154 params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); 155 params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); 156 if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getSniHostname())) { 157 params.setServerNames(Collections.<SNIServerName>singletonList( 158 new SNIHostName(engine.getSniHostname()))); 159 } 160 } 161 162 /** 163 * Helper function to unify calls to the different names used for each function taking a 164 * Socket, SSLEngine, or String (legacy Android). 165 */ 166 private static boolean checkTrusted(String methodName, X509TrustManager tm, 167 X509Certificate[] chain, String authType, Class<?> argumentClass, 168 Object argumentInstance) throws CertificateException { 169 // Use duck-typing to try and call the hostname-aware method if available. 170 try { 171 Method method = tm.getClass().getMethod(methodName, 172 X509Certificate[].class, 173 String.class, 174 argumentClass); 175 method.invoke(tm, chain, authType, argumentInstance); 176 return true; 177 } catch (NoSuchMethodException | IllegalAccessException ignored) { 178 } catch (InvocationTargetException e) { 179 if (e.getCause() instanceof CertificateException) { 180 throw (CertificateException) e.getCause(); 181 } 182 throw new RuntimeException(e.getCause()); 183 } 184 return false; 185 } 186 187 public static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, 188 String authType, OpenSSLSocketImpl socket) throws CertificateException { 189 if (tm instanceof X509ExtendedTrustManager) { 190 X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; 191 x509etm.checkClientTrusted(chain, authType, socket); 192 } else if (!checkTrusted("checkClientTrusted", tm, chain, authType, Socket.class, socket) 193 && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, 194 socket.getHandshakeSession().getPeerHost())) { 195 tm.checkClientTrusted(chain, authType); 196 } 197 } 198 199 public static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, 200 String authType, OpenSSLSocketImpl socket) throws CertificateException { 201 if (tm instanceof X509ExtendedTrustManager) { 202 X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; 203 x509etm.checkServerTrusted(chain, authType, socket); 204 } else if (!checkTrusted("checkServerTrusted", tm, chain, authType, Socket.class, socket) 205 && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, 206 socket.getHandshakeSession().getPeerHost())) { 207 tm.checkServerTrusted(chain, authType); 208 } 209 } 210 211 public static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, 212 String authType, OpenSSLEngineImpl engine) throws CertificateException { 213 if (tm instanceof X509ExtendedTrustManager) { 214 X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; 215 x509etm.checkClientTrusted(chain, authType, engine); 216 } else if (!checkTrusted("checkClientTrusted", tm, chain, authType, SSLEngine.class, engine) 217 && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, 218 engine.getHandshakeSession().getPeerHost())) { 219 tm.checkClientTrusted(chain, authType); 220 } 221 } 222 223 public static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, 224 String authType, OpenSSLEngineImpl engine) throws CertificateException { 225 if (tm instanceof X509ExtendedTrustManager) { 226 X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; 227 x509etm.checkServerTrusted(chain, authType, engine); 228 } else if (!checkTrusted("checkServerTrusted", tm, chain, authType, SSLEngine.class, engine) 229 && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, 230 engine.getHandshakeSession().getPeerHost())) { 231 tm.checkServerTrusted(chain, authType); 232 } 233 } 234 235 /** 236 * Wraps an old AndroidOpenSSL key instance. This is not needed on platform 237 * builds since we didn't backport, so return null. 238 */ 239 public static OpenSSLKey wrapRsaKey(PrivateKey key) { 240 return null; 241 } 242 243 /** 244 * Logs to the system EventLog system. 245 */ 246 public static void logEvent(String message) { 247 try { 248 Class processClass = Class.forName("android.os.Process"); 249 Object processInstance = processClass.newInstance(); 250 Method myUidMethod = processClass.getMethod("myUid", (Class[]) null); 251 int uid = (Integer) myUidMethod.invoke(processInstance); 252 253 Class eventLogClass = Class.forName("android.util.EventLog"); 254 Object eventLogInstance = eventLogClass.newInstance(); 255 Method writeEventMethod = eventLogClass.getMethod("writeEvent", 256 new Class[] { Integer.TYPE, Object[].class }); 257 writeEventMethod.invoke(eventLogInstance, 0x534e4554 /* SNET */, 258 new Object[] { "conscrypt", uid, message }); 259 } catch (Exception e) { 260 // Do not log and fail silently 261 } 262 } 263 264 /** 265 * Returns true if the supplied hostname is an literal IP address. 266 */ 267 public static boolean isLiteralIpAddress(String hostname) { 268 return InetAddress.isNumeric(hostname); 269 } 270 271 /** 272 * Wrap the SocketFactory with the platform wrapper if needed for compatability. 273 * For the platform-bundled library we never need to wrap. 274 */ 275 public static SSLSocketFactory wrapSocketFactoryIfNeeded(OpenSSLSocketFactoryImpl factory) { 276 return factory; 277 } 278 279 /** 280 * Convert from platform's GCMParameterSpec to our internal version. 281 */ 282 public static GCMParameters fromGCMParameterSpec(AlgorithmParameterSpec params) { 283 if (params instanceof GCMParameterSpec) { 284 GCMParameterSpec gcmParams = (GCMParameterSpec) params; 285 return new GCMParameters(gcmParams.getTLen(), gcmParams.getIV()); 286 } 287 return null; 288 } 289 290 /** 291 * Creates a platform version of {@code GCMParameterSpec}. 292 */ 293 public static AlgorithmParameterSpec toGCMParameterSpec(int tagLenInBits, byte[] iv) { 294 return new GCMParameterSpec(tagLenInBits, iv); 295 } 296 297 /* 298 * CloseGuard functions. 299 */ 300 301 public static CloseGuard closeGuardGet() { 302 return CloseGuard.get(); 303 } 304 305 public static void closeGuardOpen(Object guardObj, String message) { 306 CloseGuard guard = (CloseGuard) guardObj; 307 guard.open(message); 308 } 309 310 public static void closeGuardClose(Object guardObj) { 311 CloseGuard guard = (CloseGuard) guardObj; 312 guard.close(); 313 } 314 315 public static void closeGuardWarnIfOpen(Object guardObj) { 316 CloseGuard guard = (CloseGuard) guardObj; 317 guard.warnIfOpen(); 318 } 319 320 /* 321 * BlockGuard functions. 322 */ 323 324 public static void blockGuardOnNetwork() { 325 BlockGuard.getThreadPolicy().onNetwork(); 326 } 327 328 /** 329 * OID to Algorithm Name mapping. 330 */ 331 public static String oidToAlgorithmName(String oid) { 332 try { 333 return AlgorithmId.get(oid).getName(); 334 } catch (NoSuchAlgorithmException e) { 335 return oid; 336 } 337 } 338 339 /* 340 * Pre-Java 8 backward compatibility. 341 */ 342 343 public static SSLSession wrapSSLSession(AbstractOpenSSLSession sslSession) { 344 return new OpenSSLExtendedSessionImpl(sslSession); 345 } 346 347 public static SSLSession unwrapSSLSession(SSLSession sslSession) { 348 if (sslSession instanceof OpenSSLExtendedSessionImpl) { 349 return ((OpenSSLExtendedSessionImpl) sslSession).getDelegate(); 350 } 351 return sslSession; 352 } 353 354 /* 355 * Pre-Java-7 backward compatibility. 356 */ 357 358 public static String getHostStringFromInetSocketAddress(InetSocketAddress addr) { 359 return addr.getHostString(); 360 } 361 362 public static boolean isCTVerificationRequired(String hostname) { 363 return NetworkSecurityPolicy.getInstance() 364 .isCertificateTransparencyVerificationRequired(hostname); 365 } 366 } 367