elastic/elasticsearch · error · CertificateException

This trust manager is for client use only and cannot trust o

Error message

This trust manager is for client use only and cannot trust other clients

What it means

Thrown by the same custom X509TrustManager's `checkClientTrusted` override. The trust manager built by `buildTrustManagerFromLeafCertificates` is purpose-built for CLIENT-side verification of a SERVER (leaf-pinning); it explicitly refuses to act as a server-side trust manager that validates inbound client certs. Calling `checkClientTrusted` is a misuse of this manager.

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/SslTrustResolver.java:177

        var trustManager = new X509TrustManager() {
            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                final X509Certificate leaf = chain[0];
                if (trusted.contains(leaf) == false) {
                    throw new CertificateException("Untrusted leaf certificate: " + leaf.getSubjectX500Principal());
                }
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                // This doesn't apply when trusting leaf certs, and is only really needed for server trust managers anyways
                return new X509Certificate[0];
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                throw new CertificateException("This trust manager is for client use only and cannot trust other clients");
            }

        };
        return new TrustManager[] { trustManager };
    }

    private static Collection<Certificate> readCertificatesFromKeystore(File file, String password) throws GeneralSecurityException,
        IOException {
        var keyStore = readKeyStoreFromFile(file, password);
        final Set<Certificate> certificates = new HashSet<>(keyStore.size());
        var enumeration = keyStore.aliases();
        while (enumeration.hasMoreElements()) {
            var alias = enumeration.nextElement();
            if (keyStore.isKeyEntry(alias)) {
                certificates.add(keyStore.getCertificate(alias));
            }
        }
        return certificates;

View on GitHub (pinned to db6a809a66)

Solutions

  1. Use CA-based or trustStore-based trust (`certificateAuthorities` / `trustStoreFile`) instead of `serverCertificate` when client-cert verification is needed — those build standard `X509TrustManager`s that support both directions.
  2. If you only need server verification, ensure no code path triggers client-cert checking (don't install this manager on a server socket).
  3. Re-architect the test to use the testclusters framework's built-in SSL setup rather than a hand-rolled context.

Example fix

// before: leaf mode cannot do mTLS
testClusters.c.serverCertificate = file('leaf.pem')
// after: CA mode supports both directions
testClusters.c.certificateAuthorities = [file('ca.pem')]
Defensive patterns

Strategy: validation

Validate before calling

// Detect leaf-pinning mode and refuse server-side mTLS use
if (serverCertificate != null && needsClientCertValidation) {
  throw new IllegalStateException("Leaf-pin trust manager cannot validate client certs; use CA mode.");
}

Prevention

When it happens

Trigger: This trust manager (built from `serverCertificate` leaf config) is installed into a context performing server-side client-cert verification (mutual TLS where ES acts as server validating client certs). The resolver's leaf mode only supports one direction.

Common situations: A test inadvertently uses leaf-pinning trust config in a context that needs bidirectional TLS; wiring the test client's trust manager into a server socket factory; custom networking code that calls `sslContext.init(..., trustManager, ...)` and then the runtime invokes `checkClientTrusted` during an mTLS handshake.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/6de4981cf8829a03. Report an issue: GitHub.