{"record":{"id":"5b6603190f282e8c","repo":"elastic/elasticsearch","slug":"pkcs-8-private-key-is-encrypted-with-unsupported-p","errorCode":null,"errorMessage":"PKCS#8 Private Key is encrypted with unsupported PBES2 algorithm [{}]","messagePattern":"PKCS#8 Private Key is encrypted with unsupported PBES2 algorithm \\[(.+?)\\]","errorType":"exception","errorClass":"GeneralSecurityException","httpStatus":null,"severity":"error","filePath":"libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java","lineNumber":429,"sourceCode":"        } catch (IOException e) {\n            // The Sun JCE provider can't handle non-AES PBES2 data (but it can handle PBES1 DES data - go figure)\n            // It's not worth our effort to try and decrypt it ourselves, but we can detect it and give a good error message\n            DerParser parser = new DerParser(keyBytes);\n            final DerParser.Asn1Object rootSeq = parser.readAsn1Object(DerParser.Type.SEQUENCE);\n            parser = rootSeq.getParser();\n            final DerParser.Asn1Object algSeq = parser.readAsn1Object(DerParser.Type.SEQUENCE);\n            parser = algSeq.getParser();\n            final String algId = parser.readAsn1Object(DerParser.Type.OBJECT_OID).getOid();\n            if (PBES2_OID.equals(algId)) {\n                final DerParser.Asn1Object algData = parser.readAsn1Object(DerParser.Type.SEQUENCE);\n                parser = algData.getParser();\n                final DerParser.Asn1Object ignoreKdf = parser.readAsn1Object(DerParser.Type.SEQUENCE);\n                final DerParser.Asn1Object cryptSeq = parser.readAsn1Object(DerParser.Type.SEQUENCE);\n                parser = cryptSeq.getParser();\n                final String encryptionId = parser.readAsn1Object(DerParser.Type.OBJECT_OID).getOid();\n                if (encryptionId.startsWith(AES_OID) == false) {\n                    final String name = getAlgorithmNameFromOid(encryptionId);\n                    throw new GeneralSecurityException(\n                        \"PKCS#8 Private Key is encrypted with unsupported PBES2 algorithm [\"\n                            + encryptionId\n                            + \"]\"\n                            + (name == null ? \"\" : \" (\" + name + \")\"),\n                        e\n                    );\n                }\n            }\n            throw e;\n        }\n    }\n\n    /**\n     * This is horrible, but it's the only option other than to parse the encoded ASN.1 value ourselves\n     * @see AlgorithmParameters#toString() and com.sun.crypto.provider.PBES2Parameters#toString()\n     */\n    private static String getPBES2Algorithm(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo) {\n        final AlgorithmParameters algParameters = encryptedPrivateKeyInfo.getAlgParameters();","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java#L411-L447","documentation":"Thrown by getEncryptedPrivateKeyInfo as a fallback when the JCE cannot construct an EncryptedPrivateKeyInfo and manual ASN.1 parsing reveals the key is PBES2-encrypted with a cipher whose OID does not start with the AES OID prefix (2.16.840.1.101.3.4.1). Only AES variants are supported under PBES2; anything else (e.g. RC2, DES, Camellia under PBES2) is rejected with a descriptive OID and optional algorithm name.","triggerScenarios":"Loading an encrypted PKCS#8 key produced by 'openssl pkcs8 -topk8 -v2 <cipher>' where <cipher> is a non-AES cipher such as 'des3', 'rc2', or 'camellia'; a key produced by a third-party tool (e.g. old Java BouncyCastle defaults, NSS, or Windows certmgr) that selected a non-AES PBES2 cipher.","commonSituations":"Operators migrating from older OpenSSL defaults; keys generated by enterprise PKI tooling that mandates non-AES ciphers; interoperability with legacy HSMs; keys produced with 'openssl pkcs8 -v1 des3' (which is PBES1, handled separately) versus '-v2 des3' (PBES2 with 3DES, which is NOT supported here).","solutions":["Re-encrypt the key with an AES cipher: 'openssl pkcs8 -topk8 -in current.key -out new.key -v2 aes-256-cbc'.","If the key was produced by an older OpenSSL, regenerate it with a modern default (modern OpenSSL defaults to AES-256-CBC under PBES2).","If a third-party tool generated the key, export it from that tool in plaintext or PKCS#8 AES and re-import."],"exampleFix":"// before: encrypt with 3DES under PBES2 (unsupported)\n//   openssl pkcs8 -topk8 -inkey raw.key -out enc.key -v2 des3\n// after: encrypt with AES-256-CBC under PBES2\nopenssl pkcs8 -topk8 -inkey raw.key -out enc.key -v2 aes-256-cbc","handlingStrategy":"try-catch","validationCode":"// Inspect the PBES2 cipher OID before passing the key to Elasticsearch\n// openssl asn1parse -in enc.key -strparse 4 gives the encryption algorithm; confirm it starts with 2.16.840.1.101.3.4.1 (AES).\n// Alternatively: openssl pkcs8 -topk8 -in current.key -out new.key -v2 aes-256-cbc (re-encrypt to a supported cipher).","typeGuard":null,"tryCatchPattern":"try {\n    PemUtils.readPrivateKey(path, passwordSupplier);\n} catch (GeneralSecurityException e) {\n    if (e.getMessage().contains(\"unsupported PBES2 algorithm\")) {\n        // re-encrypt with AES-256-CBC and retry\n    } else throw e;\n}","preventionTips":["Standardise on AES-256-CBC for encrypted PKCS#8 keys across your PKI tooling.","Document the supported PBES2 ciphers (AES only) in your key-generation runbook.","Audit keys generated by third-party tools with 'openssl asn1parse' before importing."],"tags":["ssl","pem","pkcs8","encrypted","pbes2","crypto"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}