Skip to content

Commit

Permalink
Extracion of crypto-pgp and making crypto work on FIPS
Browse files Browse the repository at this point in the history
  • Loading branch information
JiriOndrusek committed Jul 8, 2024
1 parent 05dc90e commit 0c1ef98
Show file tree
Hide file tree
Showing 40 changed files with 1,159 additions and 190 deletions.
13 changes: 13 additions & 0 deletions docs/modules/ROOT/examples/dataformats/pgp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Do not edit directly!
# This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page
cqArtifactId: camel-quarkus-crypto-pgp
cqArtifactIdBase: crypto-pgp
cqNativeSupported: true
cqStatus: Stable
cqDeprecated: false
cqJvmSince: 3.13.0
cqNativeSince: 3.13.0
cqCamelPartName: pgp
cqCamelPartTitle: PGP
cqCamelPartDescription: Encrypt and decrypt messages using Java Cryptographic Extension (JCE) and PGP.
cqExtensionPageTitle: PGP
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@
*** xref:reference/extensions/opentelemetry.adoc[OpenTelemetry]
*** xref:reference/extensions/optaplanner.adoc[OptaPlanner]
*** xref:reference/extensions/pdf.adoc[PDF]
*** xref:reference/extensions/crypto-pgp.adoc[PGP]
*** xref:reference/extensions/paho.adoc[Paho]
*** xref:reference/extensions/paho-mqtt5.adoc[Paho MQTT5]
*** xref:reference/extensions/pinecone.adoc[Pinecone]
Expand Down
55 changes: 55 additions & 0 deletions docs/modules/ROOT/pages/reference/extensions/crypto-pgp.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Do not edit directly!
// This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page
[id="extensions-crypto-pgp"]
= PGP
:linkattrs:
:cq-artifact-id: camel-quarkus-crypto-pgp
:cq-native-supported: true
:cq-status: Stable
:cq-status-deprecation: Stable
:cq-description: Encrypt and decrypt messages using Bouncy Castle OpenPGP API.
:cq-deprecated: false
:cq-jvm-since: 3.13.0
:cq-native-since: 3.13.0

ifeval::[{doc-show-badges} == true]
[.badges]
[.badge-key]##JVM since##[.badge-supported]##3.13.0## [.badge-key]##Native since##[.badge-supported]##3.13.0##
endif::[]

Encrypt and decrypt messages using Bouncy Castle OpenPGP API.

[id="extensions-crypto-pgp-whats-inside"]
== What's inside

* xref:{cq-camel-components}:dataformats:pgp-dataformat.adoc[PGP data format]

Please refer to the above link for usage and configuration details.

[id="extensions-crypto-pgp-maven-coordinates"]
== Maven coordinates

https://{link-quarkus-code-generator}/?extension-search=camel-quarkus-crypto-pgp[Create a new project with this extension on {link-quarkus-code-generator}, window="_blank"]

Or add the coordinates to your existing project:

[source,xml]
----
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-crypto-pgp</artifactId>
</dependency>
----
ifeval::[{doc-show-user-guide-link} == true]
Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
endif::[]

[id="extensions-crypto-pgp-camel-quarkus-limitations"]
== Camel Quarkus limitations

[id="extensions-crypto-pgp-limitations-fips"]
=== FIPS

It may not be possible to run `crypto` and `crypto-pgp` extensions together on FIPS enabled system.
For example if `crypto` uses `BCFIPS` provider and `crypto-pgp` uses `BC` provider, it is not possible to have both providers on one classpath.

45 changes: 45 additions & 0 deletions docs/modules/ROOT/pages/reference/extensions/crypto.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,51 @@ ifeval::[{doc-show-user-guide-link} == true]
Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
endif::[]

[id="extensions-crypto-usage"]
== Usage
[id="extensions-crypto-usage-fips"]
=== FIPS

When running `crypto` extension on FIPS enabled system the BC-FIPS has to be utilized.

