Trying to write a SSL Proxy, but having weird problems

I am currently trying to write a SSL proxy and it works for most sites but it dosn't work on a few. This demostrates the error:

import java.io.*;

import java.net.*;

import javax.net.ssl.*;

import java.security.*;

import java.util.*;

publicclass SSLInterceptor

{

static SSLServerSocketFactory sslServerSocketFactory;

static SSLSocketFactory sslSocketFactory;

static

{

System.getProperties().put("javax.net.ssl.keyStore",new File(".keystore").getAbsolutePath());

System.getProperties().put("javax.net.ssl.keyStorePassword","password");

sslServerSocketFactory = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();

try

{

TrustManager[] trustAllCerts =new TrustManager[]

{

new X509TrustManager()

{

public java.security.cert.X509Certificate[] getAcceptedIssuers()

{

returnnull;

}

publicvoid checkClientTrusted(

java.security.cert.X509Certificate[] certs, String authType)

{

}

publicvoid checkServerTrusted(

java.security.cert.X509Certificate[] certs, String authType)

{

}

}

};

SSLContext sc = SSLContext.getInstance("SSL");

//SSLContext.getInstance("TLSv1");

sc.init(null, trustAllCerts,null);

sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();//sc.getSocketFactory();

}

catch(KeyManagementException e)

{

}

catch(NoSuchAlgorithmException e)

{

}

//sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();

}

publicstatic Socket intercept(String host,int port)throws IOException

{

SSLServerSocket sslServerSocket = (SSLServerSocket)sslServerSocketFactory.createServerSocket(0);

Socket forwardingSocket =new Socket("localhost", sslServerSocket.getLocalPort());

Socket plaintextSocket = sslServerSocket.accept();

sslServerSocket.close();

Socket sslSocket = sslSocketFactory.createSocket(host, port);

long time = System.currentTimeMillis();

Util.connect(plaintextSocket.getInputStream(), sslSocket.getOutputStream());

Util.connect(sslSocket.getInputStream(), plaintextSocket.getOutputStream());

return forwardingSocket;

}

}

import java.io.*;

import java.net.*;

import javax.net.ssl.*;

publicclass Test

{

/** Creates a new instance of Test */

public Test()

{

}

publicstaticvoid main(String[] args)throws Exception

{

Socket rawSocket = SSLInterceptor.intercept("localhost", 666);////("bugs.freenetproject.org", 443);

/*

Socket plainText = SSLInterceptor.sslSocketFactory.createSocket(rawSocket, "login.yahoo.com", 443, true);

*/

InputStream in = rawSocket.getInputStream();

int read;

while((read = in.read()) != -1)

{

System.out.println(read);

}

rawSocket.close();

}

}

import java.io.*;

import java.net.*;

import javax.net.ssl.*;

import javax.net.*;

publicfinalclass SSLServerimplements Runnable

{

int port;

static

{

/*

System.getProperties().put("javax.net.ssl.keyStore", new File(".keystore").getAbsolutePath());

System.getProperties().put("javax.net.ssl.keyStorePassword", "secure");

*/

System.getProperties().put("javax.net.ssl.keyStore",new File(".keystore").getAbsolutePath());

System.getProperties().put("javax.net.ssl.keyStorePassword","password");

}

public SSLServer(int port)

{

this.port = port;

}

publicstaticvoid main(String[] args)

{

new SSLServer(666).run();

}

publicvoid run()

{

try

{

ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();

SSLServerSocket ssocket = (SSLServerSocket)ssocketFactory.createServerSocket(port);

//ssocket.setEnabledProtocols(new String[] {"TLSv1", "SSLv3"});

// Listen for connections

while(true)

{

Socket socket = ssocket.accept();

BufferedReader reader =new BufferedReader(new InputStreamReader(socket.getInputStream()));

while(true)

{

String str = reader.readLine();

if(str ==null)

{

break;

}

else

{

System.out.println(str);

}

}

}

}

catch(IOException e)

{e.printStackTrace();}

}

}

Basically, SSLInterceptor takes a host and port as an argument and returns a Socket which it can decrypt and which sends its data to the SSL server. To test this, I wrote Test.java. However, when running Test.java, it prints out junk and the SSLServer throws a exception:

javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown

at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150)

at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:117)

at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1542)

at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:863)

at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1025)

at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:675)

at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)

at sun.nio.cs.StreamDecoder$CharsetSD.readBytes(StreamDecoder.java:411)

at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:453)

at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:183)

at java.io.InputStreamReader.read(InputStreamReader.java:167)

at java.io.BufferedReader.fill(BufferedReader.java:136)

at java.io.BufferedReader.readLine(BufferedReader.java:299)

at java.io.BufferedReader.readLine(BufferedReader.java:362)

at SSLServer.run(SSLServer.java:54)

at SSLServer.main(SSLServer.java:37)

any help concerning this error would be *much* appreciated. Tahnks in advance.

[10514 byte] By [yongqiana] at [2007-10-2 22:40:29]
# 1

RFC2246 #7.2.2:

certificate_unknown

