I want to connect to my server via SSL. Therefore I generated the certificates on the server with these commands:
openssl genrsa -out server.pem 2048
openssl req -new -x509 -nodes -sha1 -days 3650 -key server.pem > server.cert
The connection works, if I trust all certificates on the client with a TrustManager like this:
X509TrustManager tm = new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(
X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
X509Certificate[] certs, String authType) {
}
};
But I do not want to trust all certificates of course, but only mine. I tried several commands to import the certificates like:
keytool -import -alias ca -file server.cert -keystore cacerts
But I always get this error:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
What do I need to do to get this working? Can someone explain the steps necessary for a person not very familiar with the cryto field?
Edit: As proposed by Donal Fellows, I tried the approach with the custom X509TrustManager and it works. But is it secure as well like that? If i just return "null" in the method "getAcceptedIssuers" its working as well and I am not quite sure why:
X509TrustManager tm = new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
X509Certificate[] trustedCerts = new X509Certificate[1];
try{
InputStream inStream = new FileInputStream("server.cert");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
inStream.close();
trustedCerts[0] = cert;
}catch(Exception e){
e.printStackTrace();
}
return trustedCerts;
}
@Override
public void checkClientTrusted(
X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
boolean match = false;
try{
InputStream inStream = new FileInputStream("server.cert");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
inStream.close();
for(X509Certificate c : chain){
if(c.equals(cert)){
match = true;
}
}
}catch(Exception e){
throw new CertificateException();
}
if(!match)
throw new CertificateException();
}
};