I am trying to write a custom X509TrustManager that will use the default system trust store, but allowing only a restricted set of trusted CA roots.
I am trying to do this by returning a modified list of accepted CA roots from the getAcceptedIssuers method, but this does not seem to work -- server certificates are accepted as valid even when the root certificate is not part of the list returned by getAcceptedIssuers.
Here is a simple implementation that delegates to the system's default trust manager, but overrides getAcceptedIssuers to return an empty array:
import java.security.KeyStore;
import java.security.cert.*;
import javax.net.ssl.*;
public class DefaultTrustManagerWrapper implements X509TrustManager {
private final X509TrustManager defaultTrustManager;
public DefaultTrustManagerWrapper() throws Exception {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null); // Init with default keystore
// Find the X509TrustManager instance from the array of trust managers
X509TrustManager foundTrustManager = null;
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
defaultTrustManager = (X509TrustManager) tm;
}
}
if (defaultTrustManager == null) {
throw new IllegalStateException("No X509TrustManager found");
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
defaultTrustManager.checkClientTrusted(chain, authType);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
defaultTrustManager.checkServerTrusted(chain, authType);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// Return no accepted issuers
return new X509Certificate[0];
}
}
But when using this, server certificates still validate OK.
Why is this happening? Isn't getAcceptedIssuers called by default when validating a server certificate?
According to the accepted answer to a related question,
getAcceptedIssuersis not used to decide whether to trust a certificate. So that would explain the behaviour I am seeing.The linked answer also includes some additional detail on when is
getAcceptedIssuersactually used.