1 /* 2 * Copyright (C) 2007 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 org.conscrypt.Platform.createEngineSocket; 20 import static org.conscrypt.Platform.createFileDescriptorSocket; 21 22 import java.io.IOException; 23 import java.net.InetAddress; 24 import java.net.Socket; 25 import java.net.SocketException; 26 import java.net.UnknownHostException; 27 import java.security.KeyManagementException; 28 import javax.net.SocketFactory; 29 import javax.net.ssl.SSLSocketFactory; 30 31 /** 32 * An implementation of {@link SSLSocketFactory} based on BoringSSL. 33 * 34 * <p/>This name of this class cannot change in order to maintain backward-compatibility with GMS 35 * core {@code ProviderInstallerImpl} 36 */ 37 final class OpenSSLSocketFactoryImpl extends SSLSocketFactory { 38 private static boolean useEngineSocketByDefault = SSLUtils.USE_ENGINE_SOCKET_BY_DEFAULT; 39 40 private final SSLParametersImpl sslParameters; 41 private final IOException instantiationException; 42 private boolean useEngineSocket = useEngineSocketByDefault; 43 OpenSSLSocketFactoryImpl()44 OpenSSLSocketFactoryImpl() { 45 SSLParametersImpl sslParametersLocal = null; 46 IOException instantiationExceptionLocal = null; 47 try { 48 sslParametersLocal = SSLParametersImpl.getDefault(); 49 } catch (KeyManagementException e) { 50 instantiationExceptionLocal = new IOException("Delayed instantiation exception:", e); 51 } 52 this.sslParameters = sslParametersLocal; 53 this.instantiationException = instantiationExceptionLocal; 54 } 55 OpenSSLSocketFactoryImpl(SSLParametersImpl sslParameters)56 OpenSSLSocketFactoryImpl(SSLParametersImpl sslParameters) { 57 this.sslParameters = sslParameters; 58 this.instantiationException = null; 59 } 60 61 /** 62 * Configures the default socket type to be created for the default and all new instances. 63 */ setUseEngineSocketByDefault(boolean useEngineSocket)64 static void setUseEngineSocketByDefault(boolean useEngineSocket) { 65 useEngineSocketByDefault = useEngineSocket; 66 // The default SSLSocketFactory may already have been created, so also change its setting. 67 SocketFactory defaultFactory = SSLSocketFactory.getDefault(); 68 if (defaultFactory instanceof OpenSSLSocketFactoryImpl) { 69 ((OpenSSLSocketFactoryImpl) defaultFactory).setUseEngineSocket(useEngineSocket); 70 } 71 } 72 73 /** 74 * Configures the socket to be created for this instance. If not called, 75 * {@link #useEngineSocketByDefault} will be used. 76 */ setUseEngineSocket(boolean useEngineSocket)77 void setUseEngineSocket(boolean useEngineSocket) { 78 this.useEngineSocket = useEngineSocket; 79 } 80 81 @Override getDefaultCipherSuites()82 public String[] getDefaultCipherSuites() { 83 return sslParameters.getEnabledCipherSuites(); 84 } 85 86 @Override getSupportedCipherSuites()87 public String[] getSupportedCipherSuites() { 88 return NativeCrypto.getSupportedCipherSuites(); 89 } 90 91 @Override createSocket()92 public Socket createSocket() throws IOException { 93 if (instantiationException != null) { 94 throw instantiationException; 95 } 96 if (useEngineSocket) { 97 return createEngineSocket((SSLParametersImpl) sslParameters.clone()); 98 } else { 99 return createFileDescriptorSocket((SSLParametersImpl) sslParameters.clone()); 100 } 101 } 102 103 @Override createSocket(String hostname, int port)104 public Socket createSocket(String hostname, int port) throws IOException, UnknownHostException { 105 if (useEngineSocket) { 106 return createEngineSocket( 107 hostname, port, (SSLParametersImpl) sslParameters.clone()); 108 } else { 109 return createFileDescriptorSocket( 110 hostname, port, (SSLParametersImpl) sslParameters.clone()); 111 } 112 } 113 114 @Override createSocket(String hostname, int port, InetAddress localHost, int localPort)115 public Socket createSocket(String hostname, int port, InetAddress localHost, int localPort) 116 throws IOException, UnknownHostException { 117 if (useEngineSocket) { 118 return createEngineSocket(hostname, port, localHost, 119 localPort, (SSLParametersImpl) sslParameters.clone()); 120 } else { 121 return createFileDescriptorSocket(hostname, port, localHost, 122 localPort, (SSLParametersImpl) sslParameters.clone()); 123 } 124 } 125 126 @Override createSocket(InetAddress address, int port)127 public Socket createSocket(InetAddress address, int port) throws IOException { 128 if (useEngineSocket) { 129 return createEngineSocket( 130 address, port, (SSLParametersImpl) sslParameters.clone()); 131 } else { 132 return createFileDescriptorSocket( 133 address, port, (SSLParametersImpl) sslParameters.clone()); 134 } 135 } 136 137 @Override createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)138 public Socket createSocket(InetAddress address, int port, InetAddress localAddress, 139 int localPort) throws IOException { 140 if (useEngineSocket) { 141 return createEngineSocket(address, port, localAddress, 142 localPort, (SSLParametersImpl) sslParameters.clone()); 143 } else { 144 return createFileDescriptorSocket(address, port, localAddress, 145 localPort, (SSLParametersImpl) sslParameters.clone()); 146 } 147 } 148 149 @Override createSocket(Socket socket, String hostname, int port, boolean autoClose)150 public Socket createSocket(Socket socket, String hostname, int port, boolean autoClose) 151 throws IOException { 152 Preconditions.checkNotNull(socket, "socket"); 153 if (!socket.isConnected()) { 154 throw new SocketException("Socket is not connected."); 155 } 156 157 if (!useEngineSocket && hasFileDescriptor(socket)) { 158 return createFileDescriptorSocket( 159 socket, hostname, port, autoClose, (SSLParametersImpl) sslParameters.clone()); 160 } else { 161 return createEngineSocket( 162 socket, hostname, port, autoClose, (SSLParametersImpl) sslParameters.clone()); 163 } 164 } 165 hasFileDescriptor(Socket s)166 private boolean hasFileDescriptor(Socket s) { 167 try { 168 // If socket has a file descriptor we can use it directly 169 // otherwise we need to use the engine. 170 Platform.getFileDescriptor(s); 171 return true; 172 } catch (RuntimeException re) { 173 return false; 174 } 175 } 176 } 177