Skip to content

Commit

Permalink
Substitute BouncyCastle self-tests which rely on SecureRandom
Browse files Browse the repository at this point in the history
  • Loading branch information
sberyozkin committed Apr 8, 2021
1 parent c018e31 commit 94aa129
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 0 deletions.
17 changes: 17 additions & 0 deletions docs/src/main/asciidoc/security-customization.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,18 @@ and add the BouncyCastle FIPS provider dependency:
</dependency>
----

[NOTE]
====
`BCFIPS` provider option is supported in native image but the algorithm self-tests which rely on `java.security.SecureRandom` to verify the generated keys have been removed for these tests to pass. The following classes have been affected:
- `org.bouncycastle.crypto.general.DSA`
- `org.bouncycastle.crypto.general.DSTU4145`
- `org.bouncycastle.crypto.general.ECGOST3410`
- `org.bouncycastle.crypto.general.GOST3410`
- `org.bouncycastle.crypto.fips.FipsDSA`
- `org.bouncycastle.crypto.fips.FipsEC`
- `org.bouncycastle.crypto.fips.FipsRSA`
====

=== BouncyCastle JSSE FIPS

If you need to register an `org.bouncycastle.jsse.provider.BouncyCastleJsseProvider` JSSE provider and use it in combination with `org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider` instead of the default SunJSSE provider then please set a `BCFIPSJSSE` provider name:
Expand Down Expand Up @@ -363,6 +375,11 @@ One can generate a keystore with this type and provider like this:
keytool -genkey -alias server -keyalg RSA -keystore server-keystore.jks -keysize 2048 -keypass password -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider -providerpath $PATH_TO_BC_FIPS_JAR -storetype BCFKS
----

[NOTE]
====
`BCFIPSJSSE` provider option is currently not supported in native image.
====

== Reactive Security

