|
27 | 27 | import io.netty.util.AttributeMap; |
28 | 28 | import io.netty.util.DefaultAttributeMap; |
29 | 29 | import io.netty.util.internal.EmptyArrays; |
| 30 | +import io.netty.util.internal.PlatformDependent; |
30 | 31 |
|
31 | 32 | import java.io.BufferedInputStream; |
32 | 33 | import java.security.Provider; |
|
48 | 49 | import java.io.File; |
49 | 50 | import java.io.IOException; |
50 | 51 | import java.io.InputStream; |
| 52 | +import java.security.AlgorithmParameters; |
51 | 53 | import java.security.InvalidAlgorithmParameterException; |
52 | 54 | import java.security.InvalidKeyException; |
53 | 55 | import java.security.KeyException; |
@@ -102,6 +104,8 @@ public abstract class SslContext { |
102 | 104 |
|
103 | 105 | private final boolean startTls; |
104 | 106 | private final AttributeMap attributes = new DefaultAttributeMap(); |
| 107 | + private static final String OID_PKCS5_PBES2 = "1.2.840.113549.1.5.13"; |
| 108 | + private static final String PBES2 = "PBES2"; |
105 | 109 |
|
106 | 110 | /** |
107 | 111 | * Returns the default server-side implementation provider currently in use. |
@@ -1081,16 +1085,39 @@ protected static PKCS8EncodedKeySpec generateKeySpec(char[] password, byte[] key |
1081 | 1085 | } |
1082 | 1086 |
|
1083 | 1087 | EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(key); |
1084 | | - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(encryptedPrivateKeyInfo.getAlgName()); |
| 1088 | + String pbeAlgorithm = getPBEAlgorithm(encryptedPrivateKeyInfo); |
| 1089 | + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(pbeAlgorithm); |
1085 | 1090 | PBEKeySpec pbeKeySpec = new PBEKeySpec(password); |
1086 | 1091 | SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec); |
1087 | 1092 |
|
1088 | | - Cipher cipher = Cipher.getInstance(encryptedPrivateKeyInfo.getAlgName()); |
| 1093 | + Cipher cipher = Cipher.getInstance(pbeAlgorithm); |
1089 | 1094 | cipher.init(Cipher.DECRYPT_MODE, pbeKey, encryptedPrivateKeyInfo.getAlgParameters()); |
1090 | 1095 |
|
1091 | 1096 | return encryptedPrivateKeyInfo.getKeySpec(cipher); |
1092 | 1097 | } |
1093 | 1098 |
|
| 1099 | + private static String getPBEAlgorithm(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo) { |
| 1100 | + AlgorithmParameters parameters = encryptedPrivateKeyInfo.getAlgParameters(); |
| 1101 | + String algName = encryptedPrivateKeyInfo.getAlgName(); |
| 1102 | + // Java 8 ~ 16 returns OID_PKCS5_PBES2 |
| 1103 | + // Java 17+ returns PBES2 |
| 1104 | + if (PlatformDependent.javaVersion() >= 8 && parameters != null && |
| 1105 | + (OID_PKCS5_PBES2.equals(algName) || PBES2.equals(algName))) { |
| 1106 | + /* |
| 1107 | + * This should be "PBEWith<prf>And<encryption>". |
| 1108 | + * Relying on the toString() implementation is potentially |
| 1109 | + * fragile but acceptable in this case since the JRE depends on |
| 1110 | + * the toString() implementation as well. |
| 1111 | + * In the future, if necessary, we can parse the value of |
| 1112 | + * parameters.getEncoded() but the associated complexity and |
| 1113 | + * unlikeliness of the JRE implementation changing means that |
| 1114 | + * Tomcat will use to toString() approach for now. |
| 1115 | + */ |
| 1116 | + return parameters.toString(); |
| 1117 | + } |
| 1118 | + return encryptedPrivateKeyInfo.getAlgName(); |
| 1119 | + } |
| 1120 | + |
1094 | 1121 | /** |
1095 | 1122 | * Generates a new {@link KeyStore}. |
1096 | 1123 | * |
@@ -1118,12 +1145,19 @@ protected static PrivateKey toPrivateKey(File keyFile, String keyPassword) throw |
1118 | 1145 | NoSuchPaddingException, InvalidKeySpecException, |
1119 | 1146 | InvalidAlgorithmParameterException, |
1120 | 1147 | KeyException, IOException { |
| 1148 | + return toPrivateKey(keyFile, keyPassword, true); |
| 1149 | + } |
| 1150 | + |
| 1151 | + static PrivateKey toPrivateKey(File keyFile, String keyPassword, boolean tryBouncyCastle) |
| 1152 | + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, |
| 1153 | + InvalidAlgorithmParameterException, |
| 1154 | + KeyException, IOException { |
1121 | 1155 | if (keyFile == null) { |
1122 | 1156 | return null; |
1123 | 1157 | } |
1124 | 1158 |
|
1125 | 1159 | // try BC first, if this fail fallback to original key extraction process |
1126 | | - if (BouncyCastlePemReader.isAvailable()) { |
| 1160 | + if (tryBouncyCastle && BouncyCastlePemReader.isAvailable()) { |
1127 | 1161 | PrivateKey pk = BouncyCastlePemReader.getPrivateKey(keyFile, keyPassword); |
1128 | 1162 | if (pk != null) { |
1129 | 1163 | return pk; |
|
0 commit comments