Skip to content

Commit

Permalink
fix: remove bc optional dependency
Browse files Browse the repository at this point in the history
closes: fabric8io#6008

Signed-off-by: Steve Hawkins <[email protected]>
  • Loading branch information
shawkins committed Jun 12, 2024
1 parent 456c810 commit 7e02622
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 90 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#### Bugs

#### Improvements
* Fix #6008: removing the optional dependency on bouncy castle

#### Dependency Upgrade

Expand Down
7 changes: 0 additions & 7 deletions httpclient-vertx/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,6 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<!-- Required by SslTest -->
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
4 changes: 0 additions & 4 deletions junit/kube-api-test/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,6 @@
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
</dependency>
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>kubernetes-webhooks-framework-core</artifactId>
Expand Down
10 changes: 0 additions & 10 deletions junit/kubernetes-junit-jupiter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,6 @@
<artifactId>commons-compress</artifactId>
<optional>false</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<optional>false</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<optional>false</optional>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
Expand Down
2 changes: 0 additions & 2 deletions kubernetes-client-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,10 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<optional>true</optional>
</dependency>

<!-- Compile Only Dependencies -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,7 @@
*/
package io.fabric8.kubernetes.client.internal;

import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.utils.Utils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -40,7 +34,6 @@
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
Expand All @@ -52,7 +45,6 @@
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

public class CertUtils {
Expand Down Expand Up @@ -177,42 +169,10 @@ private static PrivateKey loadKey(InputStream keyInputStream, String clientKeyAl
throw new InvalidKeySpecException("Unknown type of PKCS8 Private Key, tried RSA and ECDSA");
}

private static PrivateKey handleECKey(InputStream keyInputStream) {
// Let's wrap the code to a callable inner class to avoid NoClassDef when loading this class.
try {
return new Callable<PrivateKey>() {
@Override
public PrivateKey call() throws IOException {
if (Security.getProvider("BC") == null && Security.getProvider("BCFIPS") == null) {
// org.bouncycastle.jce.provider.BouncyCastleProvider needs to be wrapped with a Callable otherwise
// runtime won't even evaluate this whole block. This happens even when above condition testing if
// block evaluates to false
new Callable<String>() {
@Override
public String call() {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
return null;
}
}.call();
}
Object pemObject = new PEMParser(new InputStreamReader(keyInputStream)).readObject();
if (pemObject == null) {
throw new KubernetesClientException("Got null PEM object from EC key's input stream.");
} else if (pemObject instanceof PEMKeyPair) {
return new JcaPEMKeyConverter().getKeyPair((PEMKeyPair) pemObject).getPrivate();
} else if (pemObject instanceof PrivateKeyInfo) {
return BouncyCastleProvider.getPrivateKey((PrivateKeyInfo) pemObject);
} else {
throw new KubernetesClientException("Don't know what to do with a " + pemObject.getClass().getName());
}
}
}.call();
} catch (NoClassDefFoundError e) {
throw new KubernetesClientException(
"JcaPEMKeyConverter is provided by BouncyCastle, an optional dependency. To use support for EC Keys you must explicitly add this dependency to classpath.");
} catch (IOException e) {
throw new KubernetesClientException(e.getMessage());
}
private static PrivateKey handleECKey(InputStream keyInputStream)
throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
byte[] keyBytes = decodePem(keyInputStream);
return KeyFactory.getInstance("EC").generatePrivate(PKCS1Util.getECKeySpec(keyBytes));
}

private static PrivateKey handleOtherKeys(InputStream keyInputStream, String clientKeyAlgo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,18 @@
*/
package io.fabric8.kubernetes.client.internal;

import java.io.*;
import io.fabric8.kubernetes.client.KubernetesClientException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPairGenerator;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;

/**
Expand Down Expand Up @@ -57,9 +67,12 @@ private static BigInteger next(DerParser parser) throws IOException {

static class DerParser {

private final static int SEQUENCE = 0x10;
private final static int INTEGER = 0x02;
private final static int OBJECT_IDENTIFIER = 0x06;
private InputStream in;

DerParser(byte[] bytes) throws IOException {
DerParser(byte[] bytes) {
this.in = new ByteArrayInputStream(bytes);
}

Expand Down Expand Up @@ -136,4 +149,75 @@ void validateSequence() throws IOException {
}
}
}

// adapted from io.vertx.core.net.impl.pkcs1.PrivateKeyParser

public static ECPrivateKeySpec getECKeySpec(byte[] keyBytes) throws IOException {
DerParser parser = new DerParser(keyBytes);

Asn1Object sequence = parser.read();
if (sequence.type != DerParser.SEQUENCE) {
throw new KubernetesClientException("Invalid DER: not a sequence");
}

// Parse inside the sequence
parser = new DerParser(sequence.value);

Asn1Object version = parser.read();
if (version.type != DerParser.INTEGER) {
throw new KubernetesClientException(String.format(
"Invalid DER: 'version' field must be of type INTEGER (2) but found type `%d`",
version.type));
} else if (version.getInteger().intValue() != 1) {
throw new KubernetesClientException(String.format(
"Invalid DER: expected 'version' field to have value '1' but found '%d'",
version.getInteger().intValue()));
}
byte[] privateValue = parser.read().getValue();
parser = new DerParser(parser.read().getValue());
Asn1Object params = parser.read();
// ECParameters are mandatory according to RFC 5915, Section 3
if (params.type != DerParser.OBJECT_IDENTIFIER) {
throw new KubernetesClientException(String.format(
"Invalid DER: expected to find an OBJECT_IDENTIFIER (6) in 'parameters' but found type '%d'",
params.type));
}
byte[] namedCurveOid = params.getValue();
ECParameterSpec spec = getECParameterSpec(oidToString(namedCurveOid));
return new ECPrivateKeySpec(new BigInteger(1, privateValue), spec);
}

private static ECParameterSpec getECParameterSpec(String curveName) {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(new ECGenParameterSpec(curveName));
ECPublicKey publicKey = (ECPublicKey) keyPairGenerator.generateKeyPair().getPublic();
return publicKey.getParams();
} catch (GeneralSecurityException e) {
throw new KubernetesClientException("Cannot determine EC parameter spec for curve name/OID", e);
}
}

private static String oidToString(byte[] oid) {
StringBuilder result = new StringBuilder();
int value = oid[0] & 0xff;
result.append(value / 40).append(".").append(value % 40);
for (int index = 1; index < oid.length; ++index) {
byte bValue = oid[index];
if (bValue < 0) {
value = (bValue & 0b01111111);
++index;
if (index == oid.length) {
throw new IllegalArgumentException("Invalid OID");
}
value <<= 7;
value |= (oid[index] & 0b01111111);
result.append(".").append(value);
} else {
result.append(".").append(bValue);
}
}
return result.toString();
}

}
10 changes: 0 additions & 10 deletions kubernetes-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,6 @@
<version>${zjsonpatch.version}</version>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
Expand Down
9 changes: 0 additions & 9 deletions kubernetes-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,6 @@
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -806,13 +806,13 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
<optional>true</optional>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
<optional>true</optional>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
Expand Down

0 comments on commit 7e02622

Please sign in to comment.