This is an automated email from the ASF dual-hosted git repository.
hanicz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new df175163e KNOX-3315: Adds BCFKS as an option cert export (#1221)
df175163e is described below
commit df175163e76403ec984ee9740429c9e4fd9222c8
Author: hanicz <[email protected]>
AuthorDate: Wed May 6 13:51:16 2026 +0200
KNOX-3315: Adds BCFKS as an option cert export (#1221)
* KNOX-3315: Adds BCFKS as an option cert export
* KNOX-3315: Address review comments
---
.../java/org/apache/knox/gateway/util/KnoxCLI.java | 7 +++--
.../service/metadata/KnoxMetadataResource.java | 15 ++++++++++
.../knox/gateway/util/X509CertificateUtil.java | 10 +++++++
.../knox/gateway/util/X509CertificateUtilTest.java | 35 ++++++++++++++++++++++
4 files changed, 65 insertions(+), 2 deletions(-)
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
index a64b743ff..141f2e816 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
@@ -756,12 +756,12 @@ public class KnoxCLI extends Configured implements Tool {
public class CertExportCommand extends Command {
- public static final String USAGE = "export-cert [--type
PEM|JKS|JCEKS|PKCS12]";
+ public static final String USAGE = "export-cert [--type
PEM|JKS|JCEKS|PKCS12|BCFKS]";
public static final String DESC = "The export-cert command exports the
public certificate\n" +
"from the a gateway.jks keystore with
the alias of gateway-identity.\n" +
"It will be exported to
`{GATEWAY_HOME}/data/security/keystores/` with a name of
`gateway-client-trust.<type>`" +
"Using the --type option you can specify
which keystore type you need (default: PEM)\n" +
- "NOTE: The password for the JKS, JCEKS
and PKCS12 types is `changeit`.\n" +
+ "NOTE: The password for the JKS, JCEKS,
PKCS12 and BCFKS types is `changeit`.\n" +
"It can be changed using: `keytool
-storepasswd -storetype <type> -keystore gateway-client-trust.<type>`";
private GatewayConfig getGatewayConfig() {
@@ -808,6 +808,9 @@ public class KnoxCLI extends Configured implements Tool {
} else if ("PKCS12".equalsIgnoreCase(type)) {
X509CertificateUtil.writeCertificateToPkcs12(cert, new
File(keyStoreDir + "gateway-client-trust.pkcs12"));
out.println("Certificate gateway-identity has been successfully
exported to: " + keyStoreDir + "gateway-client-trust.pkcs12");
+ } else if ("BCFKS".equalsIgnoreCase(type)) {
+ X509CertificateUtil.writeCertificateToBcfks(cert, new
File(keyStoreDir + "gateway-client-trust.bcfks"));
+ out.println("Certificate gateway-identity has been successfully
exported to: " + keyStoreDir + "gateway-client-trust.bcfks");
} else {
out.println("Invalid type for export file provided. Export has not
been done. Please use: [PEM|JKS|JCEKS|PKCS12] default value is PEM.");
}
diff --git
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
index 75eb88baa..ba77c0e5d 100644
---
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
+++
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
@@ -88,6 +88,7 @@ public class KnoxMetadataResource {
private Set<String> pinnedTopologies;
private java.nio.file.Path pemFilePath;
private java.nio.file.Path jksFilePath;
+ private java.nio.file.Path bcfksFilePath;
@Context
private HttpServletRequest request;
@@ -147,6 +148,9 @@ public class KnoxMetadataResource {
} else if ("jks".equals(certType)) {
generateCertificateJks(certificateChain, config);
return generateSuccessFileDownloadResponse(jksFilePath);
+ } else if ("bcfks".equals(certType)) {
+ generateCertificateBcfks(certificateChain, config);
+ return generateSuccessFileDownloadResponse(bcfksFilePath);
} else {
return generateFailureFileDownloadResponse(Status.BAD_REQUEST,
"Invalid certification type provided!");
}
@@ -208,6 +212,17 @@ public class KnoxMetadataResource {
}
}
+ private void generateCertificateBcfks(Certificate[] certificateChain,
GatewayConfig gatewayConfig) {
+ try {
+ if (bcfksFilePath == null || !bcfksFilePath.toFile().exists()) {
+ bcfksFilePath = Paths.get(gatewayConfig.getGatewaySecurityDir(),
"gateway-client-trust.bcfks");
+ X509CertificateUtil.writeCertificatesToBcfks(certificateChain,
bcfksFilePath.toFile(), null);
+ }
+ } catch (IOException | KeyStoreException | NoSuchAlgorithmException |
CertificateException e) {
+ LOG.failedToGeneratePublicCert("BCFKS", e.getMessage(), e);
+ }
+ }
+
private String getBaseGatewayUrl(GatewayConfig config) {
return request.getRequestURL().substring(0,
request.getRequestURL().length() - request.getRequestURI().length()) + "/" +
config.getGatewayPath();
}
diff --git
a/gateway-util-common/src/main/java/org/apache/knox/gateway/util/X509CertificateUtil.java
b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/X509CertificateUtil.java
index 8d0574d20..3bf07d8ca 100644
---
a/gateway-util-common/src/main/java/org/apache/knox/gateway/util/X509CertificateUtil.java
+++
b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/X509CertificateUtil.java
@@ -215,6 +215,16 @@ public class X509CertificateUtil {
writeCertificateToKeyStore(cert, file, "pkcs12");
}
+ public static void writeCertificateToBcfks(Certificate cert, final File file)
+ throws IOException, KeyStoreException, NoSuchAlgorithmException,
CertificateException {
+ writeCertificateToKeyStore(cert, file, "bcfks");
+ }
+
+ public static void writeCertificatesToBcfks(Certificate[] certs, final File
file, String keystorePassword)
+ throws IOException, KeyStoreException, NoSuchAlgorithmException,
CertificateException {
+ writeCertificatesToKeyStore(certs, file, "bcfks", keystorePassword);
+ }
+
/**
* Tests the X509 certificate to see if it was self-signed.
* <p>
diff --git
a/gateway-util-common/src/test/java/org/apache/knox/gateway/util/X509CertificateUtilTest.java
b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/X509CertificateUtilTest.java
index 06365f575..506bf3412 100644
---
a/gateway-util-common/src/test/java/org/apache/knox/gateway/util/X509CertificateUtilTest.java
+++
b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/X509CertificateUtilTest.java
@@ -17,19 +17,25 @@
*/
package org.apache.knox.gateway.util;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Assert;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
+import java.io.File;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
@@ -39,6 +45,35 @@ import java.util.concurrent.TimeUnit;
public class X509CertificateUtilTest {
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Test
+ public void testWriteCertificatesToKeyStoreBCFKS() throws Exception {
+ Security.addProvider(new BouncyCastleProvider());
+ try {
+ // 1. Generate a self-signed certificate
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(2048);
+ KeyPair keyPair = keyPairGenerator.generateKeyPair();
+ X509Certificate cert =
X509CertificateUtil.generateCertificate("CN=localhost", keyPair, 30,
"SHA256withRSA");
+
+ // 2. Write it to a BCFKS keystore
+ File bcfksFile = temporaryFolder.newFile("test.bcfks");
+ X509CertificateUtil.writeCertificatesToBcfks(new Certificate[]{cert},
bcfksFile, "password");
+
+ // 3. Verify the keystore
+ KeyStore keyStore = KeyStore.getInstance("BCFKS");
+ keyStore.load(java.nio.file.Files.newInputStream(bcfksFile.toPath()),
"password".toCharArray());
+ Assert.assertTrue(keyStore.containsAlias("gateway-identity1"));
+ Certificate loadedCert = keyStore.getCertificate("gateway-identity1");
+ Assert.assertNotNull(loadedCert);
+ Assert.assertEquals(cert, loadedCert);
+ } finally {
+ Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+ }
+ }
+
@Test
public void testFetchPublicCertsFromServer() throws Exception {
// 1. Generate a self-signed certificate