elastic/elasticsearch · error · SslConfigException
could not load ssl private key file [{}]
Error message
could not load ssl private key file [{}] What it means
Thrown by PemUtils.readPrivateKey() (the public wrapper around parsePrivateKey) when parsePrivateKey returns null. readPrivateKey is the entry point used by other Elastic SSL code that wants SslFileUtil-style error wrapping; the null return means the file was readable but contained no recognised private-key PEM block.
Source
Thrown at libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java:109
*/
private static final String DEPRECATED_DES_EDE_ALGORITHM = "DESede";
private PemUtils() {
throw new IllegalStateException("Utility class should not be instantiated");
}
/**
* Creates a {@link PrivateKey} from the contents of a file and handles any exceptions
*
* @param path the path for the key file
* @param passwordSupplier A password supplier for the potentially encrypted (password protected) key
* @return a private key from the contents of the file
*/
public static PrivateKey readPrivateKey(Path path, Supplier<char[]> passwordSupplier) throws IOException, GeneralSecurityException {
try {
final PrivateKey privateKey = PemUtils.parsePrivateKey(path, passwordSupplier);
if (privateKey == null) {
throw new SslConfigException("could not load ssl private key file [" + path + "]");
}
return privateKey;
} catch (SecurityException e) {
throw SslFileUtil.accessControlFailure("PEM private key", List.of(path), e, null);
} catch (IOException e) {
throw SslFileUtil.ioException("PEM private key", List.of(path), e);
} catch (GeneralSecurityException e) {
throw SslFileUtil.securityException("PEM private key", List.of(path), e);
}
}
/**
* Creates a {@link PrivateKey} from the contents of a file. Supports PKCS#1, PKCS#8
* encoded formats of encrypted and plaintext RSA, DSA and EC(secp256r1) keys
*
* @param keyPath the path for the key file
* @param passwordSupplier A password supplier for the potentially encrypted (password protected) key
* @return a private key from the contents of the fileView on GitHub (pinned to db6a809a66)
Solutions
- Inspect the first non-blank line of the file — it must start with `-----BEGIN` and match a supported header.
- Convert OpenSSH keys to PEM: `ssh-keygen -p -m PEM -f id_rsa`.
- Re-export as PKCS#8: `openssl pkcs8 -topk8 -inkey key.pem -out key.pk8.pem -nocrypt`.
- Verify the file is a private key (not a cert): `openssl pkey -in key.pem -noout` should succeed.
Example fix
// before: passing a public-key-only file PrivateKey pk = PemUtils.readPrivateKey(pubKeyPath, () -> null); // throws // after: pass the actual private key PrivateKey pk = PemUtils.readPrivateKey(privateKeyPath, () -> keyPassword);
Defensive patterns
Strategy: validation
Validate before calling
public static boolean fileContainsPrivateKey(Path p) throws IOException {
try (BufferedReader r = Files.newBufferedReader(p, StandardCharsets.UTF_8)) {
String line;
while ((line = r.readLine()) != null) {
if (line.startsWith("-----BEGIN") && line.contains("PRIVATE KEY")) return true;
}
}
return false;
} Prevention
- Confirm the file is a private key (not a certificate or public key).
- Convert OpenSSH keys to PKCS#8 PEM.
- Use `openssl pkey -in key.pem -noout` to verify before configuring.
When it happens
Trigger: readPrivateKey(path, passwordSupplier) calls parsePrivateKey(path, passwordSupplier); result is null. This is the same condition as error 795 but surfaced through the PemUtils API rather than PemKeyConfig — it indicates the file lacks any of the supported headers (PKCS#1 RSA, PKCS#8, PKCS#8 encrypted, OpenSSL DSA, OpenSSL EC).
Common situations: File is empty, contains only a public key, contains an OpenSSH-format key, or is a certificate rather than a private key. Note that parsePrivateKey actually throws SslConfigException for unsupported formats rather than returning null, so a true null is rare and typically comes from a future code path that may return null for an empty/unparseable file.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- could not load ssl private key file [{}]
- Error parsing Private Key [{}], file is empty
- cannot read encrypted key [{}] without a password
- Expected ASN.1 object of type 0x{} but was 0x{}
- Invalid DER: stream too short, missing tag
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/473ee720431a87ad.
Report an issue: GitHub.