I have an application server running some utility commands, which is programmed in C. I have to connect to the server through Java client program using Java SSL socket with client authentication. The key on the server side was created using:
openssl req -new -text -out ser.req
openssl rsa -in privkey.pem -out ser.key
openssl req -x509 -in ser.req -text -key ser.key -out ser.crt
I have been provided the server key and certificate. I have combined the key and certificate into a PKCS12 format file:
openssl pkcs12 -inkey ser.key -in ser.crt -export -out ser.pkcs12
Then loading the resulting PKCS12 file into a JSSE keystore with keytool:
keytool -importkeystore -srckeystore ser.pkcs12 -srcstoretype PKCS12 -destkeystore ser.keystore
But when I try to connect, I get the following error:
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alert.createSSLException(Alert.java:131)
at sun.security.ssl.TransportContext.fatal(TransportContext.java:324)
at sun.security.ssl.TransportContext.fatal(TransportContext.java:267)
at sun.security.ssl.TransportContext.fatal(TransportContext.java:262)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:654)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:473)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:369)
at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:377)
at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444)
at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:422)
at sun.security.ssl.TransportContext.dispatch(TransportContext.java:182)
at sun.security.ssl.SSLTransport.decode(SSLTransport.java:149)
at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1143)
at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1054)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:394)
at SSLSocketClient.main(SSLSocketClient.java:67)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:456)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:323)
at sun.security.validator.Validator.validate(Validator.java:271)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:315)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:223)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:638)
... 11 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:451)
... 17 more
On the server side log:
SSL open_server: could not accept SSL connection: sslv3 alert certificate unknown
Running command:
java -Djavax.net.ssl.keyStore=/path/to/ser.keystore -Djavax.net.ssl.keyStorePassword=passwd SSLSocketClient <server-ip> <port>
Does anyone know the cause of this problem?
Updated the client source code:
import java.net.*;
import java.io.*;
import javax.net.ssl.*;
import java.security.cert.CertificateFactory;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.KeyStore;
import java.security.SecureRandom;
import javax.net.SocketFactory;
public class SSLSocketClient {
public static void main(String [] args) throws Exception {
String serverName = args[0];
int port = Integer.parseInt(args[1]);
try {
SSLSocketFactory sf =
(SSLSocketFactory)SSLSocketFactory.getDefault();
Socket client = new Socket(serverName, port);
System.out.println("Connected to " + client.getRemoteSocketAddress());
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(outToServer));
writeData(out);
out.flush();
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
readData(in);
outToServer = client.getOutputStream();
out = new DataOutputStream(new BufferedOutputStream(outToServer));
writeData2(out);
out.flush();
Socket newClient = sf.createSocket(client, serverName, port, false);
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void writeData(DataOutputStream out) throws IOException {
char CMD_CHAR_U = 'U';
byte b = (byte) (0x00ff & CMD_CHAR_U);
out.writeByte(b); // <U>
}
private static void writeData2(DataOutputStream out) throws IOException {
char CMD_CHAR_S = 'S';
byte b = (byte) (0x00ff & CMD_CHAR_S);
out.writeByte(b); // <S>
}
private static void readData(DataInputStream in) throws IOException {
char sChar = (char) in.readByte();
System.out.println("<S>\t\t" + sChar);
}
}
Now creating the truststore as shown in the link: https://jdbc.postgresql.org/documentation/head/ssl-client.html
Steps to create:
openssl x509 -in server.crt -out server.crt.der -outform der
keytool -keystore mystore -alias clientstore -import -file server.crt.der
java -Djavax.net.ssl.trustStore=mystore -Djavax.net.ssl.trustStorePassword=mypassword com.mycompany.MyApp
Note - The server side is using TLSv1 protocol
But still not able to make it through. What am I doing wrong? What I want is the server to authenticate the crt of the client.
The login protocol with server; the SSL we use is only to authenticate not to secure the transmission:
-------------------------------------------------------------
client server
-------------------------------------------------------------
sock = connect() sock = accept()
<U><LOGIN_SSL=501>
--------------------------------->
'S'|'E'
<---------------------------------
'S'
--------------------------------->
SSL_connect(sock) SSL_accept(sock)
<R><LOGIN_SSL>
<---------------------------------