I'm working to get my OkHttpClient on Android to make its HTTPS requests using a custom certificate whilst bound to a specific network interface's local address. My current attempt at this uses the following OkHttpClient:
val client = OkHttpClient.Builder()
.readTimeout(2, TimeUnit.SECONDS)
.connectTimeout(2, TimeUnit.SECONDS)
.sslSocketFactory(
MySocketFactory(
getSslContext().socketFactory,
localAddress
),
MyTrustManager()
)
.build()
The MySocketFactory class is implemented as:
class MySocketFactory(
private val delegate: SSLSocketFactory,
private val localAddress: InetAddress
) : SSLSocketFactory() {
override fun createSocket(): Socket {
Timber.i("createSocket has been called!")
val socket = delegate.createSocket()
socket.bind(InetSocketAddress(localAddress, 0))
return socket
}
[other overrides of the various abstract createSocket methods, each of which throws an UnsupportedOperationException]
override fun getDefaultCipherSuites() = delegate.defaultCipherSuites
override fun getSupportedCipherSuites() = delegate.supportedCipherSuites
}
This is mostly based on the documentation from the OkHttp GitHub site which describes how passing a value to Builder.socketFactory() allows us to bind each socket to a specific address by overriding the parameter-less createSocket method. However, the docs for sslSocketFactory do not mention anything about being able to bind sockets. When I run my app with the above code, the createSocket log entry is never generated, indicating that the factory is completely ignored. As a result, the HTTP endpoint is never reached.
If I try this same setup without the wrapper MySocketFactory class - instead just passing getSslContext().socketFactory directly into Builder.sslSocketFactory - then I can contact the endpoint perfectly well, assuming I only have the single local address on my machine at the time.
So my question: is this possible to do with a custom SSLSocketFactory?