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
- 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.
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
- 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.
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
- Cannot specify more than one trust method (CA=%s, trustStore
- Trust-store does not contain any trusted certificate entries
- Untrusted leaf certificate: {}
- Can not use {} with {}
- SSL trust has been configured, but [{}] is not a 'https' URL
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/6de4981cf8829a03.
Report an issue: GitHub.