Skip to content

Commit bdab5d3

Browse files
Merge pull request #198 from brendandburns/pki
Improve key loading and add more tests.
2 parents dfc9d39 + 12980cf commit bdab5d3

File tree

9 files changed

+160
-30
lines changed

9 files changed

+160
-30
lines changed

util/pom.xml

+10
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@
5656
<artifactId>logback-classic</artifactId>
5757
<version>1.2.3</version>
5858
</dependency>
59+
<dependency>
60+
<groupId>org.bouncycastle</groupId>
61+
<artifactId>bcprov-ext-jdk15on</artifactId>
62+
<version>1.59</version>
63+
</dependency>
64+
<dependency>
65+
<groupId>org.bouncycastle</groupId>
66+
<artifactId>bcpkix-jdk15on</artifactId>
67+
<version>1.59</version>
68+
</dependency>
5969
<!-- test dependencies -->
6070
<dependency>
6171
<groupId>junit</groupId>

util/src/main/java/io/kubernetes/client/util/SSLUtils.java

+45-13
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.security.KeyStoreException;
3333
import java.security.NoSuchAlgorithmException;
3434
import java.security.PrivateKey;
35+
import java.security.Security;
3536
import java.security.UnrecoverableKeyException;
3637
import java.security.cert.Certificate;
3738
import java.security.cert.CertificateException;
@@ -43,8 +44,15 @@
4344
import javax.net.ssl.KeyManager;
4445
import javax.net.ssl.KeyManagerFactory;
4546
import org.apache.commons.codec.binary.Base64;
47+
import org.bouncycastle.openssl.PEMKeyPair;
48+
import org.bouncycastle.openssl.PEMParser;
49+
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
4650

4751
public class SSLUtils {
52+
static {
53+
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
54+
}
55+
4856
public static boolean isNotNullOrEmpty(String val) {
4957
return val != null && val.length() > 0;
5058
}
@@ -91,6 +99,42 @@ public static KeyStore createKeyStore(
9199
}
92100
}
93101