If you are going to use security in a reactive environment, you will likely need SmallRye Context Propagation:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ void prepareBouncyCastleProviders(BuildProducer<ReflectiveClassBuildItem> reflec
if (bouncyCastleJsseProvider.isPresent()) {
reflection.produce(
new ReflectiveClassBuildItem(true, true, SecurityProviderUtils.BOUNCYCASTLE_JSSE_PROVIDER_CLASS_NAME));
reflection.produce(new ReflectiveClassBuildItem(true, true, true,
"org.bouncycastle.jsse.provider.DefaultSSLContextSpi$LazyManagers"));
runtimeReInitialized
.produce(new RuntimeReinitializedClassBuildItem(
"org.bouncycastle.jsse.provider.DefaultSSLContextSpi$LazyManagers"));
prepareBouncyCastleProvider(reflection, runtimeReInitialized, bouncyCastleJsseProvider.get().isInFipsMode());
} else if (bouncyCastleProvider.isPresent()) {
prepareBouncyCastleProvider(reflection, runtimeReInitialized, bouncyCastleProvider.get().isInFipsMode());
Expand All @@ -144,10 +149,17 @@ private static void prepareBouncyCastleProvider(BuildProducer<ReflectiveClassBui
runtimeReInitialized
.produce(new RuntimeReinitializedClassBuildItem("org.bouncycastle.crypto.CryptoServicesRegistrar"));
if (!inFipsMode) {
reflection.produce(new ReflectiveClassBuildItem(true, true, true,
"org.bouncycastle.jcajce.provider.drbg.DRBG$Default"));
runtimeReInitialized
.produce(new RuntimeReinitializedClassBuildItem("org.bouncycastle.jcajce.provider.drbg.DRBG$Default"));
runtimeReInitialized
.produce(new RuntimeReinitializedClassBuildItem("org.bouncycastle.jcajce.provider.drbg.DRBG$NonceAndIV"));
} else {
reflection.produce(new ReflectiveClassBuildItem(true, true, true,
"org.bouncycastle.crypto.general.AES"));
runtimeReInitialized
.produce(new RuntimeReinitializedClassBuildItem("org.bouncycastle.crypto.general.AES"));
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package io.quarkus.security.runtime.graal;

import java.util.Arrays;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;

final class BouncyCastlePackages {
static final String ORG_BOUNCYCASTLE_CRYPTO_PACKAGE = "org.bouncycastle.crypto";
static final String ORG_BOUNCYCASTLE_CRYPTO_FIPS_PACKAGE = "org.bouncycastle.crypto.fips";
static final String ORG_BOUNCYCASTLE_CRYPTO_INTERNAL_PACKAGE = "org.bouncycastle.crypto.internal";
static final String ORG_BOUNCYCASTLE_CRYPTO_GENERAL_PACKAGE = "org.bouncycastle.crypto.general";
static final Set<String> PACKAGES = Arrays.asList(Package.getPackages()).stream()
.map(p -> p.getName()).filter(p -> p.startsWith(ORG_BOUNCYCASTLE_CRYPTO_PACKAGE)).collect(Collectors.toSet());
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.general.DSA$1", onlyWith = BouncyCastleCryptoGeneral.class)
final class Target_org_bouncycastle_crypto_general_DSA$1 {
@com.oracle.svm.core.annotate.Substitute
public boolean hasTestPassed(Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair kp) {
return true;
}
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.general.DSTU4145$2", onlyWith = BouncyCastleCryptoGeneral.class)
final class Target_org_bouncycastle_crypto_general_DSTU4145$2 {
@com.oracle.svm.core.annotate.Substitute
public boolean hasTestPassed(Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair kp) {
return true;
}
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.general.ECGOST3410$2", onlyWith = BouncyCastleCryptoGeneral.class)
final class Target_org_bouncycastle_crypto_general_ECGOST3410$2 {
@com.oracle.svm.core.annotate.Substitute
public boolean hasTestPassed(Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair kp) {
return true;
}
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.general.GOST3410$1", onlyWith = BouncyCastleCryptoGeneral.class)
final class Target_org_bouncycastle_crypto_general_GOST3410$1 {
@com.oracle.svm.core.annotate.Substitute
public boolean hasTestPassed(Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair kp) {
return true;
}
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.fips.FipsDSA$2", onlyWith = BouncyCastleCryptoFips.class)
final class Target_org_bouncycastle_crypto_fips_FipsDSA$2 {
@com.oracle.svm.core.annotate.Substitute
public boolean hasTestPassed(Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair kp) {
return true;
}
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.fips.FipsEC$1", onlyWith = BouncyCastleCryptoFips.class)
final class Target_org_bouncycastle_crypto_fips_FipsEC$1 {
@com.oracle.svm.core.annotate.Substitute
public boolean hasTestPassed(Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair kp) {
return true;
}
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.fips.FipsRSA$3", onlyWith = BouncyCastleCryptoFips.class)
final class Target_org_bouncycastle_crypto_fips_FipsRSA$3 {
@com.oracle.svm.core.annotate.Substitute
public boolean hasTestPassed(Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair kp) {
return true;
}
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.fips.FipsRSA$EngineProvider$1", onlyWith = BouncyCastleCryptoFips.class)
final class Target_org_bouncycastle_crypto_fips_FipsRSA$EngineProvider$1 {
@com.oracle.svm.core.annotate.Substitute
public void evaluate(Target_org_bouncycastle_crypto_fips_RsaBlindedEngine rsaEngine) {
// Complete
}
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.internal.AsymmetricCipherKeyPair", onlyWith = BouncyCastleCryptoInternal.class)
final class Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair {
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.crypto.fips.RsaBlindedEngine", onlyWith = BouncyCastleCryptoFips.class)
final class Target_org_bouncycastle_crypto_fips_RsaBlindedEngine {
}

class BouncyCastleCryptoFips implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return BouncyCastlePackages.PACKAGES.contains(BouncyCastlePackages.ORG_BOUNCYCASTLE_CRYPTO_FIPS_PACKAGE);
}
}

class BouncyCastleCryptoGeneral implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return BouncyCastlePackages.PACKAGES.contains(BouncyCastlePackages.ORG_BOUNCYCASTLE_CRYPTO_GENERAL_PACKAGE);
}
}

class BouncyCastleCryptoInternal implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return BouncyCastlePackages.PACKAGES.contains(BouncyCastlePackages.ORG_BOUNCYCASTLE_CRYPTO_INTERNAL_PACKAGE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ quarkus.log.category."org.bouncycastle.jsse".min-level=TRACE
quarkus.log.category."org.bouncycastle.jsse".level=TRACE
quarkus.log.file.enable=true
quarkus.log.file.format=%C - %s%n

#quarkus.native.additional-build-args=--trace-object-instantiation=org.bouncycastle.crypto.fips.FipsSecureRandom\\,java.security.SecureRandom

0 comments on commit 94aa129

Please sign in to comment.