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