{"record":{"id":"6b9ef794688d7346","repo":"elastic/elasticsearch","slug":"cannot-read-pem-private-key-because-the-file","errorCode":null,"errorMessage":"cannot read PEM private key [{}] because the file does not contain a supported key format","messagePattern":"cannot read PEM private key \\[(.+?)\\] because the file does not contain a supported key format","errorType":"exception","errorClass":"SslConfigException","httpStatus":null,"severity":"error","filePath":"libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java","lineNumber":157,"sourceCode":"                char[] password = passwordSupplier.get();\n                if (password == null) {\n                    throw new SslConfigException(\"cannot read encrypted key [\" + keyPath.toAbsolutePath() + \"] without a password\");\n                }\n                return parsePKCS8Encrypted(bReader, password);\n            } else if (PKCS8_HEADER.equals(line.trim())) {\n                return parsePKCS8(bReader);\n            } else if (PKCS1_HEADER.equals(line.trim())) {\n                return parsePKCS1Rsa(bReader, passwordSupplier);\n            } else if (OPENSSL_DSA_HEADER.equals(line.trim())) {\n                return parseOpenSslDsa(bReader, passwordSupplier);\n            } else if (OPENSSL_DSA_PARAMS_HEADER.equals(line.trim())) {\n                return parseOpenSslDsa(removeDsaHeaders(bReader), passwordSupplier);\n            } else if (OPENSSL_EC_HEADER.equals(line.trim())) {\n                return parseOpenSslEC(bReader, passwordSupplier);\n            } else if (OPENSSL_EC_PARAMS_HEADER.equals(line.trim())) {\n                return parseOpenSslEC(removeECHeaders(bReader), passwordSupplier);\n            } else {\n                throw new SslConfigException(\n                    \"cannot read PEM private key [\"\n                        + keyPath.toAbsolutePath()\n                        + \"] because the file does not contain a supported key format\"\n                );\n            }\n        }\n    }\n\n    /**\n     * Removes the EC Headers that OpenSSL adds to EC private keys as the information in them\n     * is redundant\n     *\n     * @throws IOException if the EC Parameter footer is missing\n     */\n    private static BufferedReader removeECHeaders(BufferedReader bReader) throws IOException {\n        String line = bReader.readLine();\n        while (line != null) {\n            if (OPENSSL_EC_PARAMS_FOOTER.equals(line.trim())) {","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java#L139-L175","documentation":"This SslConfigException is thrown by parsePrivateKey after the parser scans the file for a '-----BEGIN' header but no recognized PEM private-key header is found (the supported headers are PKCS#8, PKCS#8 ENCRYPTED, PKCS#1 RSA, OpenSSL DSA, DSA PARAMETERS, OpenSSL EC, and EC PARAMETERS). It is the catch-all for any file that is a PEM file but not one of the supported private-key formats. The absolute path is interpolated into the message so the offending file is easy to identify.","triggerScenarios":"Calling PemUtils.readPrivateKey(path, passwordSupplier) (or the package-private parsePrivateKey) where the first '-----BEGIN' line in the file is something like '-----BEGIN CERTIFICATE-----', '-----BEGIN PUBLIC KEY-----', '-----BEGIN X509 CRL-----', or any non-private-key PEM header. Also fires if the file has only a header that is not in the supported list (e.g. an OpenSSH-format key '-----BEGIN OPENSSH PRIVATE KEY-----').","commonSituations":"Pointing the SSL key configuration at a certificate file instead of the private key file; passing a public key PEM; using an OpenSSH/new-style ED25519 key generated by 'ssh-keygen -o' or 'ssh-keygen -t ed25519'; truncating/corrupting the key file so the first BEGIN line is unrecognised; mixing up the order of cert and key arguments in Elasticsearch xpack.ssl.* settings.","solutions":["Verify the file actually contains a private key: run 'head -1 <file>' and confirm the line is one of the supported BEGIN markers (PRIVATE KEY, RSA PRIVATE KEY, DSA PRIVATE KEY, EC PRIVATE KEY, ENCRYPTED PRIVATE KEY).","If you pointed at a certificate by mistake, change the config to reference the private-key file (e.g. xpack.http.ssl.key instead of certificate).","If the key is OpenSSH/ED25519 format ('-----BEGIN OPENSSH PRIVATE KEY-----'), regenerate it in PKCS#8 or PKCS#1 with OpenSSL: 'openssl pkcs8 -topk8 -in sshkey -out pkcs8key.pem' or 'openssl rsa -in sshkey -out rsakey.pem'.","Regenerate the key with 'openssl genrsa -out key.pem 2048' (RSA) or 'openssl ecparam -genkey -name prime256v1 -out key.pem' (EC) to get a directly supported format."],"exampleFix":"// before: config points at a certificate\nxpack.security.transport.ssl.key: /etc/elasticsearch/certs/node.crt.pem\n// after: config points at the PKCS#8 private key\nxpack.security.transport.ssl.key: /etc/elasticsearch/certs/node.key.pem","handlingStrategy":"validation","validationCode":"// Before calling readPrivateKey, confirm the file's first BEGIN line is a supported private-key header\nprivate static final Set<String> SUPPORTED_KEY_HEADERS = Set.of(\n    \"-----BEGIN PRIVATE KEY-----\",\n    \"-----BEGIN ENCRYPTED PRIVATE KEY-----\",\n    \"-----BEGIN RSA PRIVATE KEY-----\",\n    \"-----BEGIN DSA PRIVATE KEY-----\",\n    \"-----BEGIN DSA PARAMETERS-----\",\n    \"-----BEGIN EC PRIVATE KEY-----\",\n    \"-----BEGIN EC PARAMETERS-----\"\n);\nstatic void assertSupportedKey(Path keyPath) throws IOException {\n    try (BufferedReader r = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8)) {\n        String line = r.readLine();\n        while (line != null && !line.startsWith(\"-----BEGIN\")) line = r.readLine();\n        if (line == null || !SUPPORTED_KEY_HEADERS.contains(line.trim())) {\n            throw new IllegalArgumentException(\"File [\" + keyPath + \"] is not a supported PEM private key (first header: \" + line + \")\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    PrivateKey key = PemUtils.readPrivateKey(keyPath, passwordSupplier);\n} catch (SslConfigException e) {\n    if (e.getMessage().contains(\"does not contain a supported key format\")) {\n        // log + prompt user to supply a PKCS#8/PKCS#1/EC/DSA key\n    } else throw e;\n}","preventionTips":["Adopt a deployment convention: name private-key files '*.key.pem' and certificate files '*.crt.pem' to avoid swapping them.","In CI, run 'openssl pkey -in <keyfile> -noout' as a smoke test before deploying.","Document the supported key formats (PKCS#8, PKCS#1 RSA, OpenSSL DSA/EC) next to the SSL config in your runbook."],"tags":["ssl","pem","config","elasticsearch","private-key"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}