This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit e3222ae8bac52e8b3c0be8c66d98f13b58551fc1
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Oct 20 15:54:33 2023 +0100

    Fix BZ 67675 - Expand the PBKDF2 and cipher combinations supported
    
    Java only directly supports a sub-set of the possible combinations.
    Process the PBKDF2 configuration and cipher configuration
    separately thereby increasing the range or supported combinations.
---
 java/org/apache/tomcat/util/buf/Asn1Parser.java    |  48 ++-
 .../tomcat/util/net/jsse/LocalStrings.properties   |   5 +
 java/org/apache/tomcat/util/net/jsse/PEMFile.java  | 326 ++++++++++++++++-----
 .../apache/tomcat/util/net/jsse/TestPEMFile.java   |  20 +-
 .../key-encrypted-pkcs8-hmacsha256-aes-128-cbc.pem |  54 ++++
 ...key-encrypted-pkcs8-hmacsha256-aes-256-cbc.pem} |   0
 ...key-encrypted-pkcs8-hmacsha256-des-ede3-cbc.pem |  54 ++++
 7 files changed, 430 insertions(+), 77 deletions(-)

diff --git a/java/org/apache/tomcat/util/buf/Asn1Parser.java 
b/java/org/apache/tomcat/util/buf/Asn1Parser.java
index e32e71886f..92d13c02a8 100644
--- a/java/org/apache/tomcat/util/buf/Asn1Parser.java
+++ b/java/org/apache/tomcat/util/buf/Asn1Parser.java
@@ -30,6 +30,13 @@ public class Asn1Parser {
 
     private static final StringManager sm = 
StringManager.getManager(Asn1Parser.class);
 
+    public static final int TAG_INTEGER = 0x02;
+    public static final int TAG_OCTET_STRING = 0x04;
+    public static final int TAG_NULL = 0x05;
+    public static final int TAG_OID = 0x06;
+    public static final int TAG_SEQUENCE = 0x30;
+    public static final int TAG_ATTRIBUTE_BASE = 0xA0;
+
     private final byte[] source;
 
     private int pos = 0;
@@ -50,6 +57,11 @@ public class Asn1Parser {
     }
 
 
+    public void parseTagSequence() {
+        parseTag(TAG_SEQUENCE);
+    }
+
+
     public void parseTag(int tag) {
         int value = next();
         if (value != tag) {
@@ -83,15 +95,41 @@ public class Asn1Parser {
 
 
     public BigInteger parseInt() {
-        parseTag(0x02);
-        int len = parseLength();
-        byte[] val = new byte[len];
-        System.arraycopy(source, pos, val, 0, len);
-        pos += len;
+        byte[] val = parseBytes(TAG_INTEGER);
         return new BigInteger(val);
     }
 
 
+    public byte[] parseOctetString() {
+        return parseBytes(TAG_OCTET_STRING);
+    }
+
+
+    public void parseNull() {
+        parseBytes(TAG_NULL);
+    }
+
+
+    public byte[] parseOIDAsBytes() {
+        return parseBytes(TAG_OID);
+    }
+
+
+    public byte[] parseAttributeAsBytes(int index) {
+        return parseBytes(TAG_ATTRIBUTE_BASE + index);
+    }
+
+
+    private byte[] parseBytes(int tag) {
+        parseTag(tag);
+        int len = parseLength();
+        byte[] result = new byte[len];
+        System.arraycopy(source, pos, result, 0, result.length);
+        pos += result.length;
+        return result;
+    }
+
+
     public void parseBytes(byte[] dest) {
         System.arraycopy(source, pos, dest, 0, dest.length);
         pos += dest.length;
diff --git a/java/org/apache/tomcat/util/net/jsse/LocalStrings.properties 
b/java/org/apache/tomcat/util/net/jsse/LocalStrings.properties
index b276db95ab..888a2a6761 100644
--- a/java/org/apache/tomcat/util/net/jsse/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/jsse/LocalStrings.properties
@@ -21,4 +21,9 @@ jsseUtil.noDefaultProtocols=Unable to determine a default for 
sslEnabledProtocol
 
 pemFile.noMultiPrimes=The PKCS#1 certificate is in multi-prime format and Java 
does not provide an API for constructing an RSA private key object from that 
format
 pemFile.notValidRFC5915=The provided key file does not conform to RFC 5915
+pemFile.notPbkdf2=The OID [{0}] is not the correct OID for PKBDF2 which is the 
only permitted KDF for PBES2
 pemFile.parseError=Unable to parse the key from [{0}]
+pemFile.unknownEncryptedFormat=The format [{0}] is not a recognised encrypted 
PEM file format
+pemFile.unknownEncryptionAlgorithm=The encryption algorithm with DER encoded 
OID of [{0}] was not recognised
+pemFile.unknownPrfAlgorithm=The pseudo random function with DER encoded OID of 
[{0}] was not recognised
+pemFile.unknownPkcs8Algorithm=The PKCS#8 encryption algorithm with DER encoded 
OID of [{0}] was not recognised
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/net/jsse/PEMFile.java 
b/java/org/apache/tomcat/util/net/jsse/PEMFile.java
index d7f196bb3a..2785f9761c 100644
--- a/java/org/apache/tomcat/util/net/jsse/PEMFile.java
+++ b/java/org/apache/tomcat/util/net/jsse/PEMFile.java
@@ -23,7 +23,6 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.math.BigInteger;
 import java.nio.charset.StandardCharsets;
-import java.security.AlgorithmParameters;
 import java.security.GeneralSecurityException;
 import java.security.InvalidKeyException;
 import java.security.KeyFactory;
@@ -39,10 +38,12 @@ import java.security.spec.KeySpec;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.RSAPrivateCrtKeySpec;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.crypto.Cipher;
-import javax.crypto.EncryptedPrivateKeyInfo;
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.IvParameterSpec;
@@ -51,6 +52,7 @@ import javax.crypto.spec.SecretKeySpec;
 
 import org.apache.tomcat.util.buf.Asn1Parser;
 import org.apache.tomcat.util.buf.Asn1Writer;
+import org.apache.tomcat.util.buf.HexUtils;
 import org.apache.tomcat.util.codec.binary.Base64;
 import org.apache.tomcat.util.file.ConfigFileLoader;
 import org.apache.tomcat.util.res.StringManager;
@@ -64,9 +66,40 @@ public class PEMFile {
 
     private static final byte[] OID_EC_PUBLIC_KEY =
             new byte[] { 0x06, 0x07, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 
0x3D, 0x02, 0x01 };
+    // 1.2.840.113549.1.5.13
+    private static final byte[] OID_PBES2 =
+            new byte[] { 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 
0x0D, 0x01, 0x05, 0x0D };
+    // 1.2.840.113549.1.5.12
+    private static final byte[] OID_PBKDF2 =
+            new byte[] { 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 
0x0D, 0x01, 0x05, 0x0C };
+
+    private static final Map<String,String> OID_TO_PRF = new HashMap<>();
+    static {
+        // 1.2.840.113549.2.7
+        OID_TO_PRF.put("2a864886f70d0207", "HmacSHA1");
+        // 1.2.840.113549.2.8
+        OID_TO_PRF.put("2a864886f70d0208", "HmacSHA224");
+        // 1.2.840.113549.2.9
+        OID_TO_PRF.put("2a864886f70d0209", "HmacSHA256");
+        // 1.2.840.113549.2.10
+        OID_TO_PRF.put("2a864886f70d020a", "HmacSHA384");
+        // 1.2.840.113549.2.11
+        OID_TO_PRF.put("2a864886f70d020b", "HmacSHA512");
+        // 1.2.840.113549.2.12
+        OID_TO_PRF.put("2a864886f70d020c", "HmacSHA512/224");
+        // 1.2.840.113549.2.13
+        OID_TO_PRF.put("2a864886f70d020d", "HmacSHA512/256");
+    }
 
-    private static final String OID_PKCS5_PBES2 = "1.2.840.113549.1.5.13";
-    private static final String PBES2 = "PBES2";
+    private static final Map<String,Algorithm> OID_TO_ALGORITHM = new 
HashMap<>();
+    static {
+        // 1.2.840.113549.3.7
+        OID_TO_ALGORITHM.put("2a864886f70d0307", Algorithm.DES_EDE3_CBC);
+        // 2.16.840.1.101.3.4.1.2
+        OID_TO_ALGORITHM.put("608648016503040102", Algorithm.AES128_CBC_PAD);
+        // 2.16.840.1.101.3.4.1.42
+        OID_TO_ALGORITHM.put("60864801650304012a", Algorithm.AES256_CBC_PAD);
+    }
 
     public static String toPEM(X509Certificate certificate) throws 
CertificateEncodingException {
         StringBuilder result = new StringBuilder();
@@ -169,10 +202,10 @@ public class PEMFile {
         for (Part part : parts) {
             switch (part.type) {
                 case Part.PRIVATE_KEY:
-                    privateKey = part.toPrivateKey(null, keyAlgorithm, 
Format.PKCS8, filename);
+                    privateKey = part.toPrivateKey(keyAlgorithm, Format.PKCS8, 
filename);
                     break;
                 case Part.EC_PRIVATE_KEY:
-                    privateKey = part.toPrivateKey(null, "EC", Format.RFC5915, 
filename);
+                    privateKey = part.toPrivateKey("EC", Format.RFC5915, 
filename);
                     break;
                 case Part.ENCRYPTED_PRIVATE_KEY:
                     privateKey = part.toPrivateKey(passwordToUse, 
keyAlgorithm, Format.PKCS8, filename);
@@ -181,7 +214,7 @@ public class PEMFile {
                     if (part.algorithm == null) {
                         // If no encryption algorithm was detected, ignore any
                         // (probably default) key password provided.
-                        privateKey = part.toPrivateKey(null, keyAlgorithm, 
Format.PKCS1, filename);
+                        privateKey = part.toPrivateKey(keyAlgorithm, 
Format.PKCS1, filename);
                     } else {
                         privateKey = part.toPrivateKey(passwordToUse, 
keyAlgorithm, Format.PKCS1, filename);
                     }
@@ -194,7 +227,7 @@ public class PEMFile {
         }
     }
 
-    private class Part {
+    private static class Part {
         public static final String BEGIN_BOUNDARY = "-----BEGIN ";
         public static final String END_BOUNDARY   = "-----END ";
         public static final String FINISH_BOUNDARY = "-----";
@@ -220,45 +253,46 @@ public class PEMFile {
             return (X509Certificate) factory.generateCertificate(new 
ByteArrayInputStream(decode()));
         }
 
+
+        /**
+         * Extracts the private key from an unencrypted PEMFile.
+         *
+         * @param keyAlgorithm Key algorithm if known or null if it needs to 
be obtained from the PEM file
+         * @param format       The format used to encode the private key
+         * @param filename     The name of the PEM file
+         *
+         * @return The clear text private key extracted from the PEM file
+         *
+         * @throws GeneralSecurityException If there is a cryptographic error 
processing the PEM file
+         */
+        public PrivateKey toPrivateKey(String keyAlgorithm, Format format, 
String filename) throws GeneralSecurityException {
+            return toPrivateKey(keyAlgorithm, format, filename, decode());
+        }
+
+
+        /**
+         * Extracts the private key from an encrypted PEMFile.
+         *
+         * @param password     Password to decrypt the private key
+         * @param keyAlgorithm Key algorithm if known or null if it needs to 
be obtained from the PEM file
+         * @param format       The format used to encode the private key
+         * @param filename     The name of the PEM file
+         *
+         * @return The clear text private key extracted from the PEM file
+         *
+         * @throws GeneralSecurityException If there is a cryptographic error 
processing the PEM file
+         * @throws IOException              If there is an I/O error reading 
the PEM file
+         */
         public PrivateKey toPrivateKey(String password, String keyAlgorithm, 
Format format, String filename)
                 throws GeneralSecurityException, IOException {
-            KeySpec keySpec = null;
 
-            if (password == null) {
-                switch (format) {
-                    case PKCS1: {
-                        keySpec = parsePKCS1(decode());
-                        break;
-                    }
-                    case PKCS8: {
-                        keySpec = new PKCS8EncodedKeySpec(decode());
-                        break;
-                    }
-                    case RFC5915: {
-                        keySpec = new 
PKCS8EncodedKeySpec(rfc5915ToPkcs8(decode()));
-                        break;
-                    }
-                }
-            } else {
-                if (algorithm == null) {
-                    // PKCS 8
-                    EncryptedPrivateKeyInfo privateKeyInfo = new 
EncryptedPrivateKeyInfo(decode());
-                    String pbeAlgorithm = getPBEAlgorithm(privateKeyInfo);
-                    SecretKeyFactory secretKeyFactory = 
SecretKeyFactory.getInstance(pbeAlgorithm);
-                    SecretKey secretKey = secretKeyFactory.generateSecret(new 
PBEKeySpec(password.toCharArray()));
-
-                    Cipher cipher = Cipher.getInstance(pbeAlgorithm);
-                    cipher.init(Cipher.DECRYPT_MODE, secretKey, 
privateKeyInfo.getAlgParameters());
-
-                    keySpec = privateKeyInfo.getKeySpec(cipher);
-                } else {
-                    // PKCS 1
-                    String secretKeyAlgorithm;
-                    String cipherTransformation;
-                    int keyLength;
-
-                    // Is there a generic way to derive these three values from
-                    // just the algorithm name?
+            String secretKeyAlgorithm;
+            String cipherTransformation;
+            int keyLength;
+
+            switch (format) {
+                case PKCS1: {
+
                     switch (algorithm) {
                         case "DES-CBC": {
                             secretKeyAlgorithm = "DES";
@@ -288,12 +322,147 @@ public class PEMFile {
 
                     byte[] iv = fromHex(ivHex);
                     // The IV is also used as salt for the password generation
-                    byte[] key = deriveKey(keyLength, password, iv);
+                    byte[] key = deriveKeyPBKDF1(keyLength, password, iv);
                     SecretKey secretKey = new SecretKeySpec(key, 
secretKeyAlgorithm);
                     Cipher cipher = Cipher.getInstance(cipherTransformation);
                     cipher.init(Cipher.DECRYPT_MODE, secretKey, new 
IvParameterSpec(iv));
                     byte[] pkcs1 = cipher.doFinal(decode());
-                    keySpec = parsePKCS1(pkcs1);
+                    return toPrivateKey(keyAlgorithm, format, filename, pkcs1);
+                }
+                case PKCS8: {
+                    // Encrypted PEM file is PKCS8
+                    Asn1Parser p = new Asn1Parser(decode());
+
+                    //@formatter:off
+                    /*
+                     * RFC 5208 - PKCS #8
+                     * RFC 8108 - PKCS #5
+                     *
+                     * SEQ                    - PKCS #8
+                     *   SEQ                  - PKCS #8 encryptionAlgorithm
+                     *     OID                - PKCS #5 PBES2 OID
+                     *     SEQ                - PKCS #5 PBES2-params
+                     *       SEQ              - PKCS #5 PBES2 key derivation 
function
+                     *         OID            - PKCS #5 PBES2 KDF OID - must 
be PBKDF2
+                     *         SEQ            - PKCS #5 PBKDF2-params
+                     *           OCTET STRING - PKCS #5 PBKDF2 salt
+                     *           INT          - PKCS #5 PBKDF2 interationCount
+                     *           INT          - PKCS #5 PBKDF2 key length 
OPTIONAL
+                     *           SEQ          - PKCS #5 PBKDF2 PRF
+                     *             OID        - PKCS #5 PBKDF2 PRF OID
+                     *             NULL       - PKCS #5 PBKDF2 PRF parameters
+                     *       SEQ              - PKCS #5 PBES2 encryption scheme
+                     *         OID            - PKCS #5 PBES2 algorithm OID
+                     *         OCTET STRING   - PKCS #5 PBES2 algorithm iv
+                     *   OCTET STRING         - PKCS #8 encryptedData
+                     */
+                    //@formatter:on
+
+                    // Parse the PKCS #8 outer sequence and validate the length
+                    p.parseTagSequence();
+                    p.parseFullLength();
+
+                    // Parse the PKCS #8 encryption algorithm
+                    p.parseTagSequence();
+                    p.parseLength();
+
+                    // PBES2 OID
+                    byte[] oidEncryptionAlgorithm = p.parseOIDAsBytes();
+                    /*
+                     * Implementation note. If other algorithms are ever 
supported, the KDF check below is likely to
+                     * need to be adjusted.
+                     */
+                    if (!Arrays.equals(oidEncryptionAlgorithm, OID_PBES2)) {
+                        throw new 
NoSuchAlgorithmException(sm.getString("pemFile.unknownPkcs8Algorithm",
+                                HexUtils.toHexString(oidEncryptionAlgorithm)));
+                    }
+
+                    // PBES2-params
+                    p.parseTagSequence();
+                    p.parseLength();
+
+                    // PBES2 KDF
+                    p.parseTagSequence();
+                    p.parseLength();
+                    byte[] oidKDF = p.parseOIDAsBytes();
+                    if (!Arrays.equals(oidKDF, OID_PBKDF2)) {
+                        throw new 
NoSuchAlgorithmException(sm.getString("pemFile.notPbkdf2",
+                                HexUtils.toHexString(oidKDF)));
+                    }
+
+                    // PBES2 KDF-params
+                    p.parseTagSequence();
+                    p.parseLength();
+                    byte[] salt = p.parseOctetString();
+                    int iterationCount = p.parseInt().intValue();
+                    if (p.peekTag() == Asn1Parser.TAG_INTEGER) {
+                        keyLength = p.parseInt().intValue();
+                    }
+
+                    // PBKDF2 PRF
+                    p.parseTagSequence();
+                    p.parseLength();
+                    byte[] oidPRF = p.parseOIDAsBytes();
+                    String prf = OID_TO_PRF.get(HexUtils.toHexString(oidPRF));
+                    if (prf == null) {
+                        throw new 
NoSuchAlgorithmException(sm.getString("pemFile.unknownPrfAlgorithm", prf));
+                    }
+                    p.parseNull();
+
+                    // PBES2 encryption scheme
+                    p.parseTagSequence();
+                    p.parseLength();
+                    byte[] oidCipher = p.parseOIDAsBytes();
+                    Algorithm algorithm = 
OID_TO_ALGORITHM.get(HexUtils.toHexString(oidCipher));
+                    if (algorithm == null) {
+                        throw new 
NoSuchAlgorithmException(sm.getString("pemFile.unknownEncryptionAlgorithm",
+                                HexUtils.toHexString(oidCipher)));
+                    }
+
+                    byte[] iv = p.parseOctetString();
+
+                    // Encrypted data
+                    byte[] encryptedData = p.parseOctetString();
+
+                    // ASN.1 parsing complete
+
+                    // Build secret key to decrypt encrypted data
+                    byte[] key = deriveKeyPBKDF2("PBKDF2With" + prf, password, 
salt, iterationCount, algorithm.getKeyLength());
+                    SecretKey secretKey = new SecretKeySpec(key, 
algorithm.getSecretKeyAlgorithm());
+
+                    // Configure algorithm to decrypt encrypted data
+                    Cipher cipher = 
Cipher.getInstance(algorithm.getTransformation());
+                    cipher.init(Cipher.DECRYPT_MODE, secretKey, new 
IvParameterSpec(iv));
+
+                    // Decrypt the encrypted key and call this method again to 
process the key
+                    byte[] decryptedData = cipher.doFinal(encryptedData);
+                    return toPrivateKey(keyAlgorithm, format, filename, 
decryptedData);
+                }
+                default: {
+                    // Expected to be unencrypted
+                    throw new 
NoSuchAlgorithmException(sm.getString("pemFile.unknownEncryptedFormat", 
format));
+                }
+            }
+        }
+
+
+        private PrivateKey toPrivateKey(String keyAlgorithm, Format format, 
String filename, byte[] source)
+                throws GeneralSecurityException {
+
+            KeySpec keySpec = null;
+
+            switch (format) {
+                case PKCS1: {
+                    keySpec = parsePKCS1(source);
+                    break;
+                }
+                case PKCS8: {
+                    keySpec = new PKCS8EncodedKeySpec(source);
+                    break;
+                }
+                case RFC5915: {
+                    keySpec = new PKCS8EncodedKeySpec(rfc5915ToPkcs8(source));
+                    break;
                 }
             }
 
@@ -318,29 +487,7 @@ public class PEMFile {
         }
 
 
-        private String getPBEAlgorithm(EncryptedPrivateKeyInfo privateKeyInfo) 
{
-            AlgorithmParameters parameters = privateKeyInfo.getAlgParameters();
-            String algName = privateKeyInfo.getAlgName();
-            // Java 11 returns OID_PKCS5_PBES2
-            // Java 17 returns PBES2
-            if (parameters != null && (OID_PKCS5_PBES2.equals(algName) || 
PBES2.equals(algName))) {
-                /*
-                 * This should be "PBEWith<prf>And<encryption>".
-                 * Relying on the toString() implementation is potentially
-                 * fragile but acceptable in this case since the JRE depends on
-                 * the toString() implementation as well.
-                 * In the future, if necessary, we can parse the value of
-                 * parameters.getEncoded() but the associated complexity and
-                 * unlikeliness of the JRE implementation changing means that
-                 * Tomcat will use to toString() approach for now.
-                 */
-                return parameters.toString();
-            }
-            return privateKeyInfo.getAlgName();
-        }
-
-
-        private byte[] deriveKey(int keyLength, String password, byte[] salt) 
throws NoSuchAlgorithmException {
+        private byte[] deriveKeyPBKDF1(int keyLength, String password, byte[] 
salt) throws NoSuchAlgorithmException {
             // PBKDF1-MD5 as specified by PKCS#5
             byte[] key = new byte[keyLength];
 
@@ -363,6 +510,17 @@ public class PEMFile {
         }
 
 
+        private byte[] deriveKeyPBKDF2(String algorithm, String password, 
byte[] salt, int iterations, int keyLength)
+                throws GeneralSecurityException {
+            SecretKeyFactory secretKeyFactory = 
SecretKeyFactory.getInstance(algorithm);
+            KeySpec keySpec;
+            keySpec = new PBEKeySpec(password.toCharArray(), salt, iterations, 
keyLength);
+            SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
+            return secretKey.getEncoded();
+        }
+
+
+        //@formatter:off
         /*
          * RFC5915: SEQ
          *           INT               value = 1
@@ -385,6 +543,7 @@ public class PEMFile {
          *                 BIT STRING  len = 520 bits
          *
          */
+        //@formatter:on
         private byte[] rfc5915ToPkcs8(byte[] source) {
             // Parse RFC 5915 format EC private key
             Asn1Parser p = new Asn1Parser(source);
@@ -481,4 +640,33 @@ public class PEMFile {
         PKCS8,
         RFC5915
     }
+
+
+    private enum Algorithm {
+        AES128_CBC_PAD("AES/CBC/PKCS5PADDING", "AES", 128),
+        AES256_CBC_PAD("AES/CBC/PKCS5PADDING", "AES", 256),
+        DES_EDE3_CBC("DESede/CBC/PKCS5Padding", "DESede", 192);
+
+        private final String transformation;
+        private final String secretKeyAlgorithm;
+        private final int keyLength;
+
+        Algorithm(String transformation, String secretKeyAlgorithm, int 
keyLength) {
+            this.transformation = transformation;
+            this.secretKeyAlgorithm = secretKeyAlgorithm;
+            this.keyLength = keyLength;
+        }
+
+        public String getTransformation() {
+            return transformation;
+        }
+
+        public String getSecretKeyAlgorithm() {
+            return secretKeyAlgorithm;
+        }
+
+        public int getKeyLength() {
+            return keyLength;
+        }
+    }
 }
diff --git a/test/org/apache/tomcat/util/net/jsse/TestPEMFile.java 
b/test/org/apache/tomcat/util/net/jsse/TestPEMFile.java
index dc10b2b9dc..9a0941bb9a 100644
--- a/test/org/apache/tomcat/util/net/jsse/TestPEMFile.java
+++ b/test/org/apache/tomcat/util/net/jsse/TestPEMFile.java
@@ -39,7 +39,9 @@ public class TestPEMFile {
     private static final String KEY_ENCRYPTED_PKCS1_DES_CBC = 
"key-encrypted-pkcs1-des-cbc.pem";
     private static final String KEY_ENCRYPTED_PKCS1_DES_EDE3_CBC = 
"key-encrypted-pkcs1-des-ede3-cbc.pem";
     private static final String KEY_ENCRYPTED_PKCS1_AES256 = 
"key-encrypted-pkcs1-aes256.pem";
-    private static final String KEY_ENCRYPTED_PKCS8 = 
"key-encrypted-pkcs8.pem";
+    private static final String KEY_ENCRYPTED_PKCS8_HMACSHA256_AES_128_CBC = 
"key-encrypted-pkcs8-hmacsha256-aes-128-cbc.pem";
+    private static final String KEY_ENCRYPTED_PKCS8_HMACSHA256_AES_256_CBC = 
"key-encrypted-pkcs8-hmacsha256-aes-256-cbc.pem";
+    private static final String KEY_ENCRYPTED_PKCS8_HMACSHA256_DES_EDE3_CBC = 
"key-encrypted-pkcs8-hmacsha256-des-ede3-cbc.pem";
 
     @Parameterized.Parameters
     public static Collection<Object[]> parameters() {
@@ -91,8 +93,20 @@ public class TestPEMFile {
 
 
     @Test
-    public void testKeyEncryptedPkcs8() throws Exception {
-        testKeyEncrypted(KEY_ENCRYPTED_PKCS8);
+    public void testKeyEncryptedPkcs8HmacSha256Aes128() throws Exception {
+        testKeyEncrypted(KEY_ENCRYPTED_PKCS8_HMACSHA256_AES_128_CBC);
+    }
+
+
+    @Test
+    public void testKeyEncryptedPkcs8HmacSha256Aes256() throws Exception {
+        testKeyEncrypted(KEY_ENCRYPTED_PKCS8_HMACSHA256_AES_256_CBC);
+    }
+
+
+    @Test
+    public void testKeyEncryptedPkcs8HmacSha256DesEde3Cbc() throws Exception {
+        testKeyEncrypted(KEY_ENCRYPTED_PKCS8_HMACSHA256_DES_EDE3_CBC);
     }
 
 
diff --git 
a/test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8-hmacsha256-aes-128-cbc.pem
 
b/test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8-hmacsha256-aes-128-cbc.pem
new file mode 100644
index 0000000000..dfefd75707
--- /dev/null
+++ 
b/test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8-hmacsha256-aes-128-cbc.pem
@@ -0,0 +1,54 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIJrTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI/ze5ju8ZpdwCAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBCKvOamzivBoPc0g4FihbH6BIIJ
+UNPyodBA3cPJ2FJ+4dKYCb/AXj0JuOZ7fJQi1atYvpX8ADBUHFoBFittr7WGfVpl
+DNny63vhwnubewE17xuurpItncD8NPxxiWBklgrca+jM15E8WOKBlyfMExilxtIL
+SyIIFd3nbkUbGTAExwBEbZisHuJSkZemP/oBinVAoYVT7kbWV0NRFbBt7q4peeJt
+nptBTxNhaYZrXH3ydVUYTDSSMLASe1J1tlfH91qsVz2TUbL0g19LWk74Lolmkjym
+o4DZXJqM+ZCuHaSZwd1tihEdwUU7so/t4/LGH4mx1rpjchQHiK2J33+eosScSlcx
+tMnfuYRlEC34n8MPyIHFbhCvye0NovsQfQ6waK+uJMO3ZBfd0gIRE/23JmNSoh7c
+6uHwZhxM6N0DOAviRdd/dBPEALreB8lD2MmxJ4Fs/RxjYjAE1R9jGSoMLk6wbnx3
+UxlM/iBo31S1M48JwDctUYU7LBUb0Kzg/C7fxSJCUJDE2OXlY732voQ8kvqKwggz
+EOzP3Mt9MsLZazlnDrssTb3mzDPsENW7U4SW6A5CDbgQkAuSRnivjcrU+GPV//Us
+W/PEQAM2m/hA9kBipvcoXuK+onc+TQqc1Ib+/roW9rr6qCC0zzFqghC0fT/gW7Qb
+2MDizaAtP56i90zIaOS0SWAKbWMHtjFFiQqXVRqvPCb9POHfnS6Qxo5HGhTsDG0o
+Dr5gjHFfEnkMeF5IF/Pa/vaUliN7F16KbL69YQ9P4aHxDkGtXqi6v+IAJWSua9Nt
+odG4l0QCdcTiJZyOMGR8pvUo9VeJ2TOsbdpep5wdtpkCemBGGZorRjXIOv0gIssa
+4UZFHcB8p0pfTRJaIUXz03JFuL8eIPTX8bGPdzlHl95qlJsLZmMJBdcUIszsphO0
+TVCj+6TLrUMkb9T6pUuwLPgPx7cdQS9b1gbmxX6N/tlFWWB4mMG4oQ0L3kO9sYoC
+3/rltP9bbkOv9NG1NpLW9Vu+1A5adj7JYXcNsAm8hMLnx9tmJ8sdSPNxOnh2ggnV
+Lwl5lXVer8pwZRctudYOLp9MPtySwnGiJlgMqxQapkxBfehzCKALqnTG/hUyfUx0
+mj05PTKE6FXJJAx+6nWmayrXbCs0ZI+bk1DgYvU74G+A+BkzLbf9jkXG8+f3PoOJ
+aU7J2IL3GHPgy0a/D9VLBORasa1Y7+WM3dQ8Y3JWXM5jCbkMfm4iQAQJeFkR0PAa
+1uBr5sL+QjhUu0YzaIj9SfuUN+jw4s0p5UoyelxXTyA0W2+2HNQ7LWSSlg1vXp+s
+ooHtHpDY7ZnpIRqbN4G6h7WPwX5hRLSxE7w5xadj05m+BfbZW8J/RdcSxqwy1Qzu
+khiKSoFaUneq7bXhrsLTTdnMhK2yu3Pm7ARTXgAdd7htUr8WD6ySt8jPQT8T42lv
+rOLe4YoMCawNZUbKJh66um8k8Jj0EaXqVx1/o/pi+nPtni/Mph0qky3l2ezfVkjl
+WMNARZ9s5c1iBq1SPyrFkIJzGT0dhvSfg38VgL2BdVd5IkgyrFvyiXby/PvUkKft
+591t9/FkGBhtOYcNrSuSl48YuoB/Fqn04C8Cc4PGwbTOwRSqt+R/lIFCSdG7LsnZ
+Nt4IWKNxiYMLdv4ugqCKNIdzuAJrk35gEeIOgCzDxwZT7NMEaiFuQW0/9D/j59uD
+/bxcDMJHvBHjBJEPwGKopMy6CA+giMjW94XGONpx2Ko+R1tVVVHWjupZGlaIE7yP
+lm//ATvrDjXhJL6rURLG0hUbJtGrsLo1NZqUY/XoXv5h0b9PTpH0AVjppfISB84O
+/8yBpIcYlBlRhB7nBzQn85m7eDSM13izZ9Gjq+uX+q0ELuTPR2k6ksdFh9aNSFmF
+bO/OPvTyvILTD+cQhD4BaQKa9WclqRcRPfff1nsslWResjkmNji8VKoPKeBW2UdZ
+uewZnDAW++ivaZAk6WZGgrWw9UwqVNT2jRxS7tybAk+lwYoatpAr4QKXHnHqgp22
+X+twN/nD67bwhnZ1UpwK75SV/iYRcgvNaAsRltMoIm8W4GLxpUD6dlLdVLCCb3Dv
+lCn81fUQkTEKEHUSfjPGooRanFOj6uoKiu2VK3tRY5U4vpJ6Ik0XTVuzCW1UFIFT
+LV+mTYwqQcbQAxULVUDo1ppEcPALG14LkunNrxgtkDrDvwxSIu26HW5efEPey7Xi
+JV/dcbiMvGTVruqH1r89L+RWd5FvDwm31bB7g0hGzuzRJLey3PY8y3MYHVoSoPwe
+dF9ymkcIPYZ/JI8Mz/4SliSnlgzqDIfL8BD2ku7TcWrOeZcJthRPml2wfVJxKqqF
++XzQ98619GEWq2z8V5aq8IYqSV/eOIRELYPy2JNCY6w5xPLvf/00TVNb0LyWrLb1
+zdTf7TkB37BbCmvOK5YhPrJtkjqcgS9u25/CeZdTgRw6KDJv9af++LAq8qYzZIms
+GAgLtxdpDPOUqryeC2fPaRXGYlwGOyePqAlmaCDpAwvfe6KnwYbAxTN7KE4Vj7qq
+qspQYvDBRGZMQ76p5PdlLvYQddd++1a1OFz94jfw4mNtLw348KY+sFGt2fa6thWO
+N6h63HNLoVF6ztqUxS0wtiGUAcjWE2l2jQvW0DIgBglLGfK6rfze3F2SmucYt2vZ
+z+TZf0Mzgxjh47V7RpgS0tSHXEsQKl3/dz2pX9l+sOHEumEk0BgLdfBc8OXx0IYh
+jXhfTNQcQsJIusrjDoZBoYjvmDyGg0FKimsagf4TbBykxgxC78HFsVFhnPp9c+tO
+acb7fHK8DLG7XvWjSUDt2AM0j6LcjbOrrwGtSgZe+rbLsQ+z23U06Ipu5ZSIAZ9t
+T/62ieXM8c8rdm09vTwbE3BiDWXjt12vJOXMb+MFBd31xRcZHUtU1PWQ/hROpw03
+3TPS1k8Xvpt2U9mH4XQcmIkwHo5otTJxQpUFwmCabYzESgQMca+zs1HjJHv7U4Gf
+0w/72B90NJw9IGVyuP7bbCzsX/NX02236ZsMviddpMA4tZfWZwl8CgSevySFCVZY
+S5KvX2ZpS8oHCjxFLYGLeMeJriVxmzk54qlztOUbnRBcurmdAUYDdAcW9+udP0xg
+CoP49Pcqw6DQy2XS78+pM4H9IvbWKFhEsdEUNl7+BBQj6MTiDpxDDKYG4XlTzJp/
+X8Gof1N9qDcmp6yIIImCJhbMgKK63BjBJJZu6yjH4ktE
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8.pem 
b/test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8-hmacsha256-aes-256-cbc.pem
similarity index 100%
rename from test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8.pem
rename to 
test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8-hmacsha256-aes-256-cbc.pem
diff --git 
a/test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8-hmacsha256-des-ede3-cbc.pem
 
b/test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8-hmacsha256-des-ede3-cbc.pem
new file mode 100644
index 0000000000..dd5c196613
--- /dev/null
+++ 
b/test/org/apache/tomcat/util/net/jsse/key-encrypted-pkcs8-hmacsha256-des-ede3-cbc.pem
@@ -0,0 +1,54 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+XRdksDlwnGCCHdhG7YfRuQ==
+-----END ENCRYPTED PRIVATE KEY-----


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to