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.

