Skip to content

Commit

Permalink
Support bc-fips in BouncyCastleSelfSignedCertGenerator (#13954)
Browse files Browse the repository at this point in the history
Motivation:

When using the bouncycastle FIPS dependencies (bcpkix-fips instead of
bcpkix, and bc-fips instead of bcprov), BouncyCastleProvider is replaced
by BouncyCastleFipsProvider. This made
BouncyCastleSelfSignedCertGenerator fail even though all the necessary
algorithms are present.

While bc-fips is only necessary for fips-compliant production
deployments, and self-signed certs are only necessary in test
deployments that don't have to be fips-compliant, this change is still
useful because the fips and non-fips artifacts cannot exist alongside
each other. So if you have a prod fips dependency, tests that also have
a non-fips dependency for self-signed certs cannot live alongside each
other. It's easiest to just use the fips dependency everywhere.

Modification:

Use reflection in BouncyCastleSelfSignedCertGenerator to instantiate
whichever provider is available. This has the advantage of not needing a
new dependency, though it may have some impact on native image
deployments. For this reason I've also added the providers to the
reflect-config.json.

No test is possible because it would require a different classpath. I
tested manually that it works by changing to the fips dependencies and
then running SelfSignedCertificateTest, and checking with a debugger
that the correct provider was used.

Result:

SelfSignedCertificate will work with bc-fips dependencies.
  • Loading branch information
yawkat authored and chrisvest committed Apr 27, 2024
1 parent 5f5dcdc commit f6a4533
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
Expand Up @@ -20,7 +20,6 @@
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

Expand All @@ -39,7 +38,25 @@
*/
final class BouncyCastleSelfSignedCertGenerator {

private static final Provider PROVIDER = new BouncyCastleProvider();
private static final Provider PROVIDER;

static {
Class<?> providerClass;
try {
providerClass = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
} catch (ClassNotFoundException e) {
try {
providerClass = Class.forName("org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider");
} catch (ClassNotFoundException ignore) {
throw new RuntimeException("Neither BouncyCastleProvider nor BouncyCastleFipsProvider found");
}
}
try {
PROVIDER = (Provider) providerClass.newInstance();
} catch (Exception e) {
throw new RuntimeException("Failed to instantiate BouncyCastle provider", e);
}
}

static String[] generate(String fqdn, KeyPair keypair, SecureRandom random, Date notBefore, Date notAfter,
String algorithm) throws Exception {
Expand Down
Expand Up @@ -386,6 +386,7 @@ private static void safeClose(File keyFile, OutputStream keyOut) {

private static boolean isBouncyCastleAvailable() {
try {
// this class is in bcpkix, both fips and non-fips
Class.forName("org.bouncycastle.cert.X509v3CertificateBuilder");
return true;
} catch (ClassNotFoundException e) {
Expand Down
28 changes: 28 additions & 0 deletions testsuite/src/main/resources/reflect-config.json
@@ -0,0 +1,28 @@
[
{
"name": "org.bouncycastle.jce.provider.BouncyCastleProvider",
"condition": {
"typeReachable": "org.bouncycastle.jcajce.provider.BouncyCastleProvider"
},
"methods": [
{
"name": "<init>",
"parameterTypes": [
]
}
]
},
{
"name": "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider",
"condition": {
"typeReachable": "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider"
},
"methods": [
{
"name": "<init>",
"parameterTypes": [
]
}
]
}
]

0 comments on commit f6a4533

Please sign in to comment.