{"record":{"id":"6de4981cf8829a03","repo":"elastic/elasticsearch","slug":"this-trust-manager-is-for-client-use-only-and-cann","errorCode":null,"errorMessage":"This trust manager is for client use only and cannot trust other clients","messagePattern":"This trust manager is for client use only and cannot trust other clients","errorType":"exception","errorClass":"CertificateException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/SslTrustResolver.java","lineNumber":177,"sourceCode":"\n        var trustManager = new X509TrustManager() {\n            @Override\n            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n                final X509Certificate leaf = chain[0];\n                if (trusted.contains(leaf) == false) {\n                    throw new CertificateException(\"Untrusted leaf certificate: \" + leaf.getSubjectX500Principal());\n                }\n            }\n\n            @Override\n            public X509Certificate[] getAcceptedIssuers() {\n                // This doesn't apply when trusting leaf certs, and is only really needed for server trust managers anyways\n                return new X509Certificate[0];\n            }\n\n            @Override\n            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n                throw new CertificateException(\"This trust manager is for client use only and cannot trust other clients\");\n            }\n\n        };\n        return new TrustManager[] { trustManager };\n    }\n\n    private static Collection<Certificate> readCertificatesFromKeystore(File file, String password) throws GeneralSecurityException,\n        IOException {\n        var keyStore = readKeyStoreFromFile(file, password);\n        final Set<Certificate> certificates = new HashSet<>(keyStore.size());\n        var enumeration = keyStore.aliases();\n        while (enumeration.hasMoreElements()) {\n            var alias = enumeration.nextElement();\n            if (keyStore.isKeyEntry(alias)) {\n                certificates.add(keyStore.getCertificate(alias));\n            }\n        }\n        return certificates;","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/SslTrustResolver.java#L159-L195","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","If you only need server verification, ensure no code path triggers client-cert checking (don't install this manager on a server socket).","Re-architect the test to use the testclusters framework's built-in SSL setup rather than a hand-rolled context."],"exampleFix":"// before: leaf mode cannot do mTLS\ntestClusters.c.serverCertificate = file('leaf.pem')\n// after: CA mode supports both directions\ntestClusters.c.certificateAuthorities = [file('ca.pem')]","handlingStrategy":"validation","validationCode":"// Detect leaf-pinning mode and refuse server-side mTLS use\nif (serverCertificate != null && needsClientCertValidation) {\n  throw new IllegalStateException(\"Leaf-pin trust manager cannot validate client certs; use CA mode.\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reserve `serverCertificate` (leaf pinning) for client-to-server verification only.","For mutual TLS, always configure `certificateAuthorities` or `trustStoreFile`.","Document the directional limitation of leaf-pin trust in the SSL setup helper."],"tags":["gradle","testclusters","ssl","tls","mtls","build-tools"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}