{"record":{"id":"8430c4af65440f16","repo":"elastic/elasticsearch","slug":"cannot-read-encrypted-key-without-a-password","errorCode":null,"errorMessage":"cannot read encrypted key [{}] without a password","messagePattern":"cannot read encrypted key \\[(.+?)\\] without a password","errorType":"exception","errorClass":"SslConfigException","httpStatus":null,"severity":"error","filePath":"libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java","lineNumber":141,"sourceCode":"     * encoded formats of encrypted and plaintext RSA, DSA and EC(secp256r1) keys\n     *\n     * @param keyPath           the path for the key file\n     * @param passwordSupplier A password supplier for the potentially encrypted (password protected) key\n     * @return a private key from the contents of the file\n     */\n    static PrivateKey parsePrivateKey(Path keyPath, Supplier<char[]> passwordSupplier) throws IOException, GeneralSecurityException {\n        try (BufferedReader bReader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8)) {\n            String line = bReader.readLine();\n            while (null != line && line.startsWith(HEADER) == false) {\n                line = bReader.readLine();\n            }\n            if (null == line) {\n                throw new SslConfigException(\"Error parsing Private Key [\" + keyPath.toAbsolutePath() + \"], file is empty\");\n            }\n            if (PKCS8_ENCRYPTED_HEADER.equals(line.trim())) {\n                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()","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java#L123-L159","documentation":"Thrown by PemUtils.parsePrivateKey() when the file's first PEM header is `-----BEGIN ENCRYPTED PRIVATE KEY-----` (PKCS#8 encrypted) but the password supplier returned null. PKCS#8 encrypted keys cannot be decrypted without a password, so parsing aborts immediately.","triggerScenarios":"parsePrivateKey detects PKCS8_ENCRYPTED_HEADER, calls passwordSupplier.get(), and the supplier returns null. Typical when Elasticsearch is configured with an encrypted PEM key but no `ssl.key_passphrase` / secure setting is provided, or when the keystore setting that should hold the passphrase is missing.","commonSituations":"Encrypted PKCS#8 key configured without a corresponding key password in elasticsearch.yml or the Elasticsearch keystore; password setting typo (`key_passphrase` vs `key_password`); password stored in a keystore entry that was not loaded; or the password supplier is wired to return null on missing config.","solutions":["Add the key password to the Elasticsearch keystore: `bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password` (or the equivalent ssl.key_passphrase setting for PEM).","If you do not need encryption, re-export the key unencrypted: `openssl pkcs8 -topk8 -in encrypted.pem -out plain.pem -nocrypt`.","Verify the password setting name matches the SSL context (transport vs http) you are configuring.","Confirm the password is non-empty and matches the one used to encrypt the key."],"exampleFix":"# before: encrypted PKCS#8 key but no password configured\n# elasticsearch.yml\nxpack.security.http.ssl:\n  enabled: true\n  key: encrypted.pk8.pem\n  certificate: cert.pem\n\n# after: add the passphrase via the keystore\nbin/elasticsearch-keystore add xpack.security.http.ssl.key.secure_password\n# (enter the password when prompted; restart Elasticsearch)\n# or re-export the key unencrypted:\nopenssl pkcs8 -topk8 -in encrypted.pk8.pem -out plain.pk8.pem -nocrypt","handlingStrategy":"validation","validationCode":"// Detect encrypted PKCS#8 keys and ensure a password is configured before parsing.\npublic static boolean isEncryptedPkcs8(Path p) throws IOException {\n    try (BufferedReader r = Files.newBufferedReader(p, StandardCharsets.UTF_8)) {\n        String line;\n        while ((line = r.readLine()) != null) {\n            if (line.startsWith(\"-----BEGIN ENCRYPTED PRIVATE KEY-----\")) return true;\n            if (line.startsWith(\"-----BEGIN\")) return false;\n        }\n    }\n    return false;\n}\n\n// Configure Elasticsearch keystore:\n// bin/elasticsearch-keystore add xpack.security.http.ssl.key.secure_password","typeGuard":null,"tryCatchPattern":null,"preventionTips":["If the key starts with `-----BEGIN ENCRYPTED PRIVATE KEY-----`, a password is mandatory.","Store the passphrase in the Elasticsearch keystore, not in plaintext elasticsearch.yml.","If you cannot supply a password, re-export the key unencrypted (`openssl pkcs8 -nocrypt`)."],"tags":["ssl","pem","private-key","password","elasticsearch","crypto","config"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}