102+
private static PrivateKey loadKey(InputStream keyInputStream, String clientKeyAlgo)
103+
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
104+
105+
// Try PKCS7 / EC
106+
if (clientKeyAlgo.equals("EC")) {
107+
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
108+
PEMKeyPair keys =
109+
(PEMKeyPair) new PEMParser(new InputStreamReader(keyInputStream)).readObject();
110+
return new JcaPEMKeyConverter().getKeyPair(keys).getPrivate();
111+
}
112+
113+
byte[] keyBytes = decodePem(keyInputStream);
114+
115+
// Try PKCS1 / RSA
116+
if (clientKeyAlgo.equals("RSA")) {
117+
RSAPrivateCrtKeySpec keySpec = decodePKCS1(keyBytes);
118+
return KeyFactory.getInstance("RSA").generatePrivate(keySpec);
119+
}
120+
121+
// Try PKCS8
122+
// TODO: There _has_ to be a better way to do this, but I spent >
123+
// 2 hours trying to find it and failed...
124+
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
125+
try {
126+
return KeyFactory.getInstance("RSA").generatePrivate(spec);
127+
} catch (InvalidKeySpecException ex) {
128+
// ignore if it's not RSA
129+
}
130+
try {
131+
return KeyFactory.getInstance("ECDSA").generatePrivate(spec);
132+
} catch (InvalidKeySpecException ex) {
133+
// ignore if it's not DSA
134+
}
135+
throw new InvalidKeySpecException("Unknown type of PKCS8 Private Key, tried RSA and ECDSA");
136+
}
137+
94138
public static KeyStore createKeyStore(
95139
InputStream certInputStream,
96140
InputStream keyInputStream,
@@ -103,19 +147,7 @@ public static KeyStore createKeyStore(
103147
CertificateFactory certFactory = CertificateFactory.getInstance("X509");
104148
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(certInputStream);
105149

106-
byte[] keyBytes = decodePem(keyInputStream);
107-
108-
PrivateKey privateKey;
109-
110-
KeyFactory keyFactory = KeyFactory.getInstance(clientKeyAlgo);
111-
try {
112-
// First let's try PKCS8
113-
privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
114-
} catch (InvalidKeySpecException e) {
115-
// Otherwise try PKCS1
116-
RSAPrivateCrtKeySpec keySpec = decodePKCS1(keyBytes);
117-
privateKey = keyFactory.generatePrivate(keySpec);
118-
}
150+
PrivateKey privateKey = loadKey(keyInputStream, clientKeyAlgo);
119151

120152
KeyStore keyStore = KeyStore.getInstance("JKS");
121153
if (keyStoreFile != null && keyStoreFile.length() > 0) {

util/src/main/java/io/kubernetes/client/util/credentials/ClientCertificateAuthentication.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,16 @@ public ClientCertificateAuthentication(final byte[] certificate, final byte[] ke
2525

2626
@Override
2727
public void provide(ApiClient client) {
28+
String dataString = new String(key);
29+
String algo = "";
30+
if (dataString.indexOf("BEGIN EC PRIVATE KEY") != -1) {
31+
algo = "EC";
32+
}
33+
if (dataString.indexOf("BEGIN RSA PRIVATE KEY") != -1) {
34+
algo = "RSA";
35+
}
2836
try {
29-
final KeyManager[] keyManagers =
30-
SSLUtils.keyManagers(certificate, key, "RSA", "", null, null);
37+
final KeyManager[] keyManagers = SSLUtils.keyManagers(certificate, key, algo, "", null, null);
3138
client.setKeyManagers(keyManagers);
3239
} catch (NoSuchAlgorithmException
3340
| UnrecoverableKeyException

util/src/test/java/io/kubernetes/client/util/credentials/ClientCertificateAuthenticationTest.java

+37
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,20 @@
88

99
public class ClientCertificateAuthenticationTest {
1010
private static final String CLIENT_CERT_PATH = Resources.getResource("clientauth.cert").getPath();
11+
private static final String CLIENT_EC_CERT_PATH =
12+
Resources.getResource("clientauth-ec.cert").getPath();
13+
14+
// RSA key in PKCS8 format
1115
private static final String CLIENT_KEY_PATH = Resources.getResource("clientauth.key").getPath();
16+
// EC key in PKCS8 format
17+
private static final String CLIENT_EC_KEY_PATH =
18+
Resources.getResource("clientauth-ec-fixed.key").getPath();
19+
// RSA key in PKCS1 format
20+
private static final String CLIENT_KEY_OLD_PATH =
21+
Resources.getResource("clientauth-rsa.key").getPath();
22+
// EC key in PKCS7 format
23+
private static final String CLIENT_EC_KEY_OLD_PATH =
24+
Resources.getResource("clientauth-ec.key").getPath();
1225

1326
@Test
1427
public void testValidCertificates() throws Exception {
@@ -23,4 +36,28 @@ public void testInvalidCertificates() {
2336
final ApiClient client = new ApiClient();
2437
new ClientCertificateAuthentication(new byte[] {}, new byte[] {}).provide(client);
2538
}
39+
40+
@Test
41+
public void testValidECCertificates() throws Exception {
42+
try {
43+
final ApiClient client = new ApiClient();
44+
final byte[] certificate = Files.readAllBytes(Paths.get(CLIENT_EC_CERT_PATH));
45+
final byte[] key = Files.readAllBytes(Paths.get(CLIENT_EC_KEY_PATH));
46+
new ClientCertificateAuthentication(certificate, key).provide(client);
47+
} catch (Exception ex) {
48+
ex.printStackTrace();
49+
}
50+
}
51+
52+
@Test
53+
public void testValidOldECCertificates() throws Exception {
54+
try {
55+
final ApiClient client = new ApiClient();
56+
final byte[] certificate = Files.readAllBytes(Paths.get(CLIENT_EC_CERT_PATH));
57+
final byte[] key = Files.readAllBytes(Paths.get(CLIENT_EC_KEY_OLD_PATH));
58+
new ClientCertificateAuthentication(certificate, key).provide(client);
59+
} catch (Exception ex) {
60+
ex.printStackTrace();
61+
}
62+
}
2663
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgA+GiZiz2t2c2AS2v
3+
YUgHWsENie4qpXhBUBgFfjJGoAShRANCAARQcGDs68qRKmsCWNBwJylcWez+kw0O
4+
RAlm6iiP3sDTTreKkGtnNt3FNy5VwGMU0kL9OfaR41JA/6b1BtCZB+Yz
5+
-----END PRIVATE KEY-----
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIC7TCCAdWgAwIBAgIUD0Q+lZUpqmvTUxmCbhsPx93hYI4wDQYJKoZIhvcNAQEL
3+
BQAwczELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNV
4+
BAcTAkNBMRgwFgYDVQQKEw9NeSBDb21wYW55IE5hbWUxEzARBgNVBAsTCk9yZyBV
5+
bml0IDIxEDAOBgNVBAMTB0t1YmUgQ0EwHhcNMTgwMjEzMDc1MzAwWhcNMjMwMjEy
6+
MDc1MzAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNU2FuIEZyYW5jaXNjbzEL
7+
MAkGA1UEBxMCQ0ExDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0D
8+
AQcDQgAEUHBg7OvKkSprAljQcCcpXFns/pMNDkQJZuooj97A0063ipBrZzbdxTcu
9+
VcBjFNJC/Tn2keNSQP+m9QbQmQfmM6N1MHMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
10+
JQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMBq0KJaRKoC
11+
+a8R5la/B8tJahD3MB8GA1UdIwQYMBaAFOuZHF+ex0WLX3UX9LJoFHbI9cPNMA0G
12+
CSqGSIb3DQEBCwUAA4IBAQC47D3zYMTg/C9gOYu20xEmw6eTEhJ1wWG9jSdHM9G8
13+
0F3mD4+bG3skx5kaCgtJ3KqbMSGPJ234Ju9VHCNiyiasZS41a8wuagJ6v5pTItLL
14+
BmQ3OhT2HJZz+lDbsb3jLDzesQ5UCct08/e8ST4hnZUcSrz2geD1hSYQEhadsI87
15+
A+wVAvGfhCyiDUiClA2vwosWfomshkWphRzy+s5zFLuxlBAxj8g2oAbCJfhfJS5A
16+
O8W5Nu+ddO5+7PB+y28Bue1GWABIjytmyLdvic0vkKzZkSzPOwqCT1ofZ9HU56h7
17+
jKOjtBacCcl/7pLgvaA8Ng1qfjQTiveDVfI8rNWiEhRm
18+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-----BEGIN EC PRIVATE KEY-----
2+
MHcCAQEEIAPhomYs9rdnNgEtr2FIB1rBDYnuKqV4QVAYBX4yRqAEoAoGCCqGSM49
3+
AwEHoUQDQgAEUHBg7OvKkSprAljQcCcpXFns/pMNDkQJZuooj97A0063ipBrZzbd
4+
xTcuVcBjFNJC/Tn2keNSQP+m9QbQmQfmMw==
5+
-----END EC PRIVATE KEY-----
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIICXQIBAAKBgQDz2XhYxigM1TVl6+O+nl4lM+uTNs4T8h2n2bUc7GVgjSN3Xj6L
3+
6cuId+w6o9jKEC90Zgbe2UkWAkxSG3bGzhlTHM6Qh4zi8o9ybg+Yt/fYzR6KhsIt
4+
2y1D/yiyMC4FCc3oARXh7djhk3qZuS4sbeX/DsqE61Sr9NzWR6RvqgimDwIDAQAB
5+
AoGBAKnZs6MaO3Fc3TnmChePVgJR3OgIx5hLD+8HjMjdvGt5Q9f0dFqeed/PsGLU
6+
F7//cB6Cpox5Cxhid2jFqoEls6q9jnnVGYGDJHDQ7u//xigVfHf9lJzmdxQWId6G
7+
F6VoU0N6Oh2AtG4L/SQqnbacG1JVXZun/8J8bBon6C4PeacZAkEA/YaNeLcLtv22
8+
992UJaj3Rd9i5Sxs6dH6PDoABvkbipqWtj4osiMt6a5h32Xy/811CYDI1wvcVDDr
9+
9HAQP1pfPQJBAPY6vcA+JuKdg9KSZzCh77aE5LGXqz62rcMlUHPtRchNfcFo06MC
10+
ehKA+YIBmT5we0GrdyAXsYGIVypK0l8irzsCQEkr43r6wavP8FX7or131d5Zye5A
11+
8zJNAz8MsmNQ1G0djvAMYqx/UMoIJYFXqFnCD8xtWgoPB0lZUVCcY2QVjjUCQGYk
12+
A+alYZgL400MckXYRwodooiQ8/Z17SrQZclRGet3Sb1bcL9kHaNjYR0u8JTYMCkT
13+
qbzkVzv2hMIEe7P/PVUCQQCxLiT5qDxQawP1/ZFnp4KCHTKTQ1Mvw8cGajEG+DKP
14+
2GzD8K03HaJU5eN4Z1Uo1TYPQY1tRD3nM+sDH9EcLvqP
15+
-----END RSA PRIVATE KEY-----
+16-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
-----BEGIN RSA PRIVATE KEY-----
2-
MIICXQIBAAKBgQDz2XhYxigM1TVl6+O+nl4lM+uTNs4T8h2n2bUc7GVgjSN3Xj6L
3-
6cuId+w6o9jKEC90Zgbe2UkWAkxSG3bGzhlTHM6Qh4zi8o9ybg+Yt/fYzR6KhsIt
4-
2y1D/yiyMC4FCc3oARXh7djhk3qZuS4sbeX/DsqE61Sr9NzWR6RvqgimDwIDAQAB
5-
AoGBAKnZs6MaO3Fc3TnmChePVgJR3OgIx5hLD+8HjMjdvGt5Q9f0dFqeed/PsGLU
6-
F7//cB6Cpox5Cxhid2jFqoEls6q9jnnVGYGDJHDQ7u//xigVfHf9lJzmdxQWId6G
7-
F6VoU0N6Oh2AtG4L/SQqnbacG1JVXZun/8J8bBon6C4PeacZAkEA/YaNeLcLtv22
8-
992UJaj3Rd9i5Sxs6dH6PDoABvkbipqWtj4osiMt6a5h32Xy/811CYDI1wvcVDDr
9-
9HAQP1pfPQJBAPY6vcA+JuKdg9KSZzCh77aE5LGXqz62rcMlUHPtRchNfcFo06MC
10-
ehKA+YIBmT5we0GrdyAXsYGIVypK0l8irzsCQEkr43r6wavP8FX7or131d5Zye5A
11-
8zJNAz8MsmNQ1G0djvAMYqx/UMoIJYFXqFnCD8xtWgoPB0lZUVCcY2QVjjUCQGYk
12-
A+alYZgL400MckXYRwodooiQ8/Z17SrQZclRGet3Sb1bcL9kHaNjYR0u8JTYMCkT
13-
qbzkVzv2hMIEe7P/PVUCQQCxLiT5qDxQawP1/ZFnp4KCHTKTQ1Mvw8cGajEG+DKP
14-
2GzD8K03HaJU5eN4Z1Uo1TYPQY1tRD3nM+sDH9EcLvqP
15-
-----END RSA PRIVATE KEY-----
1+
-----BEGIN PRIVATE KEY-----
2+
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAPPZeFjGKAzVNWXr
3+
476eXiUz65M2zhPyHafZtRzsZWCNI3dePovpy4h37Dqj2MoQL3RmBt7ZSRYCTFIb
4+
dsbOGVMczpCHjOLyj3JuD5i399jNHoqGwi3bLUP/KLIwLgUJzegBFeHt2OGTepm5
5+
Lixt5f8OyoTrVKv03NZHpG+qCKYPAgMBAAECgYEAqdmzoxo7cVzdOeYKF49WAlHc
6+
6AjHmEsP7weMyN28a3lD1/R0Wp5538+wYtQXv/9wHoKmjHkLGGJ3aMWqgSWzqr2O
7+
edUZgYMkcNDu7//GKBV8d/2UnOZ3FBYh3oYXpWhTQ3o6HYC0bgv9JCqdtpwbUlVd
8+
m6f/wnxsGifoLg95pxkCQQD9ho14twu2/bb33ZQlqPdF32LlLGzp0fo8OgAG+RuK
9+
mpa2PiiyIy3prmHfZfL/zXUJgMjXC9xUMOv0cBA/Wl89AkEA9jq9wD4m4p2D0pJn
10+
MKHvtoTksZerPratwyVQc+1FyE19wWjTowJ6EoD5ggGZPnB7Qat3IBexgYhXKkrS
11+
XyKvOwJASSvjevrBq8/wVfuivXfV3lnJ7kDzMk0DPwyyY1DUbR2O8AxirH9Qyggl
12+
gVeoWcIPzG1aCg8HSVlRUJxjZBWONQJAZiQD5qVhmAvjTQxyRdhHCh2iiJDz9nXt
13+
KtBlyVEZ63dJvVtwv2Qdo2NhHS7wlNgwKROpvORXO/aEwgR7s/89VQJBALEuJPmo
14+
PFBrA/X9kWengoIdMpNDUy/DxwZqMQb4Mo/YbMPwrTcdolTl43hnVSjVNg9BjW1E
15+
Pecz6wMf0Rwu+o8=
16+
-----END PRIVATE KEY-----

0 commit comments

Comments
 (0)