Skip to content

Commit a026444

Browse files
xiezhaokunnormanmaurerchrisvest
authored
Add support for password-based encryption scheme 2 params (PBES2) (#13539)
Motivation: Add support for password-based encryption scheme 2 params (PBES2) Modification: Describe the modifications you've done. Result: Fixes #13536 Co-authored-by: Norman Maurer <norman_maurer@apple.com> Co-authored-by: Chris Vest <christianvest_hansen@apple.com>
1 parent 64c8983 commit a026444

4 files changed

Lines changed: 81 additions & 3 deletions

File tree

handler/src/main/java/io/netty/handler/ssl/SslContext.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import io.netty.util.AttributeMap;
2828
import io.netty.util.DefaultAttributeMap;
2929
import io.netty.util.internal.EmptyArrays;
30+
import io.netty.util.internal.PlatformDependent;
3031

3132
import java.io.BufferedInputStream;
3233
import java.security.Provider;
@@ -48,6 +49,7 @@
4849
import java.io.File;
4950
import java.io.IOException;
5051
import java.io.InputStream;
52+
import java.security.AlgorithmParameters;
5153
import java.security.InvalidAlgorithmParameterException;
5254
import java.security.InvalidKeyException;
5355
import java.security.KeyException;
@@ -102,6 +104,8 @@ public abstract class SslContext {
102104

103105
private final boolean startTls;
104106
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";
105109

106110
/**
107111
* Returns the default server-side implementation provider currently in use.
@@ -1081,16 +1085,39 @@ protected static PKCS8EncodedKeySpec generateKeySpec(char[] password, byte[] key
10811085
}
10821086

10831087
EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(key);
1084-
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(encryptedPrivateKeyInfo.getAlgName());
1088+
String pbeAlgorithm = getPBEAlgorithm(encryptedPrivateKeyInfo);
1089+
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(pbeAlgorithm);
10851090
PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
10861091
SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);
10871092

1088-
Cipher cipher = Cipher.getInstance(encryptedPrivateKeyInfo.getAlgName());
1093+
Cipher cipher = Cipher.getInstance(pbeAlgorithm);
10891094
cipher.init(Cipher.DECRYPT_MODE, pbeKey, encryptedPrivateKeyInfo.getAlgParameters());
10901095

10911096
return encryptedPrivateKeyInfo.getKeySpec(cipher);
10921097
}
10931098

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+
10941121
/**
10951122
* Generates a new {@link KeyStore}.
10961123
*
@@ -1118,12 +1145,19 @@ protected static PrivateKey toPrivateKey(File keyFile, String keyPassword) throw
11181145
NoSuchPaddingException, InvalidKeySpecException,
11191146
InvalidAlgorithmParameterException,
11201147
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 {
11211155
if (keyFile == null) {
11221156
return null;
11231157
}
11241158

11251159
// try BC first, if this fail fallback to original key extraction process
1126-
if (BouncyCastlePemReader.isAvailable()) {
1160+
if (tryBouncyCastle && BouncyCastlePemReader.isAvailable()) {
11271161
PrivateKey pk = BouncyCastlePemReader.getPrivateKey(keyFile, keyPassword);
11281162
if (pk != null) {
11291163
return pk;

handler/src/test/java/io/netty/handler/ssl/SslContextTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,13 @@ public void testPkcs8Des3EncryptedRsa() throws Exception {
173173
assertNotNull(key);
174174
}
175175

176+
@Test
177+
public void testPkcs8Pbes2() throws Exception {
178+
PrivateKey key = SslContext.toPrivateKey(new File(getClass().getResource("rsa_pbes2_enc_pkcs8.key")
179+
.getFile()), "12345678", false);
180+
assertNotNull(key);
181+
}
182+
176183
@Test
177184
public void testPkcs1UnencryptedRsaEmptyPassword() throws Exception {
178185
assertThrows(IOException.class, new Executable() {

handler/src/test/resources/io/netty/handler/ssl/generate-certs.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,15 @@ openssl gendsa -out dsa_pkcs1_unencrypted.key dsaparam.pem
7171
openssl gendsa -des3 -out dsa_pkcs1_des3_encrypted.key -passout pass:example dsaparam.pem
7272
openssl gendsa -aes128 -out dsa_pkcs1_aes_encrypted.key -passout pass:example dsaparam.pem
7373

74+
# PBES2
75+
openssl genrsa -out rsa_pbes2.key
76+
openssl req -new -subj "/CN=NettyTest" -key rsa_pbes2.key -out rsa_pbes2.csr
77+
openssl x509 -req -days 36500 -in rsa_pbes2.csr -signkey rsa_pbes2.key -out rsa_pbes2.crt
78+
openssl pkcs8 -topk8 -inform PEM -in rsa_pbes2.key -outform pem -out rsa_pbes2_enc_pkcs8.key -v2 aes-256-cbc -passin pass:12345678 -passout pass:12345678
79+
7480
# Clean up intermediate files
7581
rm intermediate.csr
7682
rm mutual_auth_ca.key mutual_auth_invalid_client.key mutual_auth_client.key mutual_auth_server.key mutual_auth_invalid_intermediate_ca.key mutual_auth_intermediate_ca.key
7783
rm mutual_auth_invalid_client.pem mutual_auth_client.pem mutual_auth_server.pem mutual_auth_client_cert_chain.pem mutual_auth_invalid_intermediate_ca.pem mutual_auth_intermediate_ca.pem mutual_auth_invalid_client_cert_chain.pem
7884
rm dsaparam.pem
85+
rm rsa_pbes2.crt rsa_pbes2.csr rsa_pbes2.key
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-----BEGIN ENCRYPTED PRIVATE KEY-----
2+
MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIJddddGJqvzACAggA
3+
MB0GCWCGSAFlAwQBKgQQ0SIWTVvrPdriTZKRZuWb7QSCBNDoU6Y1qeABJPV726zv
4+
gymMUAZdfxqBlbS865q3RlnHO2xm4082l7VwFK9QGVFIxURx4QU76qjhsoJfmGiv
5+
pAvkZCln90iguY0ssnAzBFi8B2AgBcZrIG1OMQpR0L/hjveIvorg4/vb5rIgyIdn
6+
+3u7I077yF3udPnt0jUYcfonzsOglwa3FVun2yqM7/gAzGkQu/CeOshSQaJ9EV/0
7+
ZQmemVCJbmm7I2iEq6RUXgBW8hPjo1cwuQznE2jBx3SlhQoSrWTGdy9WXLqwxrHX
8+
e2W6LqaXqFOrgmtPz5h3JzhUh0AGtNS0SsB6AsyKD548NP7NGRlmbUXo8iQXS/Z6
9+
QmwIh1bt67VecHKka17ZYGBQt/2/zcQddRvlVeT3SbRgGCGQeDnXWhfJIMb6bFDe
10+
vdr0L44zyW6/OwYQU1RNBFclrjtFIAVQEI8L/BVciowsJ7J6W2UsxR3hrLtPjO9o
11+
zH7bp85TlSaSZW3T2HfAPu6isMECzVzZ+x8qnpuDoHjIOZID630Amw1v2/gfFZTA
12+
mXn4gld1JKUBrvBfXN4cjTDC1eO1zvzEZB6VZw6ePhggWijySoLUO+E/mJpP5mNA
13+
4OQSMxNQ+UcZH+MT093cOJeOleOlbc9weIeNhXgONX/pbnq1gV23tN3mZbGIJojY
14+
GZoH32ft76x+DxrMZrjtjL7dOUL5QjjUlpJ6319aaLFf6Z/AIWXBOyHC1i9l+lKv
15+
2hpZ/YS+eyExy/axwx0J4eH+7csDrz63F1A9hRrIxx2wKdYjsKWR21Hb/mst/U4z
16+
1MGWeIX1hqAe7VYUiZBZldnOYdmNG/sRtcHMrW9zqkJUuW25YjuGm9gVbIVw/YOY
17+
lOd/9puSiRzuJLX02p1o1PN17+5rzMkpE4bVpd6Pvbex+oMSUVvd+V845bCB0qCt
18+
eA5TUBi2gbLvj7TqoA+C0zoXGtXD1Ea/7hnmwC5Gzl4m6YmvZRpxXA6Mzs62CYgt
19+
KWJSiuuTfSop/2B8+nnkZQAGKxvXkpFLXyGXfP+Y22X00BB43GtMB2ZPzmliQ+TA
20+
bFePkPBoXqytJR9vrbWJIIzcxaYWTwqN1vZJzIgdFjK2yOiqopGi0sG0zjn8xryv
21+
ZqraVnTznb5xUGojezIbtWwMNIRrmNU9b1HMtpMsnuNNPQy/UhgDqgM6bQOh23Q8
22+
7DQRqXGlNqJc22ne1E/gN5IxdbrgoE6jnnoAzOlFRD1XdhLBW3hb2DpzTFAveDKi
23+
ti5UHucXrURILD1ee9CtyKcYQajr3XNp0tMJJQFCybnX+zOgH6HXsrfXFT8CghDt
24+
aeo7TBfhVC4MadvggLNWmyjyGJd7KeDGuiXVDsWr9icesDCUgC/T2Lq58boT70BM
25+
T14pABDOqSylJdL0qWV7m8yZ0fNAkrTB/+2qdi4B632NIQ+ZGRZy5WK09jRUtVm0
26+
+EZMoX6pAjBQR4RwgbyNTJDIt/tXOopBAoEjRc8qWotlJozc3RkpGBHgT8POZT60
27+
Jxu3QaE9rJq8kfrO/e5gq7zDy4AK/ck1+aVxfiwM1D7vPvFt0WwztdvEGz3Hjpkv
28+
qtj8ePpDBrBo1ISJqVmTi3pvRz/kuKFYvoYdWq2Wluz1NGZdCETwNYIao1/hfP52
29+
NydFNZTmdrun22ezf6yVGiCaEw==
30+
-----END ENCRYPTED PRIVATE KEY-----

0 commit comments

Comments
 (0)