javasslx509trustmanager

Implementing X509TrustManager


I'm currently trying to transfer data over the internet via SSL/TLS in java and I want both parties to authenticate themselves. I have implemented the KeyManager myself to load the key pair and present the other party the appropriate certificate.

Now, I'm trying to check the certificate and I'm doing that by implementing my own TrustManager (both parties hold the cert of the other party, everything is self-signed). However, getAcceptedIssuers doesn't work like I want it to, because even when I return none the connection still gets established without problem.

Why doesn't the certificate get refused?

protected static class SelectingTrustManager implements X509TrustManager{
    final X509TrustManager delegate;

    private String[] trustedAliases;
    private final KeyStore keystore;

    public SelectingTrustManager(X509TrustManager delegate, KeyStore keystore, String[] trustedAliases) {
        this.trustedAliases = trustedAliases;
        this.keystore = keystore;
        this.delegate = delegate;
    }

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException{
        delegate.checkClientTrusted(chain, authType);
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException{
        delegate.checkServerTrusted(chain, authType);
    }

    public X509Certificate[] getAcceptedIssuers(){
        return new X509Certificate[0];
    }

}

Solution

  • You aren't clear if your code is client or server, so I answer both, although it pretty much matters only for server.

    Although the javadoc isn't specific, X509TM.getAcceptedIssuers is NOT used to decide whether to trust a received cert or chain; that is done solely by checkServerTrusted in the client or checkClientTrusted in the server.

    The value of getAcceptedIssuers is used for, and affects, only two things:

    In the specific case of no 'CAs' (an array of 0 length, as you have), the client can send a cert from any CA it chooses, and the server will accept it depending only on checkClientTrusted.

    For completeness note the RFCs define an extension for the client to specify what CA(s) it wants the server cert to use, but I don't know any implementation that supports this extension and Java/JSSE definitely doesn't, so in practice the server either has only one cert (per algorithm), or it selects based on SNI (and nothing else), and if that cert isn't trusted by the client too bad.

    Whether the person who put the cert in a truststore or otherwise made it an anchor actually evaluated its security correctly is a different question that Java doesn't try to answer. Even Stackexchange may not be able to do that, although I'm sure there will be people here glad to try. (I make no commitment whether I will be one of them.)