Skip to content

Commit

Permalink
Support BouncyCastle ECDSA KeyPairGenerator and AES/CBC/PKCS7Padding …
Browse files Browse the repository at this point in the history
…Cipher
  • Loading branch information
sberyozkin committed Feb 15, 2022
1 parent 9636db6 commit c0dc625
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 4 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 Down Expand Up @@ -222,23 +232,53 @@ 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()
final String commonProviderName = bouncyCastleJsseProvider.get().isInFipsMode()
? SecurityProviderUtils.BOUNCYCASTLE_FIPS_PROVIDER_CLASS_NAME
: SecurityProviderUtils.BOUNCYCASTLE_PROVIDER_CLASS_NAME;
additionalProviders.produce(new NativeImageSecurityProviderBuildItem(providerName));
additionalProviders.produce(new NativeImageSecurityProviderBuildItem(commonProviderName));

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

ResultHandle bcCommonProvider = overallCatch
.newInstance(MethodDescriptor.ofConstructor(commonProviderName));
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),
bcCommonProvider, overallCatch.load(sunJsseIndex));
overallCatch.invokeStaticMethod(
MethodDescriptor.ofMethod(Security.class, "insertProviderAt", int.class, Provider.class, int.class),
bcJsseProvider, overallCatch.load(sunJsseIndex + 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
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 c0dc625

Please sign in to comment.