Authenticate client that uses IE

I try to undersand SSLSocket and the setWantClientAuth(true)

Here is what I want to accomplish, I have a java app listening to port 443 that uses a

keystore containing an imported clientkey.

When a client makes a connection to that server (other java app) it needs to use a

keystore where the clientkey was exported form and setWantClientAuth(true) works.

Here is how the keystores were made (server and client)

del *.key

del *.cer

keytool -genkey -keystore serverkeys.key -keyalg rsa -dname"CN=Harm Meijer Server, OU=Technology, O=CliffordChance, L=Amsterdam, ST=, C=NL" -alias server -validity 720 -keypass keypass -storepass storepass

rem export server to inport in a client keystore (to be trusted)

keytool -export -alias server -file fromserver.cer -keystore serverkeys.key -storepass storepass

rem generate client keystore

keytool -genkey -keystore clientkeys.key -keyalg rsa -dname"CN=Harm Meijer Client, OU=Technology, O=CliffordChance, L=Amsterdam, ST=Client, C=NL" -alias client -validity 720 -keypass keypass -storepass storepass

remimport the server key server into the client keystore

keytool -noprompt -import -alias server -file fromserver.cer -keypass keypass -keystore clientkeys.key -storepass storepass

rem export client key andimport it in the server so authentication can be set:

keytool -export -alias client -file fromclient.cer -keystore clientkeys.key -storepass storepass

keytool -noprompt -import -alias client -file fromclient.cer -keypass keypass -keystore serverkeys.key -storepass storepass

pause

This works OK when I use 2 java appls for server and client. But when I use MS

Internet Explorer it doesn't work.

Here is the server code:

import java.io.BufferedReader;

import java.io.DataOutputStream;

import java.io.FileInputStream;

import java.io.InputStreamReader;

import java.security.KeyStore;

import javax.net.ServerSocketFactory;

import javax.net.ssl.KeyManagerFactory;

import javax.net.ssl.SSLContext;

import javax.net.ssl.SSLServerSocket;

import javax.net.ssl.SSLSession;

import javax.net.ssl.SSLSocket;

import javax.net.ssl.TrustManagerFactory;

import javax.security.cert.X509Certificate;

publicclass HttpsServerextends Thread{

String keystore ="serverkeys.key";

char keystorepass[] ="storepass".toCharArray();

char keypassword[] ="keypass".toCharArray();

// The port number which the server will be listening on

publicstaticfinalint HTTPS_PORT = 443;

KeyStore ks =null;

public SSLServerSocket getServer()throws Exception{

System.out.println("username is: " + System.getProperty("user.name"));

ks = KeyStore.getInstance("JKS");

ks.load(new FileInputStream(keystore), keystorepass);

TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

tmf.init(ks);

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");

kmf.init(ks, keypassword);

SSLContext sslcontext = SSLContext.getInstance("SSLv3");

sslcontext.init(kmf.getKeyManagers(), tmf.getTrustManagers(),null);

ServerSocketFactory ssf = sslcontext.getServerSocketFactory();

SSLServerSocket serversocket = (SSLServerSocket) ssf

.createServerSocket(HTTPS_PORT);

return serversocket;

}

publicvoid run(){

SSLServerSocket listen =null;

try{

listen = getServer();

//listen.setNeedClientAuth(true);

}catch (Exception e){

e.printStackTrace();

}

while (true){

try{

String user ="";

String f ="";

int cerCount = 0;

SSLSocket client = (SSLSocket) listen.accept();

try{

//client.setNeedClientAuth(true);

client.setWantClientAuth(true);

SSLSession SslSession = client.getSession();

java.security.cert.Certificate cer[] = SslSession

.getPeerCertificates();

int i = 0;

while (i < cer.length){

X509Certificate cert = X509Certificate

.getInstance(cer[i].getEncoded());

System.out.println("Got a peer cert:");

System.out.print("");

System.out.println(cert.getIssuerDN().getName());

user = cert.getIssuerDN().getName();

i++;

}

}catch (Exception ex){

System.out

.println("got a connection from an unknown client");

client.setNeedClientAuth(false);

}

BufferedReader in =new BufferedReader(new InputStreamReader(

client.getInputStream()));

String sIn = in.readLine();

StringBuffer sbHeader =new StringBuffer();

System.out.println("Got a request: ");

System.out.println(sIn);

sbHeader.append(sIn);

sbHeader.append('\n');

// this should go in a seperate thread, if reading the header

// is not finished within 5 seconds then close the SSLSocket

while (sIn.compareTo("") != 0){// request header ends with an

// empty line

sIn = in.readLine();

sbHeader.append(sIn);

sbHeader.append('\n');

}

String stHeader = sbHeader.toString();

System.out.println("Header is: ");

System.out.println(stHeader);

stHeader = stHeader.toLowerCase();

if (stHeader.indexOf("content-length:") != -1){

// some posted data, do something with this

}

DataOutputStream out =new DataOutputStream(client

.getOutputStream());

if (client.getNeedClientAuth()){

f ="Hello " + user;

}else{

f ="Don't know who you are";

}

String toWrite ="HTTP/1.0 200 OK\r\nContent-Length: "

+ f.length() +"\r\nContent-Type: text/html\r\n\r\n";

out.write(toWrite.getBytes("utf-8"));

out.write(f.getBytes());

out.flush();

out.close();

in.close();

}catch (Exception e){

e.printStackTrace();

}

}

}

// main program

publicstaticvoid main(String argv[])throws Exception{

new HttpsServer().start();

}

}

