diff --git a/security/bouncycastle-fips/README.md b/security/bouncycastle-fips/README.md index 62e1ad3d6c..6b5191f128 100644 --- a/security/bouncycastle-fips/README.md +++ b/security/bouncycastle-fips/README.md @@ -2,22 +2,14 @@ ## Generate certificates steps (Keytool manual process) -Generate a self-signed PEM ```shell -openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem -``` - -Convert the certificate from PEM to PKCS12, using the following command: -```shell -openssl pkcs12 -export -out Cert.p12 -in cert.pem -inkey key.pem -``` - -Generate truststore from p12 file -```shell -keytool -importkeystore -srckeystore Cert.p12 -srcstoretype pkcs12 -destkeystore server-truststore.jks -deststoretype BCFKS -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider -providerpath $PATH_TO_BC_FIPS_JAR -storetype BCFKS -validity 3000 -``` - -Generate keystore -```shell -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 -validity 3000 -``` +keytool -keystore server-keystore.jks -alias localhost -validity 3000 -genkeypair -keyalg RSA -keysize 2048 -storepass password -keypass password -storetype BCFKS -providerpath /home/pablojosegonzalezgranados/.m2/repository/org/bouncycastle/bc-fips/1.0.2.1/bc-fips-1.0.2.1.jar -providerclass org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider -dname "cn=Redhat, ou=QuarkusQE, o=Redhat,L=Madrid, st=MA, c=ES" -ext SAN="DNS:localhost,IP:127.0.0.1" +openssl req -new -x509 -keyout ca-key -out ca-cert -days 3000 +keytool -keystore client-truststore.jks -storetype BCFKS -alias CARoot -import -file ca-cert -providerpath /home/pablojosegonzalezgranados/.m2/repository/org/bouncycastle/bc-fips/1.0.2.1/bc-fips-1.0.2.1.jar -providerclass org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider +keytool -keystore server-truststore.jks -storetype BCFKS -alias CARoot -importcert -file ca-cert -providerpath /home/pablojosegonzalezgranados/.m2/repository/org/bouncycastle/bc-fips/1.0.2.1/bc-fips-1.0.2.1.jar -providerclass org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider +keytool -keystore server-keystore.jks -alias localhost -storepass password -keypass password -storetype BCFKS -certreq -file cert-file -providerpath /home/pablojosegonzalezgranados/.m2/repository/org/bouncycastle/bc-fips/1.0.2.1/bc-fips-1.0.2.1.jar -providerclass org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider +openssl x509 -req -CA ca-cert -CAkey ca-key -in cert-file -out cert-signed -days 3000 -CAcreateserial -passin pass:password +keytool -keystore server-keystore.jks -storetype BCFKS -alias CARoot -import -file ca-cert -storepass password -providerpath /home/pablojosegonzalezgranados/.m2/repository/org/bouncycastle/bc-fips/1.0.2.1/bc-fips-1.0.2.1.jar -providerclass org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider +cat ca-cert cert-signed > cert +keytool -keystore server-keystore.jks -storetype BCFKS -storepass password -alias localhost -import -file cert -providerpath /home/pablojosegonzalezgranados/.m2/repository/org/bouncycastle/bc-fips/1.0.2.1/bc-fips-1.0.2.1.jar -providerclass org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider +``` \ No newline at end of file diff --git a/security/bouncycastle-fips/pom.xml b/security/bouncycastle-fips/pom.xml index 69eace014a..2e569846b0 100644 --- a/security/bouncycastle-fips/pom.xml +++ b/security/bouncycastle-fips/pom.xml @@ -23,5 +23,9 @@ org.bouncycastle bc-fips + + io.smallrye.reactive + smallrye-mutiny-vertx-web-client + diff --git a/security/bouncycastle-fips/src/main/resources/server-keystore.jks b/security/bouncycastle-fips/src/main/resources/server-keystore.jks index a39b06f6aa..2ae1850729 100644 Binary files a/security/bouncycastle-fips/src/main/resources/server-keystore.jks and b/security/bouncycastle-fips/src/main/resources/server-keystore.jks differ diff --git a/security/bouncycastle-fips/src/main/resources/server-truststore.jks b/security/bouncycastle-fips/src/main/resources/server-truststore.jks index 79baa9f41e..00eefefe0d 100644 Binary files a/security/bouncycastle-fips/src/main/resources/server-truststore.jks and b/security/bouncycastle-fips/src/main/resources/server-truststore.jks differ diff --git a/security/bouncycastle-fips/src/test/java/io/quarkus/ts/security/bouncycastle/fips/BouncyCastleFipsJsseIT.java b/security/bouncycastle-fips/src/test/java/io/quarkus/ts/security/bouncycastle/fips/BouncyCastleFipsJsseIT.java index 6eddd3e4e0..fb0b88272f 100644 --- a/security/bouncycastle-fips/src/test/java/io/quarkus/ts/security/bouncycastle/fips/BouncyCastleFipsJsseIT.java +++ b/security/bouncycastle-fips/src/test/java/io/quarkus/ts/security/bouncycastle/fips/BouncyCastleFipsJsseIT.java @@ -1,36 +1,98 @@ package io.quarkus.ts.security.bouncycastle.fips; -import static io.restassured.RestAssured.given; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; +import java.security.Security; +import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider; import org.junit.jupiter.api.Test; +import io.quarkus.runtime.util.ClassPathUtils; +import io.quarkus.test.bootstrap.Protocol; import io.quarkus.test.bootstrap.RestService; import io.quarkus.test.scenarios.QuarkusScenario; import io.quarkus.test.services.Dependency; import io.quarkus.test.services.QuarkusApplication; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.KeyStoreOptions; +import io.vertx.ext.web.client.WebClientOptions; +import io.vertx.mutiny.ext.web.client.WebClient; @QuarkusScenario public class BouncyCastleFipsJsseIT { private static final String PASSWORD = "password"; - @QuarkusApplication(dependencies = { + @QuarkusApplication(ssl = true, dependencies = { @Dependency(groupId = "org.bouncycastle", artifactId = "bctls-fips", version = "${bouncycastle.bctls-fips.version}") }) private static final RestService app = new RestService().withProperties("jsse.properties"); @Test - public void verifyBouncyCastleFipsAndJsseProviderAvailability() { - given() - .keyStore(Paths.get("client-keystore.jks").toFile(), PASSWORD) - .trustStore(Paths.get("client-truststore.jks").toFile(), PASSWORD) - .when() - .get("/api/listProviders") - .then() - .statusCode(200) - .body(containsString("BCFIPS,BCJSSE")); + public void verifyBouncyCastleFipsAndJsseProviderAvailability() throws Exception { + Security.insertProviderAt(new BouncyCastleFipsProvider(), 1); + WebClient webClient = WebClient.create(new io.vertx.mutiny.core.Vertx(Vertx.vertx()), createWebClientOptions()); + String endpoint = app.getHost(Protocol.HTTPS) + ":" + app.getPort(Protocol.HTTPS) + "/api/listProviders"; + String body = webClient + .getAbs(endpoint) + .sendAndAwait().bodyAsString(); + + assertThat(body, containsString("BCFIPS,BCJSSE")); + } + + private WebClientOptions createWebClientOptions() throws Exception { + WebClientOptions webClientOptions = new WebClientOptions(); + + byte[] keyStoreData = getFileContent(Paths.get("src", "test", "resources", "client-keystore.jks")); + KeyStoreOptions keyStoreOptions = new KeyStoreOptions() + .setPassword(PASSWORD) + .setValue(Buffer.buffer(keyStoreData)) + .setType("BCFKS") + .setProvider("BCFIPS"); + webClientOptions.setKeyCertOptions(keyStoreOptions); + + byte[] trustStoreData = getFileContent(Paths.get("src", "test", "resources", "client-truststore.jks")); + KeyStoreOptions trustStoreOptions = new KeyStoreOptions() + .setPassword(PASSWORD) + .setValue(Buffer.buffer(trustStoreData)) + .setType("BCFKS") + .setProvider("BCFIPS"); + webClientOptions.setVerifyHost(false).setTrustAll(true).setTrustOptions(trustStoreOptions); + + return webClientOptions; + } + + private static byte[] getFileContent(Path path) throws IOException { + byte[] data; + final InputStream resource = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(ClassPathUtils.toResourceName(path)); + if (resource != null) { + try (InputStream is = resource) { + data = doRead(is); + } + } else { + try (InputStream is = Files.newInputStream(path)) { + data = doRead(is); + } + } + return data; + } + + private static byte[] doRead(InputStream is) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int r; + while ((r = is.read(buf)) > 0) { + out.write(buf, 0, r); + } + return out.toByteArray(); } } diff --git a/security/bouncycastle-fips/src/test/resources/client-keystore.jks b/security/bouncycastle-fips/src/test/resources/client-keystore.jks index a39b06f6aa..2ae1850729 100644 Binary files a/security/bouncycastle-fips/src/test/resources/client-keystore.jks and b/security/bouncycastle-fips/src/test/resources/client-keystore.jks differ diff --git a/security/bouncycastle-fips/src/test/resources/client-truststore.jks b/security/bouncycastle-fips/src/test/resources/client-truststore.jks index 79baa9f41e..00eefefe0d 100644 Binary files a/security/bouncycastle-fips/src/test/resources/client-truststore.jks and b/security/bouncycastle-fips/src/test/resources/client-truststore.jks differ diff --git a/security/bouncycastle-fips/src/test/resources/jsse.properties b/security/bouncycastle-fips/src/test/resources/jsse.properties index ca5d152bf2..e088498ac6 100644 --- a/security/bouncycastle-fips/src/test/resources/jsse.properties +++ b/security/bouncycastle-fips/src/test/resources/jsse.properties @@ -10,4 +10,8 @@ quarkus.http.ssl.certificate.trust-store-file=server-truststore.jks quarkus.http.ssl.certificate.trust-store-password=password quarkus.http.ssl.certificate.trust-store-file-type=BCFKS quarkus.http.ssl.certificate.trust-store-provider=BCFIPS -quarkus.native.additional-build-args=-H:IncludeResources=.*\\.jks \ No newline at end of file +#quarkus.native.additional-build-args=-H:IncludeResources=.*\\.jks + +quarkus.log.category."org.bouncycastle.jsse".min-level=TRACE +quarkus.log.category."org.bouncycastle.jsse".level=TRACE +quarkus.log.file.enable=true