dochenaj
dochenaj

Reputation: 51

How to implement an SSL proxy server in Java that overcomes certificate errors in browsers?

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

Answers (3)

Bruno
Bruno

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

Warren Dew
Warren Dew

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

user207421
user207421

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

Related Questions