{"record":{"id":"5c8406897c64af8f","repo":"elastic/elasticsearch","slug":"cannot-read-encrypted-key-without-a-password-5c8406","errorCode":null,"errorMessage":"cannot read encrypted key without a password","messagePattern":"cannot read encrypted key without a password","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java","lineNumber":480,"sourceCode":"     * @param passwordSupplier A password supplier for the encrypted (password protected) key\n     * @return the decrypted key bytes\n     * @throws GeneralSecurityException if the key can't be decrypted\n     * @throws IOException              if the PEM headers are missing or malformed\n     */\n    private static byte[] possiblyDecryptPKCS1Key(Map<String, String> pemHeaders, String keyContents, Supplier<char[]> passwordSupplier)\n        throws GeneralSecurityException, IOException {\n        byte[] keyBytes = Base64.getDecoder().decode(keyContents);\n        String procType = pemHeaders.get(\"Proc-Type\");\n        if (\"4,ENCRYPTED\".equals(procType)) {\n            // We only handle PEM encryption\n            String encryptionParameters = pemHeaders.get(\"DEK-Info\");\n            if (null == encryptionParameters) {\n                // malformed pem\n                throw new IOException(\"Malformed PEM File, DEK-Info header is missing\");\n            }\n            char[] password = passwordSupplier.get();\n            if (password == null) {\n                throw new IOException(\"cannot read encrypted key without a password\");\n            }\n            Cipher cipher = getCipherFromParameters(encryptionParameters, password);\n            byte[] decryptedKeyBytes = cipher.doFinal(keyBytes);\n            return decryptedKeyBytes;\n        }\n        return keyBytes;\n    }\n\n    /**\n     * Creates a {@link Cipher} from the contents of the DEK-Info header of a PEM file. RFC 1421 indicates that supported algorithms are\n     * defined in RFC 1423. RFC 1423 only defines DES-CBS and triple DES (EDE) in CBC mode. AES in CBC mode is also widely used though ( 3\n     * different variants of 128, 192, 256 bit keys )\n     *\n     * @param dekHeaderValue The value of the DEK-Info PEM header\n     * @param password       The password with which the key is encrypted\n     * @return a cipher of the appropriate algorithm and parameters to be used for decryption\n     * @throws GeneralSecurityException if the algorithm is not available in the used security provider, or if the key is inappropriate\n     * for the cipher","sourceCodeStart":462,"sourceCodeEnd":498,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java#L462-L498","documentation":"Thrown by possiblyDecryptPKCS1Key when the PEM is marked 'Proc-Type: 4,ENCRYPTED' and a DEK-Info header exists, but the password supplier returns null. The library cannot decrypt an OpenSSL-format encrypted key without a password, so it aborts rather than attempting a no-op decrypt.","triggerScenarios":"Calling PemUtils.readPrivateKey(path, passwordSupplier) where passwordSupplier.get() returns null for an encrypted OpenSSL-format key; the Elasticsearch SSL keystore password setting is empty or unset while the key file is encrypted.","commonSituations":"Misconfigured xpack.ssl.secure_key_pass / keystore.password; the password was added to the wrong keystore entry; the password supplier reads from an environment variable that is unset in the running process; deploying an encrypted key but forgetting to provision the secret.","solutions":["Configure the password: in Elasticsearch, store it with 'bin/elasticsearch-keystore add <setting>.secure_key_pass' (e.g. xpack.security.transport.ssl.secure_key_pass).","Ensure the password supplier returns a non-null char[] for encrypted keys.","If the key is not meant to be encrypted, regenerate it without a passphrase: 'openssl rsa -in enc.key -out plain.key'.","Verify the running process has access to whatever source the password supplier reads (env var, secret store, file permissions)."],"exampleFix":"// before: supplier returns null for an encrypted key\nSupplier<char[]> pw = () -> null;\nPemUtils.readPrivateKey(keyPath, pw);\n// after: supplier resolves the password (e.g. from a secure keystore)\nSupplier<char[]> pw = () -> keystore.getCharArray(\"xpack.security.transport.ssl.secure_key_pass\");\nPemUtils.readPrivateKey(keyPath, pw);","handlingStrategy":"validation","validationCode":"// Ensure the password supplier returns a non-null char[] before reading an encrypted key\nchar[] pw = passwordSupplier.get();\nif (pw == null || pw.length == 0) {\n    throw new IllegalStateException(\"Encrypted key requires a non-empty password; configure xpack.*.secure_key_pass in the keystore\");\n}","typeGuard":null,"tryCatchPattern":"try { PemUtils.readPrivateKey(path, passwordSupplier); }\ncatch (IOException e) { if (e.getMessage().contains(\"cannot read encrypted key without a password\")) { /* provision password */ } else throw e; }","preventionTips":["Provision the key password via 'bin/elasticsearch-keystore add <setting>.secure_key_pass'.","Test the password supplier in isolation before wiring it into SSL config.","If the key is not meant to be encrypted, export it unencrypted to remove the dependency."],"tags":["ssl","pem","encrypted","password","config"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}