Reputation: 51
I am trying to implement an SSL proxy server in Java that does not raise certificate errors in the browser. I understand that I will need to process the "CONNECT" request, do an SSL handshake thus requiring that I create a sever certificate and store that in the keystore which I will initialize for the SSL socket.
But the browser will always have to verify the server certificate returned and throw the warning error if; 1.The CA certificate is not trusted, but this can be overcome by installing the CA certificate used in signing the server certificate once in the browser. 2.The CN of the certificate does not match the hostname of the website being requested. For this second issue, I implemented using BouncyCastle a certificate generation thread, that uses the hostname being requested to generate a certificate that is signed with the trusted CA private key from above. Then I add the server certificate generated and it's private key into the keystore using the hostname as the alias for the key entry. Now comes the part I can't seem to get a hold of, how do I get to use different certificates for the handshake depending on the hostname being requested. I have seen so many suggestions talking about keymanagers and sslcontext but none of that seem to be able to dynamically change the certificate used for sslhandshake depending on the differing hostname being requested.
I am sorry for the very verbose question, I am new to all this, so please be a little patient with me.
EDIT: Considering implementing a keymanager and initializing sslcontext with it, and creating the serversocket, at the moment when the serversocket is being created there is no hostname being requested, so how do I create a keymanager that is dynamic unlike the fixedserveralias examples I have seen around.
Upvotes: 0
Views: 2049
Reputation: 122609
Since you're getting the CONNECT
request over a plain socket, presumably, you're trying to upgrade that socket to an SSLSocket
afterwards (which you can indeed to with SSLSocketFactory.createSocket(Socket s, String host, int port, boolean autoClose)
.
Since you're generating your new certificate on the fly by putting the hostname you get via CONNECT
into its CN (by the way, it would be better in a SAN), you can quite easily create a KeyStore
instance in memory and put that cert and its private key into it. Then, initialise a KeyManagerFactory from that instance, initialise a new SSLContext
using that KMF, create an new SSLSocketFactory
from that SSLContext
, and use SSLSocketFactory.createSocket(Socket, ...)
to upgrade that specific accepted socket. You can do all this per accepted socket and they would all be independent.
Having a single KeyManager
and SSLContext
for all your sockets would mean that you need to implement some custom logic into your own subclass of X509KeyManager
(implementing your own chooseServerAlias()
), which seems unnecessarily complicated.
Upvotes: 2
Reputation: 8928
Presumably your proxy server is serving multiple host names on a single IP address. Your best bet is to generate a single certificate with multiple subject alternative names (SANs), one for each host name that is served from your IP address.
You cannot use separate certificates for each host name because your proxy server has no way of knowing which host name is requested. That's because the browser first goes to a DNS to translate the host name into the IP address, and then sends the request directly to the IP address. In fact, doing this with separate dynamically generated certificates would be, from a technological standpoint, equivalent to a "man in the middle" attack, which is exactly what the host name checking is supposed to guard against.
Upvotes: -1
Reputation: 310869
Basically you'll have to remember the target hostname and return an appropriate keystore alias from X509KeyManager.chooseServerAlias()
.
The whole thing sounds like a Grade A security breach to me, in more than one respect. You're not entitled to mediate in what is supposed to be a private conversation, and the end user is entitled to know if the server he thinks he's talking to has a bad or non-trusted certificate.
Upvotes: 1