In IE I choose tools -> "internet options" -> content -> certificates -> personal -> import

-> next -> browse -> "slected the "fromclient.cer" file -> next -> checked automatically ....

-> next -> finish

Then go to the "Trusted root CA" and found the cert issued by Harm Meijer Client.

Double clicked that and in the general tab found out that it is used to

"Proves your identity to a remote computer"

The problem is that it doesn't, I think I know the reason why is that the fromclient.cer

file is only the public key part from the keystore, I need IE to import the entire keystore.

Problem is that both IE and Mozilla can only import the pkcs12 (p12) type files that

contain both the public and client keys.

[10740 byte] By [harmmeijera] at [2007-10-1 10:14:22]
# 1

Well, I found a way to convert the keystore to a p12 or pkcs12 file and import it in both

Mozilla and IE but both browsers refuse to send authentication to the server.

This is the batch file:

del *.key

del *.cer

del *.pfx

del *.rfc

del *.crt

keytool -genkey -keystore serverkeys.key -keyalg rsa -dname "CN=Harm Meijer Server, OU=Technology, O=CliffordChance, L=Amsterdam, ST=, C=NL" -alias server -validity 720 -keypass keypass -storepass storepass

pause

cls

rem export server to inport in a client keystore (to be trusted)

keytool -export -alias server -file fromserver.cer -keystore serverkeys.key -storepass storepass

pause

cls

rem generate client keystore

keytool -genkey -keystore clientkeys.key -keyalg rsa -dname "CN=Harm Meijer Client, OU=Technology, O=CliffordChance, L=Amsterdam, ST=Client, C=NL" -alias client -validity 720 -keypass keypass -storepass storepass

pause

cls

rem import the server key server into the client keystore

keytool -noprompt -import -alias server -file fromserver.cer -keypass keypass -keystore clientkeys.key -storepass storepass

pause

cls

rem export client key and import it in the server so authentication can be set:

keytool -export -alias client -file fromclient.cer -keystore clientkeys.key -storepass storepass

keytool -noprompt -import -alias client -file fromclient.cer -keypass keypass -keystore serverkeys.key -storepass storepass

pause

pause

cls

rem now convert the clientkeys keystore to a p12 so it can be used in IE and Mozilla

rem see the following site: http://mark.foster.cc/kb/openssl-keytool.html

openssl x509 -noout -text -in fromclient.cer -inform der

openssl x509 -out exported-pem.crt -outform pem -text -in fromclient.cer -inform der

pause

cls

javac ExportPriv.java

java ExportPriv clientkeys.key client storepass keypass > exported-pkcs8.key

pause

cls

openssl pkcs8 -inform PEM -nocrypt -in exported-pkcs8.key -out exported.key

openssl pkcs12 -export -out exported.pfx -inkey exported.key -in exported-pem.crt

pause

Had to adjust the java file that exports private keys to p8

http://mark.foster.cc/pub/java/ExportPriv.java

(some explenation) http://mark.foster.cc/kb/openssl-keytool.html

because KeyPair kp = getPrivateKey(ks, aliasName, ....

assumes that storepass and keypass are the same.

As mentioned before, no luck. I will stick to form login from now on because this

whole ssl authentications sucks big time.

harmmeijera at 2007-7-10 2:40:57 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...
# 2
Must have done something wrong creating the p12 key before because it works now.
harmmeijera at 2007-7-10 2:40:57 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...