Skip to content

Commit

Permalink
Add BouncyCastle providers to generated AutoFeature
Browse files Browse the repository at this point in the history
  • Loading branch information
sberyozkin committed Feb 24, 2022
1 parent 36351d4 commit 39d3923
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.deployment.builditem.nativeimage;

import io.quarkus.gizmo.TryBlock;

public interface AutoFeatureAugmentor {
void augment(TryBlock overallCatch);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.quarkus.deployment.builditem.nativeimage;

import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.gizmo.TryBlock;

/**
* A build item that can be used to augment the generated AutoFeature
*/
public final class NativeImageAutoFeatureAugmentorBuildItem extends MultiBuildItem {
AutoFeatureAugmentor autoFeatureAugmentor;

public NativeImageAutoFeatureAugmentorBuildItem(AutoFeatureAugmentor autoFeatureAugmentor) {
this.autoFeatureAugmentor = autoFeatureAugmentor;
}

public void augment(TryBlock overallCatch) {
autoFeatureAugmentor.augment(overallCatch);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ForceNonWeakReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.JniRuntimeAccessBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageAutoFeatureAugmentorBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageProxyDefinitionBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem;
Expand Down Expand Up @@ -114,6 +115,7 @@ void generateFeature(BuildProducer<GeneratedNativeImageClassBuildItem> nativeIma
List<NativeImageProxyDefinitionBuildItem> proxies,
List<NativeImageResourcePatternsBuildItem> resourcePatterns,
List<NativeImageResourceBundleBuildItem> resourceBundles,
List<NativeImageAutoFeatureAugmentorBuildItem> augmentors,
List<ReflectiveMethodBuildItem> reflectiveMethods,
List<ReflectiveFieldBuildItem> reflectiveFields,
List<ReflectiveClassBuildItem> reflectiveClassBuildItems,
Expand Down Expand Up @@ -337,6 +339,11 @@ public void write(String s, byte[] bytes) {
//c.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), c.getCaughtException());
}
}

for (NativeImageAutoFeatureAugmentorBuildItem augmentor : augmentors) {
augmentor.augment(overallCatch);
}

int count = 0;

final Map<String, ReflectionInfo> reflectiveClasses = new LinkedHashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.quarkus.security.deployment;

import static io.quarkus.security.runtime.SecurityProviderUtils.findProviderIndex;

import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
Expand Down Expand Up @@ -42,12 +44,15 @@
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.ApplicationClassPredicateBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.nativeimage.AutoFeatureAugmentor;
import io.quarkus.deployment.builditem.nativeimage.JPMSExportBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageAutoFeatureAugmentorBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageSecurityProviderBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.gizmo.TryBlock;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.security.runtime.IdentityProviderManagerCreator;
import io.quarkus.security.runtime.SecurityBuildTimeConfig;
Expand Down Expand Up @@ -149,10 +154,15 @@ private static void prepareBouncyCastleProvider(BuildProducer<ReflectiveClassBui
isFipsMode ? SecurityProviderUtils.BOUNCYCASTLE_FIPS_PROVIDER_CLASS_NAME
: SecurityProviderUtils.BOUNCYCASTLE_PROVIDER_CLASS_NAME));
reflection.produce(new ReflectiveClassBuildItem(true, true,
"org.bouncycastle.jcajce.provider.symmetric.AES",
"org.bouncycastle.jcajce.provider.symmetric.AES$CBC",
"org.bouncycastle.crypto.paddings.PKCS7Padding",
"org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi",
"org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi$EC",
"org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi$ECDSA",
"org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi",
"org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi$EC",
"org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi$ECDSA",
"org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi",
"org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyPairGeneratorSpi",
"org.bouncycastle.jcajce.provider.asymmetric.rsa.PSSSignatureSpi",
Expand All @@ -169,13 +179,6 @@ private static void prepareBouncyCastleProvider(BuildProducer<ReflectiveClassBui
} else {
reflection.produce(new ReflectiveClassBuildItem(true, true, true, "org.bouncycastle.crypto.general.AES"));
runtimeReInitialized.produce(new RuntimeReinitializedClassBuildItem("org.bouncycastle.crypto.general.AES"));
runtimeReInitialized
.produce(new RuntimeReinitializedClassBuildItem("org.bouncycastle.math.ec.custom.sec.SecP521R1Curve"));
runtimeReInitialized
.produce(new RuntimeReinitializedClassBuildItem("org.bouncycastle.math.ec.custom.sec.SecP384R1Curve"));
runtimeReInitialized
.produce(new RuntimeReinitializedClassBuildItem("org.bouncycastle.math.ec.custom.sec.SecP256R1Curve"));
runtimeReInitialized.produce(new RuntimeReinitializedClassBuildItem("org.bouncycastle.math.ec.ECPoint"));
runtimeReInitialized
.produce(new RuntimeReinitializedClassBuildItem(
"org.bouncycastle.crypto.asymmetric.NamedECDomainParameters"));
Expand Down Expand Up @@ -222,23 +225,73 @@ void recordBouncyCastleProviders(SecurityProviderRecorder recorder,

@BuildStep
void addBouncyCastleProvidersToNativeImage(BuildProducer<NativeImageSecurityProviderBuildItem> additionalProviders,
BuildProducer<NativeImageAutoFeatureAugmentorBuildItem> autoFeatureAugmentors,
List<BouncyCastleProviderBuildItem> bouncyCastleProviders,
List<BouncyCastleJsseProviderBuildItem> bouncyCastleJsseProviders) {
Optional<BouncyCastleJsseProviderBuildItem> bouncyCastleJsseProvider = getOne(bouncyCastleJsseProviders);
if (bouncyCastleJsseProvider.isPresent()) {
additionalProviders.produce(
new NativeImageSecurityProviderBuildItem(SecurityProviderUtils.BOUNCYCASTLE_JSSE_PROVIDER_CLASS_NAME));
final String providerName = bouncyCastleJsseProvider.get().isInFipsMode()
? SecurityProviderUtils.BOUNCYCASTLE_FIPS_PROVIDER_CLASS_NAME
: SecurityProviderUtils.BOUNCYCASTLE_PROVIDER_CLASS_NAME;
additionalProviders.produce(new NativeImageSecurityProviderBuildItem(providerName));

autoFeatureAugmentors.produce(new NativeImageAutoFeatureAugmentorBuildItem(new AutoFeatureAugmentor() {
@Override
public void augment(TryBlock overallCatch) {
if (!bouncyCastleJsseProvider.get().isInFipsMode()) {
final int sunJsseIndex = findProviderIndex(SecurityProviderUtils.SUN_JSSE_PROVIDER_NAME);

ResultHandle bcProvider = overallCatch
.newInstance(
MethodDescriptor.ofConstructor(SecurityProviderUtils.BOUNCYCASTLE_PROVIDER_CLASS_NAME));
ResultHandle bcJsseProvider = overallCatch.newInstance(
MethodDescriptor.ofConstructor(SecurityProviderUtils.BOUNCYCASTLE_JSSE_PROVIDER_CLASS_NAME));

overallCatch.invokeStaticMethod(
MethodDescriptor.ofMethod(Security.class, "insertProviderAt", int.class, Provider.class,
int.class),
bcProvider, overallCatch.load(sunJsseIndex));
overallCatch.invokeStaticMethod(
MethodDescriptor.ofMethod(Security.class, "insertProviderAt", int.class, Provider.class,
int.class),
bcJsseProvider, overallCatch.load(sunJsseIndex + 1));
} else {
final int sunIndex = findProviderIndex(SecurityProviderUtils.SUN_PROVIDER_NAME);

ResultHandle bcFipsProvider = overallCatch
.newInstance(MethodDescriptor
.ofConstructor(SecurityProviderUtils.BOUNCYCASTLE_FIPS_PROVIDER_CLASS_NAME));
MethodDescriptor bcJsseProviderConstructor = MethodDescriptor.ofConstructor(
SecurityProviderUtils.BOUNCYCASTLE_JSSE_PROVIDER_CLASS_NAME, "boolean",
Provider.class.getName());
ResultHandle bcJsseProvider = overallCatch.newInstance(bcJsseProviderConstructor,
overallCatch.load(true), bcFipsProvider);

overallCatch.invokeStaticMethod(
MethodDescriptor.ofMethod(Security.class, "insertProviderAt", int.class, Provider.class,
int.class),
bcFipsProvider, overallCatch.load(sunIndex));
overallCatch.invokeStaticMethod(
MethodDescriptor.ofMethod(Security.class, "insertProviderAt", int.class, Provider.class,
int.class),
bcJsseProvider, overallCatch.load(sunIndex + 1));
}
}
}));
} else {
Optional<BouncyCastleProviderBuildItem> bouncyCastleProvider = getOne(bouncyCastleProviders);
if (bouncyCastleProvider.isPresent()) {
final String providerName = bouncyCastleProvider.get().isInFipsMode()
? SecurityProviderUtils.BOUNCYCASTLE_FIPS_PROVIDER_CLASS_NAME
: SecurityProviderUtils.BOUNCYCASTLE_PROVIDER_CLASS_NAME;
additionalProviders.produce(new NativeImageSecurityProviderBuildItem(providerName));

autoFeatureAugmentors.produce(new NativeImageAutoFeatureAugmentorBuildItem(new AutoFeatureAugmentor() {
@Override
public void augment(TryBlock overallCatch) {
ResultHandle bcProvider = overallCatch.newInstance(MethodDescriptor.ofConstructor(providerName));
overallCatch.invokeStaticMethod(
MethodDescriptor.ofMethod(Security.class, "addProvider", int.class, Provider.class),
bcProvider);
}
}));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package io.quarkus.security.runtime.graal;

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

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.RecomputeFieldValue;

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";
Expand Down Expand Up @@ -86,6 +90,24 @@ final class Target_org_bouncycastle_crypto_internal_AsymmetricCipherKeyPair {
final class Target_org_bouncycastle_crypto_fips_RsaBlindedEngine {
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider", onlyWith = BouncyCastleCryptoFips.class)
final class Target_org_bouncycastle_jcajce_provider_BouncyCastleFipsProvider {
@Alias
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
private SecureRandom entropySource;

@Alias
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
private SecureRandom providerDefaultRandom;
}

@com.oracle.svm.core.annotate.TargetClass(className = "org.bouncycastle.math.ec.ECPoint", onlyWith = BouncyCastleCryptoFips.class)
final class Target_org_bouncycastle_math_ec_ECPoint {
@Alias //
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
private static SecureRandom testRandom;
}

class BouncyCastleCryptoFips implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.DisabledOnNativeImage;
import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class BouncyCastleJsseITCase extends BouncyCastleJsseTestCase {
@Test
@DisabledOnNativeImage
@Override
public void testListProviders() {
doTestListProviders();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Arrays;
import java.util.stream.Collectors;

import javax.crypto.Cipher;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

Expand Down Expand Up @@ -45,6 +46,14 @@ public String generateEcKeyPair() throws Exception {
return "success";
}

@GET
@Path("generateEcDsaKeyPair")
public String generateEcDsaKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "BC");
keyPairGenerator.generateKeyPair();
return "success";
}

@GET
@Path("generateRsaKeyPair")
public String generateRsaKeyPair() throws Exception {
Expand All @@ -53,6 +62,13 @@ public String generateRsaKeyPair() throws Exception {
return "success";
}

@GET
@Path("checkAesCbcPKCS7PaddingCipher")
public String checkAesCbcPKCS7PaddingCipher() throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
return cipher.getAlgorithm();
}

@GET
@Path("readEcPrivatePemKey")
public String readEcPrivatePemKey() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ public void testGenerateEcKeyPair() {
.body(equalTo("success"));
}

@Test
public void testGenerateEcDsaKeyPair() {
RestAssured.given()
.when()
.get("/jca/generateEcDsaKeyPair")
.then()
.statusCode(200)
.body(equalTo("success"));
}

@Test
public void testGenerateRsaKeyPair() {
RestAssured.given()
Expand All @@ -50,6 +60,16 @@ public void testGenerateRsaKeyPair() {
.body(equalTo("success"));
}

@Test
public void testAesCbcPKCS7PaddingCipher() {
RestAssured.given()
.when()
.get("/jca/checkAesCbcPKCS7PaddingCipher")
.then()
.statusCode(200)
.body(equalTo("AES/CBC/PKCS7Padding"));
}

@Test
public void readEcPrivatePemKey() {
RestAssured.given()
Expand Down

0 comments on commit 39d3923

Please sign in to comment.