* Exclude all `bc*` dependencies. Example:
```
<exclusions>
<exclusion>
<artifactId>*</artifactId>
<groupId>org.bouncycastle</groupId>
</exclusion>
</exclusions>
```

* Add dependency wih BouncyCastle implementation for FIPS systems. For example
```
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bc-fips</artifactId>
</dependency>
```




[id="extensions-crypto-camel-quarkus-limitations"]
== Camel Quarkus limitations

[id="extensions-crypto-limitations-security-provider"]
=== Security Provider

Extension requires BouncyCastle provider and also utilizes the quarkus security extension (see https://quarkus.io/guides/security-customization#registering-security-providers[security providers registration doc])
If there is no `BC*` provider registered (by `quarkus.security.security-providers` property).
The `BC` provider is registered.

[id="extensions-crypto-limitations-fips"]
=== FIPS

It may not be possible to run `crypto` and `crypto-pgp` extensions together on FIPS enabled system.
For example if `crypto` uses `BCFIPS` provider and `crypto-pgp` uses `BC` provider, it is not possible to have both providers on one classpath.


[id="extensions-crypto-ssl-in-native-mode"]
== SSL in native mode

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,46 @@
*/
package org.apache.camel.quarkus.support.bouncycastle.deployment;

import java.util.Collections;
import java.util.List;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;

import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.IndexDependencyBuildItem;
import io.quarkus.deployment.builditem.ExcludeDependencyBuildItem;
import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem;
import io.quarkus.security.deployment.BouncyCastleProviderBuildItem;
import io.quarkus.security.deployment.SecurityConfig;
import org.apache.camel.quarkus.support.bouncycastle.BouncyCastleRecorder;
import org.jboss.jandex.IndexView;

public class BouncyCastleSupportProcessor {

@BuildStep
SecurityConfig securityConfig;

@BuildStep(onlyIfNot = BcProviderConfigured.class) //register BC only if no BC* provider is registered
void produceBouncyCastleProvider(BuildProducer<BouncyCastleProviderBuildItem> bouncyCastleProvider) {
//register BC if there is no BC or BCFIPS provider in securityConfiguration
bouncyCastleProvider.produce(new BouncyCastleProviderBuildItem());
}

@BuildStep
@BuildStep()
@Record(ExecutionTime.STATIC_INIT)
public void registerBouncyCastleProvider(List<CipherTransformationBuildItem> cipherTransformations,
BouncyCastleRecorder recorder,
ShutdownContextBuildItem shutdownContextBuildItem) {
List<String> allCipherTransformations = cipherTransformations.stream()
.flatMap(c -> c.getCipherTransformations().stream()).collect(Collectors.toList());
recorder.registerBouncyCastleProvider(allCipherTransformations, shutdownContextBuildItem);
}

@BuildStep()
ReflectiveClassBuildItem registerForReflection(CombinedIndexBuildItem combinedIndex) {
IndexView index = combinedIndex.getIndex();

Expand All @@ -54,23 +70,45 @@ ReflectiveClassBuildItem registerForReflection(CombinedIndexBuildItem combinedIn
return ReflectiveClassBuildItem.builder(dtos).build();
}

@BuildStep
IndexDependencyBuildItem registerBCDependencyForIndex() {
return new IndexDependencyBuildItem("org.bouncycastle", "bcprov-jdk18on");
}

@BuildStep
@BuildStep(onlyIfNot = FipsProviderConfigured.class)
void secureRandomConfiguration(BuildProducer<RuntimeReinitializedClassBuildItem> reinitialized) {
reinitialized.produce(new RuntimeReinitializedClassBuildItem("java.security.SecureRandom"));
}

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
public void registerBouncyCastleProvider(List<CipherTransformationBuildItem> cipherTransformations,
BouncyCastleRecorder recorder,
ShutdownContextBuildItem shutdownContextBuildItem) {
List<String> allCipherTransformations = cipherTransformations.stream()
.flatMap(c -> c.getCipherTransformations().stream()).collect(Collectors.toList());
recorder.registerBouncyCastleProvider(allCipherTransformations, shutdownContextBuildItem);
@BuildStep(onlyIf = FipsProviderConfigured.class)
void excludeBc(BuildProducer<ExcludeDependencyBuildItem> excludeDependencies) {
//exclude BC in FIPS environment
excludeDependencies.produce(new ExcludeDependencyBuildItem("org.bouncycastle", "bcpkix-jdk18on"));
excludeDependencies.produce(new ExcludeDependencyBuildItem("org.bouncycastle", "bcbcprov-jdk18on"));
excludeDependencies.produce(new ExcludeDependencyBuildItem("org.bouncycastle", "bcutil-jdk18on"));
}

/**
* Indicates whether FIPS provider is registered via quarkus.security.
*/
static final class FipsProviderConfigured implements BooleanSupplier {
SecurityConfig securityConfig;

@Override
public boolean getAsBoolean() {
return securityConfig.securityProviders().orElse(Collections.emptySet()).stream()
.anyMatch(p -> p.toLowerCase().contains("fips"));

}
}

/**
* Indicates whether BC* provider is registered via quarkus.security.
*/
static final class BcProviderConfigured implements BooleanSupplier {
SecurityConfig securityConfig;

@Override
public boolean getAsBoolean() {
return securityConfig.securityProviders().orElse(Collections.emptySet()).stream()
.filter(p -> p.toLowerCase().startsWith("bc")).findAny().isPresent();

}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import io.quarkus.runtime.ShutdownContext;
import io.quarkus.runtime.annotations.Recorder;
import io.quarkus.security.runtime.SecurityProviderUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jboss.logging.Logger;

@Recorder
Expand All @@ -35,11 +34,28 @@ public class BouncyCastleRecorder {

public void registerBouncyCastleProvider(List<String> cipherTransformations, ShutdownContext shutdownContext) {
Provider provider = Security.getProvider(SecurityProviderUtils.BOUNCYCASTLE_PROVIDER_NAME);
if (provider == null) {
provider = Security.getProvider(SecurityProviderUtils.BOUNCYCASTLE_FIPS_PROVIDER_NAME);
}
if (provider == null) {
// TODO: Fix BuildStep execution order so that this is not required
// https://github.com/apache/camel-quarkus/issues/3472
provider = new BouncyCastleProvider();
Security.addProvider(provider);
try {
provider = (Provider) Thread.currentThread().getContextClassLoader()
.loadClass(SecurityProviderUtils.BOUNCYCASTLE_PROVIDER_CLASS_NAME).getConstructor().newInstance();
Security.addProvider(provider);
} catch (Exception e) {
try {
//try to load BCFIPS
provider = (Provider) Thread.currentThread().getContextClassLoader()
.loadClass(SecurityProviderUtils.BOUNCYCASTLE_FIPS_PROVIDER_CLASS_NAME).getConstructor()
.newInstance();
Security.addProvider(provider);
} catch (Exception e2) {
throw new RuntimeException("Neither BC nor BCFIPS provider can be registered. \nBC: " + e.getMessage()
+ "\nBCFIPS " + e2.getMessage());
}
}
}

// Make it explicit to the static analysis that below security services should be registered as they are reachable at runtime
Expand Down
67 changes: 67 additions & 0 deletions extensions/crypto-pgp/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-crypto-pgp-parent</artifactId>
<version>3.13.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>camel-quarkus-crypto-pgp-deployment</artifactId>
<name>Camel Quarkus :: PGP :: Deployment</name>

<dependencies>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-crypto-pgp</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-support-bouncycastle-deployment</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${quarkus.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>

</project>
Loading

0 comments on commit 0c1ef98

Please sign in to comment.