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.StructTimeval; 24 import dalvik.system.BlockGuard; 25 import dalvik.system.CloseGuard; 26 import java.io.FileDescriptor; 27 import java.io.IOException; 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.AlgorithmParameters; 37 import java.security.NoSuchAlgorithmException; 38 import java.security.PrivateKey; 39 import java.security.cert.CertificateException; 40 import java.security.cert.X509Certificate; 41 import java.security.spec.AlgorithmParameterSpec; 42 import java.security.spec.ECParameterSpec; 43 import java.security.spec.InvalidParameterSpecException; 44 import java.util.Collections; 45 import java.util.List; 46 import javax.crypto.spec.GCMParameterSpec; 47 import javax.net.ssl.SNIHostName; 48 import javax.net.ssl.SNIServerName; 49 import javax.net.ssl.SSLEngine; 50 import javax.net.ssl.SSLParameters; 51 import javax.net.ssl.SSLSession; 52 import javax.net.ssl.SSLSocketFactory; 53 import javax.net.ssl.StandardConstants; 54 import javax.net.ssl.X509ExtendedTrustManager; 55 import javax.net.ssl.X509TrustManager; 56 import libcore.io.Libcore; 57 import libcore.net.NetworkSecurityPolicy; 58 import sun.security.x509.AlgorithmId; 59 60 final class Platform { 61 private static class NoPreloadHolder { public static final Platform MAPPER = new Platform(); } 62 63 /** 64 * Runs all the setup for the platform that only needs to run once. 65 */ 66 public static void setup() { 67 NoPreloadHolder.MAPPER.ping(); 68 } 69 70 /** 71 * Just a placeholder to make sure the class is initialized. 72 */ 73 private void ping() {} 74 75 private Platform() {} 76 77 /** 78 * Default name used in the {@link java.security.Security JCE system} by {@code OpenSSLProvider} 79 * if the default constructor is used. 80 */ 81 static String getDefaultProviderName() { 82 return "AndroidOpenSSL"; 83 } 84 85 static FileDescriptor getFileDescriptor(Socket s) { 86 return s.getFileDescriptor$(); 87 } 88 89 static FileDescriptor getFileDescriptorFromSSLSocket(AbstractConscryptSocket socket) { 90 try { 91 Field f_impl = Socket.class.getDeclaredField("impl"); 92 f_impl.setAccessible(true); 93 Object socketImpl = f_impl.get(socket); 94 Field f_fd = SocketImpl.class.getDeclaredField("fd"); 95 f_fd.setAccessible(true); 96 return (FileDescriptor) f_fd.get(socketImpl); 97 } catch (Exception e) { 98 throw new RuntimeException("Can't get FileDescriptor from socket", e); 99 } 100 } 101 102 static String getCurveName(ECParameterSpec spec) { 103 return spec.getCurveName(); 104 } 105 106 static void setCurveName(ECParameterSpec spec, String curveName) { 107 spec.setCurveName(curveName); 108 } 109 110 static void setSocketWriteTimeout(Socket s, long timeoutMillis) throws SocketException { 111 StructTimeval tv = StructTimeval.fromMillis(timeoutMillis); 112 try { 113 Libcore.os.setsockoptTimeval(s.getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv); 114 } catch (ErrnoException errnoException) { 115 throw errnoException.rethrowAsSocketException(); 116 } 117 } 118 119 static void setSSLParameters( 120 SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { 121 impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); 122 impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); 123 List<SNIServerName> serverNames = params.getServerNames(); 124 if (serverNames != null) { 125 for (SNIServerName serverName : serverNames) { 126 if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { 127 socket.setHostname(((SNIHostName) serverName).getAsciiName()); 128 break; 129 } 130 } 131 } 132 } 133 134 static void getSSLParameters( 135 SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { 136 params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); 137 params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); 138 if (impl.getUseSni() && AddressUtils.isValidSniHostname(socket.getHostname())) { 139 params.setServerNames(Collections.<SNIServerName>singletonList( 140 new SNIHostName(socket.getHostname()))); 141 } 142 } 143 144 static void setSSLParameters( 145 SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { 146 impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); 147 impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); 148 List<SNIServerName> serverNames = params.getServerNames(); 149 if (serverNames != null) { 150 for (SNIServerName serverName : serverNames) { 151 if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { 152 engine.setHostname(((SNIHostName) serverName).getAsciiName()); 153 break; 154 } 155 } 156 } 157 } 158 159 static void getSSLParameters( 160 SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { 161 params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); 162 params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); 163 if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) { 164 params.setServerNames(Collections.<SNIServerName>singletonList( 165 new SNIHostName(engine.getHostname()))); 166 } 167 } 168 169 /** 170 * Helper function to unify calls to the different names used for each function taking a 171 * Socket, SSLEngine, or String (legacy Android). 172 */ 173 private static boolean checkTrusted(String methodName, X509TrustManager tm, 174 X509Certificate[] chain, String authType, Class<?> argumentClass, 175 Object argumentInstance) throws CertificateException { 176 // Use duck-typing to try and call the hostname-aware method if available. 177 try { 178 Method method = tm.getClass().getMethod( 179 methodName, X509Certificate[].class, String.class, argumentClass); 180 method.invoke(tm, chain, authType, argumentInstance); 181 return true; 182 } catch (NoSuchMethodException | IllegalAccessException ignored) { 183 } catch (InvocationTargetException e) { 184 if (e.getCause() instanceof CertificateException) { 185 throw(CertificateException) e.getCause(); 186 } 187 throw new RuntimeException(e.getCause()); 188 } 189 return false; 190 } 191 192 static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, 193 AbstractConscryptSocket socket) throws CertificateException { 194 if (tm instanceof X509ExtendedTrustManager) { 195 X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; 196 x509etm.checkClientTrusted(chain, authType, socket); 197 } else if (!checkTrusted("checkClientTrusted", tm, chain, authType, Socket.class, socket) 198 && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, 199 socket.getHandshakeSession().getPeerHost())) { 200 tm.checkClientTrusted(chain, authType); 201 } 202 } 203 204 static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, 205 AbstractConscryptSocket socket) throws CertificateException { 206 if (tm instanceof X509ExtendedTrustManager) { 207 X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; 208 x509etm.checkServerTrusted(chain, authType, socket); 209 } else if (!checkTrusted("checkServerTrusted", tm, chain, authType, Socket.class, socket) 210 && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, 211 socket.getHandshakeSession().getPeerHost())) { 212 tm.checkServerTrusted(chain, authType); 213 } 214 } 215 216 static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, 217 ConscryptEngine engine) throws CertificateException { 218 if (tm instanceof X509ExtendedTrustManager) { 219 X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; 220 x509etm.checkClientTrusted(chain, authType, engine); 221 } else if (!checkTrusted("checkClientTrusted", tm, chain, authType, SSLEngine.class, engine) 222 && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, 223 engine.getHandshakeSession().getPeerHost())) { 224 tm.checkClientTrusted(chain, authType); 225 } 226 } 227 228 static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, 229 ConscryptEngine engine) throws CertificateException { 230 if (tm instanceof X509ExtendedTrustManager) { 231 X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; 232 x509etm.checkServerTrusted(chain, authType, engine); 233 } else if (!checkTrusted("checkServerTrusted", tm, chain, authType, SSLEngine.class, engine) 234 && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, 235 engine.getHandshakeSession().getPeerHost())) { 236 tm.checkServerTrusted(chain, authType); 237 } 238 } 239 240 /** 241 * Wraps an old AndroidOpenSSL key instance. This is not needed on platform 242 * builds since we didn't backport, so return null. 243 */ 244 static OpenSSLKey wrapRsaKey(PrivateKey key) { 245 return null; 246 } 247 248 /** 249 * Logs to the system EventLog system. 250 */ 251 static void logEvent(String message) { 252 try { 253 Class processClass = Class.forName("android.os.Process"); 254 Object processInstance = processClass.newInstance(); 255 Method myUidMethod = processClass.getMethod("myUid", (Class[]) null); 256 int uid = (Integer) myUidMethod.invoke(processInstance); 257 258 Class eventLogClass = Class.forName("android.util.EventLog"); 259 Object eventLogInstance = eventLogClass.newInstance(); 260 Method writeEventMethod = eventLogClass.getMethod( 261 "writeEvent", new Class[] {Integer.TYPE, Object[].class}); 262 writeEventMethod.invoke(eventLogInstance, 0x534e4554 /* SNET */, 263 new Object[] {"conscrypt", uid, message}); 264 } catch (Exception e) { 265 // Do not log and fail silently 266 } 267 } 268 269 /** 270 * Returns true if the supplied hostname is an literal IP address. 271 */ 272 static boolean isLiteralIpAddress(String hostname) { 273 return InetAddress.isNumeric(hostname); 274 } 275 276 static SSLEngine wrapEngine(ConscryptEngine engine) { 277 return new Java8EngineWrapper(engine); 278 } 279 280 static SSLEngine unwrapEngine(SSLEngine engine) { 281 return Java8EngineWrapper.getDelegate(engine); 282 } 283 284 static ConscryptEngineSocket createEngineSocket(SSLParametersImpl sslParameters) 285 throws IOException { 286 return new Java8EngineSocket(sslParameters); 287 } 288 289 static ConscryptEngineSocket createEngineSocket(String hostname, int port, 290 SSLParametersImpl sslParameters) throws IOException { 291 return new Java8EngineSocket(hostname, port, sslParameters); 292 } 293 294 static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, 295 SSLParametersImpl sslParameters) throws IOException { 296 return new Java8EngineSocket(address, port, sslParameters); 297 } 298 299 static ConscryptEngineSocket createEngineSocket(String hostname, int port, 300 InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) 301 throws IOException { 302 return new Java8EngineSocket(hostname, port, clientAddress, clientPort, sslParameters); 303 } 304 305 static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, 306 InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) 307 throws IOException { 308 return new Java8EngineSocket(address, port, clientAddress, clientPort, sslParameters); 309 } 310 311 static ConscryptEngineSocket createEngineSocket(Socket socket, String hostname, int port, 312 boolean autoClose, SSLParametersImpl sslParameters) throws IOException { 313 return new Java8EngineSocket(socket, hostname, port, autoClose, sslParameters); 314 } 315 316 static ConscryptFileDescriptorSocket createFileDescriptorSocket(SSLParametersImpl sslParameters) 317 throws IOException { 318 return new Java8FileDescriptorSocket(sslParameters); 319 } 320 321 static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port, 322 SSLParametersImpl sslParameters) throws IOException { 323 return new Java8FileDescriptorSocket(hostname, port, sslParameters); 324 } 325 326 static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port, 327 SSLParametersImpl sslParameters) throws IOException { 328 return new Java8FileDescriptorSocket(address, port, sslParameters); 329 } 330 331 static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port, 332 InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) 333 throws IOException { 334 return new Java8FileDescriptorSocket( 335 hostname, port, clientAddress, clientPort, sslParameters); 336 } 337 338 static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port, 339 InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) 340 throws IOException { 341 return new Java8FileDescriptorSocket( 342 address, port, clientAddress, clientPort, sslParameters); 343 } 344 345 static ConscryptFileDescriptorSocket createFileDescriptorSocket(Socket socket, String hostname, 346 int port, boolean autoClose, SSLParametersImpl sslParameters) throws IOException { 347 return new Java8FileDescriptorSocket(socket, hostname, port, autoClose, sslParameters); 348 } 349 350 /** 351 * Wrap the SocketFactory with the platform wrapper if needed for compatability. 352 * For the platform-bundled library we never need to wrap. 353 */ 354 static SSLSocketFactory wrapSocketFactoryIfNeeded(OpenSSLSocketFactoryImpl factory) { 355 return factory; 356 } 357 358 /** 359 * Convert from platform's GCMParameterSpec to our internal version. 360 */ 361 static GCMParameters fromGCMParameterSpec(AlgorithmParameterSpec params) { 362 if (params instanceof GCMParameterSpec) { 363 GCMParameterSpec gcmParams = (GCMParameterSpec) params; 364 return new GCMParameters(gcmParams.getTLen(), gcmParams.getIV()); 365 } 366 return null; 367 } 368 369 /** 370 * Convert from an opaque AlgorithmParameters to the platform's GCMParameterSpec. 371 */ 372 static AlgorithmParameterSpec fromGCMParameters(AlgorithmParameters params) { 373 try { 374 return params.getParameterSpec(GCMParameterSpec.class); 375 } catch (InvalidParameterSpecException e) { 376 return null; 377 } 378 } 379 380 /** 381 * Creates a platform version of {@code GCMParameterSpec}. 382 */ 383 static AlgorithmParameterSpec toGCMParameterSpec(int tagLenInBits, byte[] iv) { 384 return new GCMParameterSpec(tagLenInBits, iv); 385 } 386 387 /* 388 * CloseGuard functions. 389 */ 390 391 static CloseGuard closeGuardGet() { 392 return CloseGuard.get(); 393 } 394 395 static void closeGuardOpen(Object guardObj, String message) { 396 CloseGuard guard = (CloseGuard) guardObj; 397 guard.open(message); 398 } 399 400 static void closeGuardClose(Object guardObj) { 401 CloseGuard guard = (CloseGuard) guardObj; 402 guard.close(); 403 } 404 405 static void closeGuardWarnIfOpen(Object guardObj) { 406 CloseGuard guard = (CloseGuard) guardObj; 407 guard.warnIfOpen(); 408 } 409 410 /* 411 * BlockGuard functions. 412 */ 413 414 static void blockGuardOnNetwork() { 415 BlockGuard.getThreadPolicy().onNetwork(); 416 } 417 418 /** 419 * OID to Algorithm Name mapping. 420 */ 421 static String oidToAlgorithmName(String oid) { 422 try { 423 return AlgorithmId.get(oid).getName(); 424 } catch (NoSuchAlgorithmException e) { 425 return oid; 426 } 427 } 428 429 /** 430 * Provides extended capabilities for the session if supported by the platform. 431 */ 432 static SSLSession wrapSSLSession(ConscryptSession sslSession) { 433 return new Java8ExtendedSSLSession(sslSession); 434 } 435 436 public static String getOriginalHostNameFromInetAddress(InetAddress addr) { 437 try { 438 Method getHolder = InetAddress.class.getDeclaredMethod("holder"); 439 getHolder.setAccessible(true); 440 441 Method getOriginalHostName = Class.forName("java.net.InetAddress$InetAddressHolder") 442 .getDeclaredMethod("getOriginalHostName"); 443 getOriginalHostName.setAccessible(true); 444 445 String originalHostName = (String) getOriginalHostName.invoke(getHolder.invoke(addr)); 446 if (originalHostName == null) { 447 return addr.getHostAddress(); 448 } 449 return originalHostName; 450 } catch (InvocationTargetException e) { 451 throw new RuntimeException("Failed to get originalHostName", e); 452 } catch (ClassNotFoundException ignore) { 453 // passthrough and return addr.getHostAddress() 454 } catch (IllegalAccessException ignore) { 455 } catch (NoSuchMethodException ignore) { 456 } 457 return addr.getHostAddress(); 458 } 459 460 /* 461 * Pre-Java-7 backward compatibility. 462 */ 463 464 static String getHostStringFromInetSocketAddress(InetSocketAddress addr) { 465 return addr.getHostString(); 466 } 467 468 static boolean isCTVerificationRequired(String hostname) { 469 return NetworkSecurityPolicy.getInstance().isCertificateTransparencyVerificationRequired( 470 hostname); 471 } 472 } 473