Search code examples
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 server, (only) if client auth is enabled (by calling needClientAuth(true) or wantClientAuth(true)), the Subject names from its elements are used to create the CA list in the server's CertificateRequest message. This is not forced to be the same as the list of CAs that will be used as trust anchors for the client cert chain, if one is received; in fact, the trustmanager isn't actually required to use a list of trust anchors or even the rest of the standard validation algorithm -- although if your 'delegate' is the standard X509[Extended]TrustManager which uses the standard CertPathValidator that does. However, if you tell client(s) to use cert(s) from certain CAs, and then don't accept valid cert chain(s) from those CAs, you will likely have unhappy client(s) who may come after you with various heavy, sharp and/or otherwise unpleasant objects.

    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.

    • if you have algorithm constraints in effect (and nowadays you usually do by default even if you don't explicitly set some) they are not enforced on the last cert in a chain (the putative anchor) if it is among the certs returned by getAcceptedIssuers, which are presumed to be (actual) anchors. In other words if a cert is a trust anchor presumably the user has decided to trust it even though it may use algorithms that do not meet current standards (like MD5, or RSA smaller than 1024).

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