Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add trustStore for client authentication [duplicate]

A server and respective client support client authentication but as noted here: SSLHandshakeException: no cipher suites in common, do not have trustStore reference, i.e. they use the default trustStore. How can the trustStore be specified?

ClassFileServer:

private static ServerSocketFactory getServerSocketFactory(String type) {
    if (type.equals("TLS")) {
        SSLServerSocketFactory ssf = null;

        Properties systemProps = System.getProperties();
        systemProps.put( "javax.net.ssl.trustStore", "cacerts.jks");
        systemProps.put( "javax.net.ssl.trustStorePassword", "p@ssw0rd");
        System.setProperties(systemProps);

        try {
            // set up key manager to do server authentication
            SSLContext ctx;
            KeyManagerFactory kmf;
            KeyStore ks;
            char[] passphrase = "p@ssw0rd".toCharArray();

            ctx = SSLContext.getInstance("TLS");
            kmf = KeyManagerFactory.getInstance("SunX509");
            ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream("keystore.jks"), passphrase);
            kmf.init(ks, passphrase);
            ctx.init(kmf.getKeyManagers(), null, null);

            ssf = ctx.getServerSocketFactory();
            return ssf;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

SSLSocketClientWithClientAuth:

    try {

        /*
         * Set up a key manager for client authentication
         * if asked by the server.  Use the implementation's
         * default TrustStore and secureRandom routines.
         */
        Properties systemProps = System.getProperties();
        systemProps.put( "javax.net.ssl.trustStore", "cacerts.jks");
        systemProps.put( "javax.net.ssl.trustStorePassword", "changeit");
        System.setProperties(systemProps);

        SSLSocketFactory factory = null;
        try {
            SSLContext ctx;
            KeyManagerFactory kmf;
            KeyStore ks;
            char[] passphrase = "changeit".toCharArray();

            ctx = SSLContext.getInstance("TLS");
            kmf = KeyManagerFactory.getInstance("SunX509");
            ks = KeyStore.getInstance("JKS");

            ks.load(new FileInputStream("keystore.jks"), passphrase);

            kmf.init(ks, passphrase);
            ctx.init(kmf.getKeyManagers(), null, null);

            factory = ctx.getSocketFactory();
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }

        SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
like image 870
Astron Avatar asked Oct 08 '22 12:10

Astron


2 Answers

Specify the trustStore by setting the system properties:

System.setProperty("javax.net.ssl.trustStore", "cacerts.jks");

or via command line invocation:

-Djavax.net.ssl.keyStore=path/to/keystore.jks

like image 159
Astron Avatar answered Oct 12 '22 12:10

Astron


'No cipher suites in common' is not caused by using the default truststore. It is caused by not having a keystore, or not having a private key and certificate in it, or else by overspecifying cipher suites at one peer or the other such that there can be no agreement.

If the server doesn't have a private key, it can't use any cipher suites except the insecure anonymous ones, which are disabled by default, and should stay that way. Hence the alert.

Using the default truststore will cause a different problem if and only if you are using self-signed certificates. Simple solution: don't. More complex solution: export the respective certificates from the respective keystores and import them into the other party's truststore.

See the JSSE Reference Guide.

like image 43
user207421 Avatar answered Oct 12 '22 10:10

user207421