elastic/elasticsearch · error · GeneralSecurityException

PKCS#8 Private Key is encrypted with unsupported PBES2 algor

Error message

PKCS#8 Private Key is encrypted with unsupported PBES2 algorithm [{}]

What it means

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.

Source

Thrown at libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java:429

        } catch (IOException e) {
            // The Sun JCE provider can't handle non-AES PBES2 data (but it can handle PBES1 DES data - go figure)
            // It's not worth our effort to try and decrypt it ourselves, but we can detect it and give a good error message
            DerParser parser = new DerParser(keyBytes);
            final DerParser.Asn1Object rootSeq = parser.readAsn1Object(DerParser.Type.SEQUENCE);
            parser = rootSeq.getParser();
            final DerParser.Asn1Object algSeq = parser.readAsn1Object(DerParser.Type.SEQUENCE);
            parser = algSeq.getParser();
            final String algId = parser.readAsn1Object(DerParser.Type.OBJECT_OID).getOid();
            if (PBES2_OID.equals(algId)) {
                final DerParser.Asn1Object algData = parser.readAsn1Object(DerParser.Type.SEQUENCE);
                parser = algData.getParser();
                final DerParser.Asn1Object ignoreKdf = parser.readAsn1Object(DerParser.Type.SEQUENCE);
                final DerParser.Asn1Object cryptSeq = parser.readAsn1Object(DerParser.Type.SEQUENCE);
                parser = cryptSeq.getParser();
                final String encryptionId = parser.readAsn1Object(DerParser.Type.OBJECT_OID).getOid();
                if (encryptionId.startsWith(AES_OID) == false) {
                    final String name = getAlgorithmNameFromOid(encryptionId);
                    throw new GeneralSecurityException(
                        "PKCS#8 Private Key is encrypted with unsupported PBES2 algorithm ["
                            + encryptionId
                            + "]"
                            + (name == null ? "" : " (" + name + ")"),
                        e
                    );
                }
            }
            throw e;
        }
    }

    /**
     * This is horrible, but it's the only option other than to parse the encoded ASN.1 value ourselves
     * @see AlgorithmParameters#toString() and com.sun.crypto.provider.PBES2Parameters#toString()
     */
    private static String getPBES2Algorithm(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo) {
        final AlgorithmParameters algParameters = encryptedPrivateKeyInfo.getAlgParameters();

View on GitHub (pinned to db6a809a66)

Solutions

  1. Re-encrypt the key with an AES cipher: 'openssl pkcs8 -topk8 -in current.key -out new.key -v2 aes-256-cbc'.
  2. If the key was produced by an older OpenSSL, regenerate it with a modern default (modern OpenSSL defaults to AES-256-CBC under PBES2).
  3. If a third-party tool generated the key, export it from that tool in plaintext or PKCS#8 AES and re-import.

Example fix

// before: encrypt with 3DES under PBES2 (unsupported)
//   openssl pkcs8 -topk8 -inkey raw.key -out enc.key -v2 des3
// after: encrypt with AES-256-CBC under PBES2
openssl pkcs8 -topk8 -inkey raw.key -out enc.key -v2 aes-256-cbc
Defensive patterns

Strategy: try-catch

Validate before calling

// Inspect the PBES2 cipher OID before passing the key to Elasticsearch
// openssl asn1parse -in enc.key -strparse 4 gives the encryption algorithm; confirm it starts with 2.16.840.1.101.3.4.1 (AES).
// Alternatively: openssl pkcs8 -topk8 -in current.key -out new.key -v2 aes-256-cbc (re-encrypt to a supported cipher).

Try / catch

try {
    PemUtils.readPrivateKey(path, passwordSupplier);
} catch (GeneralSecurityException e) {
    if (e.getMessage().contains("unsupported PBES2 algorithm")) {
        // re-encrypt with AES-256-CBC and retry
    } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/5b6603190f282e8c. Report an issue: GitHub.