Add trustStore for client authentication [duplicat

2019-03-16 21:01发布

问题:

This question already has an answer here:

  • SSLHandshakeException: no cipher suites in common 2 answers

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);

回答1:

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



回答2:

'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.