Some other (unspecified) issue arose in processing the

certificate, rendering it unacceptable.

which is not much help. You'll have to look into what happened at the peer to get more information. If it's a Java peer turn on javax.net.debug=all; otherwise turn on whatever SSL tracing you can by whatever means are available.

ejpa at 2007-7-14 5:54:04 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...
# 2

Have you tried being a little more trusting in your certificate checks?

I use the following trust manager to help connect to development servers and such:

private static class WorkAroundX509TrustManager implements X509TrustManager {

public boolean isClientTrusted(X509Certificate[] chain){ return true; }

public boolean checkServerTrusted(X509Certificate[] chain, String s){ return true; }

public boolean isServerTrusted(X509Certificate[] chain){ return true; }

public X509Certificate[] getAcceptedIssuers(){ return null; }

}

private static class WorkAroundHostnameVerifier implements HostnameVerifier {

public boolean verify(String hostname, SSLSession session) { return true; }

public boolean verify(String hostname, String session) { return true; }

}

private static class BasicAuthenticator extends Authenticator {

private String username = "";

private String password = "";

public BasicAuthenticator(String username, String password){

this.username = username;

this.password = password;

}

}

JohnSoutherlanda at 2007-7-14 5:54:04 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...
# 3
I don't think so. Your WorkAroundX509TrustManager doesn't even compile. His is fine. Your second verify() method isn't part of the interface implemented.
ejpa at 2007-7-14 5:54:04 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...
# 4

oops, my bad, i just found that commented out in some code i havn't touched in a while, here is one that works; for posterity....

private static class WorkAroundX509TrustManager implements X509TrustManager {

public boolean isClientTrusted(X509Certificate[] chain){ return true; }

public boolean isServerTrusted(X509Certificate[] chain){ return true; }

public X509Certificate[] getAcceptedIssuers(){ return null; }

}

private static class WorkAroundHostnameVerifier implements HostnameVerifier {

public boolean verify(String hostname, String session) { return true; }

}

private static class BasicAuthenticator extends Authenticator {

private String username = "";

private String password = "";

public BasicAuthenticator(String username, String password){

this.username = username;

this.password = password;

}

}

Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

System.setProperty("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol");

X509TrustManager tm = new WorkAroundX509TrustManager();

KeyManager []km = null;

TrustManager []tma = {tm};

HostnameVerifier hmv = new WorkAroundHostnameVerifier();

SSLContext sc = SSLContext.getInstance("ssl");

sc.init(km,tma,new java.security.SecureRandom());

SSLSocketFactory sf1 = sc.getSocketFactory();

HttpsURLConnection.setDefaultSSLSocketFactory(sf1);

HttpsURLConnection.setDefaultHostnameVerifier(hmv);

NetPermission np = new NetPermission("setDefaultAuthenticator");

secureClient = new SecureXmlRpcClient(config.controller);

secureClient.setBasicAuthentication(config.user, config.pass);

Me, i'm just really really trusting.

JohnSoutherlanda at 2007-7-14 5:54:04 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...
# 5

Your Authenticator doesn't override getPasswordAuthentication() so it returns null. How's that going to work?

>Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

> System.setProperty("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol");

Both these lines apply to JDK 1.3 and earlier only.

> NetPermission np = new NetPermission("setDefaultAuthenticator");

What's that for? Does nothing.

> Me, i'm just really really trusting.

So why use SSL at all? It's not secure without authentication and authorization. I can understand that in an SSL proxy, but not in a client.

ejpa at 2007-7-14 5:54:04 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...
# 6

> Your Authenticator doesn't override

> getPasswordAuthentication() so it returns null. How's

> that going to work?

> > >Security.addProvider(new

> com.sun.net.ssl.internal.ssl.Provider());

> >

> System.setProperty("java.protocol.handler.pkgs","com.s

> un.net.ssl.internal.www.protocol");

>

> Both these lines apply to JDK 1.3 and earlier only.

> > > NetPermission np = new

> NetPermission("setDefaultAuthenticator");

>

> What's that for? Does nothing.

>

It exists mainly to annoy you ;)

> > Me, i'm just really really trusting.

>

> So why use SSL at all? It's not secure without

> authentication and authorization. I can understand

> that in an SSL proxy, but not in a client.

I just want it to encrypt the pipe between my client and my server, i could care less if my keys are in place and paid for. I use an XML-RPC stack with basic auth so this is just a quick and dirty way to get my connection.

It is really cool, i expect to see something like this added to the base SSL implementation sometime soon, for all us lazy idiots.

JohnSoutherlanda at 2007-7-14 5:54:05 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...
# 7

It is not 'really cool', it is really insecure.. The TLS/SSL RFC says so. You are having a conversation with a stranger in a blacked-out soundproof room. NObody else can hear, but who are you talking to?

Your expectations regarding this sort of thing appearing in the JDK are misplaced. The JSSE API is no place for insecurity.

And X509TrustManager.getAcceptedIssuers() is specified to return 'a non-null (possibly empty) array'.

ejpa at 2007-7-14 5:54:05 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...