From 61dac86bceb9d727e1bd707982c41ab9467c6d5a Mon Sep 17 00:00:00 2001
From: Maxim Thomas <maxim.thomas@gmail.com>
Date: Mon, 03 Nov 2025 06:30:05 +0000
Subject: [PATCH] Switch from sun.security.x509 to Bouncy Castle API (#560)
---
opendj-server-legacy/src/test/java/org/opends/server/replication/service/ReplicationDomainTest.java | 37 ++
opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java | 4
opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedTrustManagerProvider.java | 4
opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java | 8
opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java | 13
pom.xml | 21 +
opendj-server-legacy/pom.xml | 6
opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java | 285 ++++++---------------
opendj-core/src/main/java/com/forgerock/opendj/util/FipsStaticUtils.java | 6
opendj-server-legacy/src/test/java/org/opends/server/util/TestTimer.java | 6
opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java | 2
opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java | 24 +
opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java | 94 ++++++-
opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java | 2
opendj-server-legacy/src/test/java/org/opends/server/replication/SchemaReplicationTest.java | 2
opendj-server-legacy/src/test/java/org/opends/server/DirectoryServerTestCase.java | 3
opendj-server-legacy/src/test/java/org/opends/server/replication/service/FakeReplicationDomain.java | 7
opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java | 56 +++
opendj-server-legacy/src/test/java/org/opends/server/TestListener.java | 28 +
opendj-server-legacy/src/main/java/org/opends/server/types/HostPort.java | 14 +
opendj-server-legacy/src/main/java/org/opends/server/tools/InstallDS.java | 5
opendj-core/src/main/java/org/forgerock/opendj/ldap/TrustManagers.java | 4
.github/workflows/build.yml | 56 ++++
opendj-server-legacy/src/main/java/org/opends/server/tools/SSLConnectionFactory.java | 2
opendj-server-legacy/resource/bin/_script-util.bat | 4
opendj-server-legacy/resource/bin/_script-util.sh | 2
opendj-server-legacy/src/messages/org/opends/messages/utility.properties | 10
opendj-core/pom.xml | 28 +-
28 files changed, 454 insertions(+), 279 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b8570f0..8e0f3df 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -70,6 +70,62 @@
opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "ou=people,dc=example2,dc=com" --searchScope sub "(uid=user.*)" dn | grep ^dn: | wc -l | grep -q 10000
opendj-server-legacy/target/package/opendj/bin/stop-ds
rm -rf opendj-server-legacy/target/package/opendj/{config,db,changelogDb,logs}
+
+ - name: Test on Unix FIPS
+ if: runner.os != 'Windows'
+ run: |
+ export OPENDJ_JAVA_ARGS="-server -Xmx512m"
+ echo password > /tmp/opendj.keystore.pin
+
+ keytool -genkey -alias server-cert -keyalg rsa \
+ -dname "CN=example.com,O=OpenDJ RSA Self-Signed Certificate" \
+ -keystore /tmp/opendj.bcfks -storetype BCFKS -validity 3650 -providername BCFIPS \
+ -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
+ -providerpath ./opendj-server-legacy/target/package/opendj/lib/org.bouncycastle.bc-fips.jar:./opendj-server-legacy/target/package/opendj/lib/org.bouncycastle.bcpkix-fips.jar \
+ -keypass:file /tmp/opendj.keystore.pin -storepass:file /tmp/opendj.keystore.pin -keysize 2048 -sigalg SHA256WITHRSA
+
+ keytool -selfcert -alias server-cert -keystore /tmp/opendj.bcfks \
+ -storetype BCFKS -validity 3650 -providername BCFIPS \
+ -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
+ -providerpath ./opendj-server-legacy/target/package/opendj/lib/org.bouncycastle.bc-fips.jar:./opendj-server-legacy/target/package/opendj/lib/org.bouncycastle.bcpkix-fips.jar \
+ -storepass:file /tmp/opendj.keystore.pin
+
+ keytool -genkey -alias admin-cert -keyalg rsa \
+ -dname "CN=example.com,O=Administration Connector RSA Self-Signed Certificate" \
+ -keystore /tmp/opendj.bcfks -storetype BCFKS -validity 3650 -providername BCFIPS \
+ -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
+ -providerpath ./opendj-server-legacy/target/package/opendj/lib/org.bouncycastle.bc-fips.jar:./opendj-server-legacy/target/package/opendj/lib/org.bouncycastle.bcpkix-fips.jar \
+ -keypass:file /tmp/opendj.keystore.pin -storepass:file /tmp/opendj.keystore.pin -keysize 2048 -sigalg SHA256WITHRSA
+
+ keytool -selfcert -alias admin-cert -keystore /tmp/opendj.bcfks \
+ -storetype BCFKS -validity 3650 -providername BCFIPS \
+ -provider org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider \
+ -providerpath ./opendj-server-legacy/target/package/opendj/lib/org.bouncycastle.bc-fips.jar:./opendj-server-legacy/target/package/opendj/lib/org.bouncycastle.bcpkix-fips.jar \
+ -storepass:file /tmp/opendj.keystore.pin
+
+ echo "useBcfksKeystore=/tmp/opendj.bcfks
+ keyStorePasswordFile=/tmp/opendj.keystore.pin" > /tmp/opendj-setup.properties.bcfks
+
+ opendj-server-legacy/target/package/opendj/setup -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 \
+ --enableStartTLS --certNickname admin-cert --rootUserDN "cn=Directory Manager" --rootUserPassword password \
+ --baseDN dc=example,dc=com --sampleData 5000 --cli --acceptLicense --no-prompt \
+ --propertiesFilePath /tmp/opendj-setup.properties.bcfks --doNotStart
+
+ opendj-server-legacy/target/package/opendj/bin/start-ds
+
+ opendj-server-legacy/target/package/opendj/bin/status --bindDN "cn=Directory Manager" --bindPassword password --trustAll
+ opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1
+ opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "ou=people,dc=example,dc=com" --searchScope sub "(uid=user.*)" dn | grep ^dn: | wc -l | grep -q 5000
+ opendj-server-legacy/target/package/opendj/bin/dsconfig create-backend --hostname localhost --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --backend-name=example2 --type je --set=base-dn:dc=example2,dc=com --set=enabled:true --no-prompt --trustAll
+ opendj-server-legacy/target/package/opendj/bin/makeldif -o /tmp/test.ldif -c suffix=dc=example2,dc=com opendj-server-legacy/target/package/opendj/config/MakeLDIF/example.template
+ opendj-server-legacy/target/package/opendj/bin/stop-ds
+ opendj-server-legacy/target/package/opendj/bin/import-ldif --offline --ldifFile /tmp/test.ldif --backendID=example2
+ opendj-server-legacy/target/package/opendj/bin/rebuild-index --offline --bindDN "cn=Directory Manager" --bindPassword password --baseDN "dc=example2,dc=com" --rebuildAll
+ opendj-server-legacy/target/package/opendj/bin/start-ds
+ opendj-server-legacy/target/package/opendj/bin/rebuild-index --bindDN "cn=Directory Manager" --bindPassword password --baseDN "dc=example2,dc=com" --rebuildAll --trustAll
+ opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "ou=people,dc=example2,dc=com" --searchScope sub "(uid=user.*)" dn | grep ^dn: | wc -l | grep -q 10000
+ opendj-server-legacy/target/package/opendj/bin/stop-ds
+ rm -rf opendj-server-legacy/target/package/opendj/{config,db,changelogDb,logs}
- name: Test LDAP in Cassandra
if: runner.os == 'Linux'
run: |
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java
index 248fc6d..056ea7c 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java
@@ -727,9 +727,9 @@
if (isFips) {
keystore.load(null, keyStorePIN);
} else {
- try (final FileInputStream fos = new FileInputStream(keyStoreFile)) {
- keystore.load(fos, keyStorePIN);
- }
+ try (final FileInputStream fos = new FileInputStream(keyStoreFile)) {
+ keystore.load(fos, keyStorePIN);
+ }
}
if (isFips) {
@@ -852,7 +852,7 @@
}
if (isFips) {
- return TrustManagers.checkUsingPkcs11TrustStore();
+ return TrustManagers.checkUsingPkcs12TrustStore();
}
return tm;
diff --git a/opendj-core/pom.xml b/opendj-core/pom.xml
index 6d31842..b976231 100644
--- a/opendj-core/pom.xml
+++ b/opendj-core/pom.xml
@@ -92,18 +92,19 @@
<artifactId>jaxb-impl</artifactId>
</dependency>
- <!-- BC FIPS Provider libs -->
- <dependency>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bc-fips</artifactId>
- <version>${bc.fips.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bctls-fips</artifactId>
- <version>${bctls.fips.version}</version>
- </dependency>
+ <!-- BC FIPS Provider libs -->
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bc-fips</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bctls-fips</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-fips</artifactId>
+ </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@@ -113,8 +114,7 @@
<properties>
- <bc.fips.version>2.1.1</bc.fips.version>
- <bctls.fips.version>2.1.20</bctls.fips.version>
+
<opendj.osgi.import.additional>
com.sun.security.auth*;resolution:=optional
diff --git a/opendj-core/src/main/java/com/forgerock/opendj/util/FipsStaticUtils.java b/opendj-core/src/main/java/com/forgerock/opendj/util/FipsStaticUtils.java
index e7daede..7f2758e 100644
--- a/opendj-core/src/main/java/com/forgerock/opendj/util/FipsStaticUtils.java
+++ b/opendj-core/src/main/java/com/forgerock/opendj/util/FipsStaticUtils.java
@@ -21,7 +21,11 @@
private static final String BC_FIPS_PROVIDER_CLASS_NAME = "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider";
public static void registerBcProvider() {
- if (!StaticUtils.isFips()) {
+ registerBcProvider(false);
+ }
+ public static void registerBcProvider(boolean force) {
+
+ if(!"true".equals(System.getProperty("org.openidentityplatform.opendj.fips.register")) && !force) {
return;
}
diff --git a/opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java b/opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java
index 16ecb55..64dbbcc 100644
--- a/opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java
+++ b/opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java
@@ -13,6 +13,8 @@
*
* Copyright 2009-2010 Sun Microsystems, Inc.
* Portions copyright 2011-2015 ForgeRock AS.
+ * Portions copyright 2017-2025 3A Systems, LLC.
+ *
*/
package com.forgerock.opendj.util;
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/TrustManagers.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/TrustManagers.java
index 803c2a0..d8624bc 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/TrustManagers.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/TrustManagers.java
@@ -522,8 +522,8 @@
throw new NoSuchAlgorithmException();
}
- public static X509TrustManager checkUsingPkcs11TrustStore() throws GeneralSecurityException, IOException {
- final KeyStore keyStore = KeyStore.getInstance("PKCS11");
+ public static X509TrustManager checkUsingPkcs12TrustStore() throws GeneralSecurityException, IOException {
+ final KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(null, null);
final TrustManagerFactory tmf =
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
index f4bcccb..f758226 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
@@ -13,6 +13,7 @@
*
* Copyright 2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2025 3A Systems LLC.
*/
package org.forgerock.opendj.ldap;
@@ -22,10 +23,18 @@
import static org.forgerock.opendj.ldap.TestCaseUtils.loopbackWithDynamicPort;
import java.io.IOException;
+import java.math.BigInteger;
import java.net.InetSocketAddress;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.Security;
import java.security.cert.X509Certificate;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -41,12 +50,20 @@
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.x500.X500Principal;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.RealmCallback;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.util.BigIntegers;
import org.forgerock.opendj.io.ASN1;
import org.forgerock.opendj.io.ASN1Reader;
import org.forgerock.opendj.io.LDAP;
@@ -77,9 +94,6 @@
import com.forgerock.opendj.ldap.controls.AccountUsabilityResponseControl;
import com.forgerock.reactive.ServerConnectionFactoryAdapter;
-import sun.security.tools.keytool.CertAndKeyGen;
-import sun.security.x509.X500Name;
-
/**
* A simple ldap server that manages 1000 entries and used for running
* testcases.
@@ -520,14 +534,40 @@
static {
final String password="keypassword";
try {
- CertAndKeyGen keyGen=new CertAndKeyGen("RSA","SHA256WithRSA",null);
- keyGen.generate(2048);
- X509Certificate[] chain=new X509Certificate[1];
- chain[0]=keyGen.getSelfCertificate(new X500Name("CN=localhost"), (long)1*3600);
+ if (Security.getProvider(BouncyCastleFipsProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleFipsProvider());
+ }
+
+ String keyType = "RSA";
+ String signatureAlgorithm = "SHA256WithRSA";
+ int keySize = 2048;
+ KeyPairGenerator generator = KeyPairGenerator.getInstance(keyType, BouncyCastleFipsProvider.PROVIDER_NAME);
+ generator.initialize(keySize);
+ KeyPair keyPair = generator.generateKeyPair();
+
+ X509Certificate[] chain = new X509Certificate[1];
+
+ BigInteger serial = BigIntegers.createRandomBigInteger(64, new SecureRandom());
+ Instant now = Instant.now();
+ Date notBeforeDate = Date.from(now);
+ Date notAfterDate = Date.from(now.plus(1, ChronoUnit.DAYS));
+
+ X500Principal subject = new X500Principal("CN=localhost");
+ JcaX509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
+ subject, serial, notBeforeDate, notAfterDate, subject, keyPair.getPublic()
+ );
+ ContentSigner signer = new JcaContentSignerBuilder(signatureAlgorithm)
+ .setProvider(BouncyCastleFipsProvider.PROVIDER_NAME)
+ .build(keyPair.getPrivate());
+ X509CertificateHolder holder = builder.build(signer);
+ JcaX509CertificateConverter converter = new JcaX509CertificateConverter()
+ .setProvider(BouncyCastleFipsProvider.PROVIDER_NAME);
+
+ chain[0] = converter.getCertificate(holder);
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(null, null);
- ks.setKeyEntry("localhost", keyGen.getPrivateKey(),password.toCharArray(), chain);
+ ks.setKeyEntry("localhost", keyPair.getPrivate(), password.toCharArray(), chain);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, password.toCharArray());
sslContext = new SSLContextBuilder().setKeyManager(kmf.getKeyManagers()[0]).getSSLContext();
diff --git a/opendj-server-legacy/pom.xml b/opendj-server-legacy/pom.xml
index d1c6d33..53824dd 100644
--- a/opendj-server-legacy/pom.xml
+++ b/opendj-server-legacy/pom.xml
@@ -321,6 +321,10 @@
<artifactId>mssql-jdbc</artifactId>
<version>12.10.0.jre8</version>
</dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-fips</artifactId>
+ </dependency>
</dependencies>
<build><finalName>${project.groupId}.${project.artifactId}</finalName>
@@ -1274,6 +1278,8 @@
<org.opends.test.suppressOutput>true</org.opends.test.suppressOutput>
<org.opends.test.pauseOnFailure>false</org.opends.test.pauseOnFailure>
<org.opends.test.copyClassesToTestPackage>false</org.opends.test.copyClassesToTestPackage>
+ <org.opends.test.timeout>600000</org.opends.test.timeout><!--15 mins-->
+ <org.opends.test.trace.pattern>(org\.opends\.server\.replication\.service\..*)|(org\.opends\.server\.replication\.GenerationIdTest)|(org\.opends\.server\.types.\HostPortTest)</org.opends.test.trace.pattern>
</systemPropertyVariables>
<argLine>@{argLine}</argLine>
<reuseForks>false</reuseForks>
diff --git a/opendj-server-legacy/resource/bin/_script-util.bat b/opendj-server-legacy/resource/bin/_script-util.bat
index 8971ccd..785a4bd 100644
--- a/opendj-server-legacy/resource/bin/_script-util.bat
+++ b/opendj-server-legacy/resource/bin/_script-util.bat
@@ -168,9 +168,9 @@
set PATH=%SystemRoot%;%PATH%
set SCRIPT_NAME_ARG=-Dorg.opends.server.scriptName=%SCRIPT_NAME%
set SET_ENVIRONMENT_VARS_DONE=true
-"%OPENDJ_JAVA_BIN%" --add-exports java.base/sun.security.x509=ALL-UNNAMED --add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --version > NUL 2>&1
+"%OPENDJ_JAVA_BIN%" --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --version > NUL 2>&1
set RESULT_CODE=%errorlevel%
-if %RESULT_CODE% == 0 set OPENDJ_JAVA_ARGS=%OPENDJ_JAVA_ARGS% --add-exports java.base/sun.security.x509=ALL-UNNAMED --add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED --add-opens java.base/jdk.internal.loader=ALL-UNNAMED
+if %RESULT_CODE% == 0 set OPENDJ_JAVA_ARGS=%OPENDJ_JAVA_ARGS% --add-opens java.base/jdk.internal.loader=ALL-UNNAMED
goto scriptBegin
:testJava
diff --git a/opendj-server-legacy/resource/bin/_script-util.sh b/opendj-server-legacy/resource/bin/_script-util.sh
index 09a8808..43b67cc 100644
--- a/opendj-server-legacy/resource/bin/_script-util.sh
+++ b/opendj-server-legacy/resource/bin/_script-util.sh
@@ -184,7 +184,7 @@
SCRIPT_NAME_ARG=-Dorg.opends.server.scriptName=${SCRIPT_NAME}
export SCRIPT_NAME_ARG
- "${OPENDJ_JAVA_BIN}" --add-exports java.base/sun.security.x509=ALL-UNNAMED --add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --version > /dev/null 2>&1
+ "${OPENDJ_JAVA_BIN}" --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --version > /dev/null 2>&1
RESULT_CODE=${?}
if test ${RESULT_CODE} -eq 0
then
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java
index 749b43f..0f62462 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java
@@ -32,6 +32,7 @@
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
+import com.forgerock.opendj.util.FipsStaticUtils;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageDescriptor.Arg2;
import org.forgerock.i18n.LocalizableMessageDescriptor.Arg3;
@@ -259,6 +260,9 @@
{
try
{
+ if(cfg.getKeyStoreType().equals("BCFKS")) {
+ FipsStaticUtils.registerBcProvider(true);
+ }
KeyStore.getInstance(cfg.getKeyStoreType());
return cfg.getKeyStoreType();
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedTrustManagerProvider.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedTrustManagerProvider.java
index f82d64c..32b4ad7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedTrustManagerProvider.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedTrustManagerProvider.java
@@ -16,6 +16,7 @@
*/
package org.opends.server.extensions;
+import com.forgerock.opendj.util.FipsStaticUtils;
import org.forgerock.i18n.LocalizableMessage;
import java.io.File;
import java.io.FileInputStream;
@@ -204,6 +205,9 @@
final String trustStoreType = cfg.getTrustStoreType();
if (trustStoreType != null)
{
+ if(trustStoreType.equals("BCFKS")) {
+ FipsStaticUtils.registerBcProvider(true);
+ }
try
{
KeyStore.getInstance(trustStoreType);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java
index 6e6504b..c3096b2 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java
@@ -13,6 +13,7 @@
*
* Copyright 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2023-2025 3A Systems LLC.
* Portions Copyright 2025 Wren Security.
*/
package org.opends.server.replication.service;
@@ -2665,14 +2666,16 @@
{
debugInfo("is stopping and will close the connection to RS(" + getRsServerId() + ")");
}
+ synchronized (startStopLock) {
+ if (shutdown) {
+ return;
+ }
+ }
+
+ domain.publishReplicaOfflineMsg();
synchronized (startStopLock)
{
- if (shutdown)
- {
- return;
- }
- domain.publishReplicaOfflineMsg();
shutdown = true;
setConnectedRS(ConnectedRS.stopped());
stopRSHeartBeatMonitoring();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
index 0ce56d1..9c5bed7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
@@ -13,6 +13,7 @@
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2025 3A Systems LLC.
*/
package org.opends.server.replication.service;
@@ -39,6 +40,9 @@
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -373,6 +377,11 @@
protected volatile long generationId;
/**
+ * Thread pool for export thread tasks
+ */
+ private final ExecutorService exportThreadPool = Executors.newCachedThreadPool();
+
+ /**
* Returns the {@link CSNGenerator} that will be used to
* generate {@link CSN} for this domain.
*
@@ -879,7 +888,10 @@
// Do this work in a thread to allow replay thread continue working
ExportThread exportThread = new ExportThread(
initReqMsg.getSenderID(), initReqMsg.getInitWindow());
- exportThread.start();
+ exportThreadPool.execute(() -> {
+ Thread.currentThread().setName(exportThread.getName());
+ exportThread.run();
+ });
}
}
@@ -1075,6 +1087,9 @@
This server is not the initiator of the export so there is
nothing more to do locally.
*/
+ if (logger.isTraceEnabled()) {
+ logger.trace(LocalizableMessage.raw("[IE] got exception" + getName()), de);
+ }
}
if (logger.isTraceEnabled())
@@ -3016,6 +3031,13 @@
{
broker.stop();
}
+ try {
+ exportThreadPool.shutdown();
+ boolean timedOut = exportThreadPool.awaitTermination(100, TimeUnit.SECONDS);
+ logger.info(LocalizableMessage.raw("export pool termination timed out: " + timedOut));
+ } catch (InterruptedException e) {
+ // Give up waiting.
+ }
// Stop the listener thread
if (listenerThread != null)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/InstallDS.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/InstallDS.java
index f5bf1a4..2594512 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/InstallDS.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/InstallDS.java
@@ -40,6 +40,7 @@
import java.util.LinkedList;
import java.util.List;
+import com.forgerock.opendj.util.FipsStaticUtils;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageDescriptor.Arg0;
import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1;
@@ -326,6 +327,10 @@
return InstallReturnCode.ERROR_LICENSE_NOT_ACCEPTED.getReturnCode();
}
+ if(argParser.useBcfksArg.isPresent()) {
+ FipsStaticUtils.registerBcProvider(true);
+ }
+
final UserData uData = new UserData();
InstallReturnCode fillUserDataRC;
try
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/SSLConnectionFactory.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/SSLConnectionFactory.java
index 9be9cf4..b8f72a9 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/SSLConnectionFactory.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/SSLConnectionFactory.java
@@ -122,7 +122,7 @@
trustManagers = blindTrustProvider.getTrustManagers();
} else if (trustStorePath == null) {
if (isFips()) {
- TrustManager tm = TrustManagers.checkUsingPkcs11TrustStore();
+ TrustManager tm = TrustManagers.checkUsingPkcs12TrustStore();
trustManagers = new TrustManager[] { tm };
} else {
trustManagers = PromptTrustManager.getTrustManagers();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/HostPort.java b/opendj-server-legacy/src/main/java/org/opends/server/types/HostPort.java
index 322023d..fabb3df 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/HostPort.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/types/HostPort.java
@@ -13,6 +13,7 @@
*
* Copyright 2006-2008 Sun Microsystems, Inc.
* Portions Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2025 3A Systems LLC.
*/
package org.opends.server.types;
@@ -459,6 +460,9 @@
// Get and compare ports of RS1 and RS2
if (getPort() != other.getPort())
{
+ if(logger.isTraceEnabled()) {
+ logger.trace("port and host does not match " + this + "; " + other);
+ }
return false;
}
@@ -475,6 +479,9 @@
}
else if (thisAddresses == null || otherAddresses == null)
{
+ if(logger.isTraceEnabled()) {
+ logger.trace("port and host does not match: " + this + "=" + thisAddresses + "; " + other + "=" + otherAddresses);
+ }
// One local address and one non-local.
return false;
}
@@ -490,10 +497,17 @@
}
}
}
+ if(logger.isTraceEnabled()) {
+ logger.trace("port and host does not match: " + this + "=" + thisAddresses + "; " + other + "=" + otherAddresses);
+ }
+
return false;
}
catch (UnknownHostException ex)
{
+ if(logger.isTraceEnabled()) {
+ logger.traceException(ex, "got exception when resolving hosts: " + this + " and " + other );
+ }
// Unknown RS: should not happen
return false;
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java b/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java
index 543f5f9..9289f99 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java
@@ -13,30 +13,50 @@
*
* Copyright 2009-2010 Sun Microsystems, Inc.
* Portions Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2025 Wren Security.
+ * Portions Copyright 2025 3A Systems LLC.
*/
package org.opends.server.util;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Date;
+import com.forgerock.opendj.util.StaticUtils;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.util.BigIntegers;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.util.Reject;
-import static org.opends.messages.UtilityMessages.*;
-import static org.opends.server.util.ServerConstants.CERTANDKEYGEN_PROVIDER;
+import static org.opends.messages.UtilityMessages.ERR_CERTMGR_ADD_CERT;
+import static org.opends.messages.UtilityMessages.ERR_CERTMGR_ALIAS_ALREADY_EXISTS;
+import static org.opends.messages.UtilityMessages.ERR_CERTMGR_ALIAS_INVALID;
+import static org.opends.messages.UtilityMessages.ERR_CERTMGR_CERT_REPLIES_INVALID;
+import static org.opends.messages.UtilityMessages.ERR_CERTMGR_DELETE_ALIAS;
+import static org.opends.messages.UtilityMessages.ERR_CERTMGR_GEN_SELF_SIGNED_CERT;
+import static org.opends.messages.UtilityMessages.ERR_CERTMGR_KEYSTORE_NONEXISTANT;
+import static org.opends.messages.UtilityMessages.ERR_CERTMGR_TRUSTED_CERT;
/**
* Provides a wrapper class that collects all of the JVM vendor and JDK version
@@ -45,21 +65,6 @@
public final class Platform
{
- /** Prefix that determines which security package to use. */
- private static final String pkgPrefix;
-
- /** The two security package prefixes (IBM and SUN). */
- private static final String IBM_SEC = "com.ibm.security";
- private static final String SUN_SEC = "sun.security";
-
- /** The CertAndKeyGen class is located in different packages depending on JVM environment. */
- private static final String[] CERTANDKEYGEN_PATHS = new String[] {
- "sun.security.x509.CertAndKeyGen", // Oracle/Sun/OpenJDK 6,7
- "sun.security.tools.keytool.CertAndKeyGen", // Oracle/Sun/OpenJDK 8
- "com.ibm.security.x509.CertAndKeyGen", // IBM SDK 7
- "com.ibm.security.tools.CertAndKeyGen" // IBM SDK 8
- };
-
private static final PlatformIMPL IMPL;
/** The minimum java supported version. */
@@ -67,16 +72,6 @@
static
{
- String vendor = System.getProperty("java.vendor");
-
- if (vendor.startsWith("IBM"))
- {
- pkgPrefix = IBM_SEC;
- }
- else
- {
- pkgPrefix = SUN_SEC;
- }
IMPL = new DefaultPlatformIMPL();
}
@@ -84,10 +79,10 @@
public static enum KeyType
{
/** RSA key algorithm with 2048 bits size and SHA256withRSA signing algorithm. */
- RSA("rsa", 2048, "SHA256WithRSA"),
+ RSA("RSA", 2048, "SHA256withRSA"),
- /** Elliptic Curve key algorithm with 233 bits size and SHA256withECDSA signing algorithm. */
- EC("ec", 256, "SHA256withECDSA");
+ /** Elliptic Curve key algorithm with 256 bits size and SHA256withECDSA signing algorithm. */
+ EC("EC", 256, "SHA256withECDSA");
/** Default key type used when none can be determined. */
public final static KeyType DEFAULT = RSA;
@@ -104,22 +99,6 @@
}
/**
- * Check whether this key type is supported by the current JVM.
- * @return true if this key type is supported, false otherwise.
- */
- public boolean isSupported()
- {
- try
- {
- return KeyPairGenerator.getInstance(keyAlgorithm.toUpperCase()) != null;
- }
- catch (NoSuchAlgorithmException e)
- {
- return false;
- }
- }
-
- /**
* Get a KeyType based on the alias name.
*
* @param alias
@@ -144,106 +123,13 @@
*/
private static abstract class PlatformIMPL
{
- /** Time values used in validity calculations. */
- private static final int SEC_IN_DAY = 24 * 60 * 60;
-
- /** Methods pulled from the classes. */
- private static final String GENERATE_METHOD = "generate";
- private static final String GET_PRIVATE_KEY_METHOD = "getPrivateKey";
- private static final String GET_SELFSIGNED_CERT_METHOD =
- "getSelfCertificate";
-
- /** Classes needed to manage certificates. */
- private static final Class<?> certKeyGenClass, X500NameClass;
-
- /** Constructors for each of the above classes. */
- private static Constructor<?> certKeyGenCons, X500NameCons;
-
- /** Filesystem APIs */
-
- static
- {
-
- String certAndKeyGen = getCertAndKeyGenClassName();
- if(certAndKeyGen == null)
- {
- LocalizableMessage msg = ERR_CERTMGR_CERTGEN_NOT_FOUND.get(CERTANDKEYGEN_PROVIDER);
- throw new ExceptionInInitializerError(msg.toString());
- }
-
- String X500Name = pkgPrefix + ".x509.X500Name";
- try
- {
- certKeyGenClass = Class.forName(certAndKeyGen);
- X500NameClass = Class.forName(X500Name);
- certKeyGenCons = certKeyGenClass.getConstructor(String.class,
- String.class);
- X500NameCons = X500NameClass.getConstructor(String.class);
- }
- catch (ClassNotFoundException e)
- {
- LocalizableMessage msg = ERR_CERTMGR_CLASS_NOT_FOUND.get(e.getMessage());
- throw new ExceptionInInitializerError(msg.toString());
- }
- catch (SecurityException e)
- {
- LocalizableMessage msg = ERR_CERTMGR_SECURITY.get(e.getMessage());
- throw new ExceptionInInitializerError(msg.toString());
- }
- catch (NoSuchMethodException e)
- {
- LocalizableMessage msg = ERR_CERTMGR_NO_METHOD.get(e.getMessage());
- throw new ExceptionInInitializerError(msg.toString());
- }
- }
-
- /**
- * Try to decide which CertAndKeyGen class to use.
- *
- * @return a fully qualified class name or null
- */
- private static String getCertAndKeyGenClassName() {
- String certAndKeyGen = System.getProperty(CERTANDKEYGEN_PROVIDER);
- if (certAndKeyGen != null)
- {
- return certAndKeyGen;
- }
-
- for (String className : CERTANDKEYGEN_PATHS)
- {
- if (classExists(className))
- {
- return className;
- }
- }
- return null;
- }
-
- /**
- * A quick check to see if a class can be loaded. Doesn't check if
- * it can be instantiated.
- *
- * @param className full class name to check
- * @return true if the class is found
- */
- private static boolean classExists(final String className)
- {
- try {
- Class.forName(className);
- return true;
- } catch (ClassNotFoundException | ClassCastException e) {
- return false;
- }
- }
protected PlatformIMPL()
{
}
-
-
private final void deleteAlias(KeyStore ks, String ksPath, String alias,
- char[] pwd) throws KeyStoreException
+ char[] pwd) throws KeyStoreException
{
try
{
@@ -264,10 +150,8 @@
}
}
-
-
private final void addCertificate(KeyStore ks, String ksType, String ksPath,
- String alias, char[] pwd, String certPath) throws KeyStoreException
+ String alias, char[] pwd, String certPath) throws KeyStoreException
{
try
{
@@ -284,7 +168,7 @@
throw new KeyStoreException(msg.toString());
}
else if (!ks.containsAlias(alias)
- || ks.entryInstanceOf(alias, KeyStore.TrustedCertificateEntry.class))
+ || ks.entryInstanceOf(alias, KeyStore.TrustedCertificateEntry.class))
{
try (InputStream inStream = new FileInputStream(certPath)) {
trustedCert(alias, cf, ks, inStream);
@@ -305,14 +189,17 @@
}
}
-
-
private static final KeyStore generateSelfSignedCertificate(KeyStore ks,
- String ksType, String ksPath, KeyType keyType, String alias, char[] pwd, String dn,
- int validity) throws KeyStoreException
+ String ksType, String ksPath, KeyType keyType, String alias, char[] pwd, String dn,
+ int validity) throws KeyStoreException
{
+ boolean isFips = StaticUtils.isFips();
try
{
+ if(!isFips)
+ {
+ Security.addProvider(new BouncyCastleFipsProvider());
+ }
if (ks == null)
{
ks = KeyStore.getInstance(ksType);
@@ -324,12 +211,11 @@
throw new KeyStoreException(msg.toString());
}
- final Object keypair = newKeyPair(keyType);
- final Object subject = newX500Name(dn);
- generate(keypair, keyType.keySize);
- final PrivateKey privateKey = getPrivateKey(keypair);
- final Certificate[] certificateChain = new Certificate[] {
- getSelfCertificate(keypair, subject, validity * SEC_IN_DAY)
+ KeyPair keyPair = newKeyPair(keyType);
+ PrivateKey privateKey = keyPair.getPrivate();
+ X500Name subject = new X500Name(dn);
+ Certificate[] certificateChain = new Certificate[] {
+ generateSelfCertificate(keyPair, keyType, subject, validity)
};
ks.setKeyEntry(alias, privateKey, pwd, certificateChain);
try (FileOutputStream fileOutStream = new FileOutputStream(ksPath)) {
@@ -341,34 +227,41 @@
{
throw new KeyStoreException(ERR_CERTMGR_GEN_SELF_SIGNED_CERT.get(alias, e.getMessage()).toString(), e);
}
+ finally
+ {
+ if(!isFips)
+ {
+ Security.removeProvider(BouncyCastleFipsProvider.PROVIDER_NAME);
+ }
+ }
}
- private static Object newKeyPair(KeyType keyType) throws Exception
+ private static KeyPair newKeyPair(KeyType keyType) throws Exception
{
- return certKeyGenCons.newInstance(keyType.keyAlgorithm, keyType.signatureAlgorithm);
+ KeyPairGenerator generator = KeyPairGenerator.getInstance(keyType.keyAlgorithm, BouncyCastleFipsProvider.PROVIDER_NAME);
+ generator.initialize(keyType.keySize);
+ return generator.generateKeyPair();
}
- private static Object newX500Name(String dn) throws Exception
+ private static Certificate generateSelfCertificate(KeyPair keyPair, KeyType keyType, X500Name subject, int days) throws Exception
{
- return X500NameCons.newInstance(dn);
- }
+ BigInteger serial = BigIntegers.createRandomBigInteger(64, new SecureRandom());
+ Instant now = Instant.now();
+ Date notBeforeDate = Date.from(now);
+ Date notAfterDate = Date.from(now.plus(days, ChronoUnit.DAYS));
- private static void generate(Object keypair, int keySize) throws Exception
- {
- Method certAndKeyGenGenerate = certKeyGenClass.getMethod(GENERATE_METHOD, int.class);
- certAndKeyGenGenerate.invoke(keypair, keySize);
- }
+ JcaX509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
+ subject, serial, notBeforeDate, notAfterDate, subject, keyPair.getPublic()
+ );
+ ContentSigner signer = new JcaContentSignerBuilder(keyType.signatureAlgorithm)
+ .setProvider(BouncyCastleFipsProvider.PROVIDER_NAME)
+ .build(keyPair.getPrivate());
+ X509CertificateHolder holder = builder.build(signer);
+ JcaX509CertificateConverter converter = new JcaX509CertificateConverter()
+ .setProvider(BouncyCastleFipsProvider.PROVIDER_NAME);
- private static PrivateKey getPrivateKey(Object keypair) throws Exception
- {
- Method certAndKeyGetPrivateKey = certKeyGenClass.getMethod(GET_PRIVATE_KEY_METHOD);
- return (PrivateKey) certAndKeyGetPrivateKey.invoke(keypair);
- }
- private static Certificate getSelfCertificate(Object keypair, Object subject, int days) throws Exception
- {
- Method getSelfCertificate = certKeyGenClass.getMethod(GET_SELFSIGNED_CERT_METHOD, X500NameClass, long.class);
- return (Certificate) getSelfCertificate.invoke(keypair, subject, days);
+ return converter.getCertificate(holder);
}
/**
@@ -376,7 +269,7 @@
* only if it is self-signed.
*/
private void trustedCert(String alias, CertificateFactory cf, KeyStore ks,
- InputStream in) throws KeyStoreException
+ InputStream in) throws KeyStoreException
{
try
{
@@ -398,8 +291,6 @@
}
}
-
-
/**
* Check that the issuer and subject DNs match.
*/
@@ -409,15 +300,11 @@
}
}
-
-
/** Prevent instantiation. */
private Platform()
{
}
-
-
/**
* Add the certificate in the specified path to the provided keystore;
* creating the keystore with the provided type and path if it doesn't exist.
@@ -439,13 +326,11 @@
* If an error occurred adding the certificate to the keystore.
*/
public static void addCertificate(KeyStore ks, String ksType, String ksPath,
- String alias, char[] pwd, String certPath) throws KeyStoreException
+ String alias, char[] pwd, String certPath) throws KeyStoreException
{
IMPL.addCertificate(ks, ksType, ksPath, alias, pwd, certPath);
}
-
-
/**
* Delete the specified alias from the provided keystore.
*
@@ -461,13 +346,11 @@
* If an error occurred deleting the alias.
*/
public static void deleteAlias(KeyStore ks, String ksPath, String alias,
- char[] pwd) throws KeyStoreException
+ char[] pwd) throws KeyStoreException
{
IMPL.deleteAlias(ks, ksPath, alias, pwd);
}
-
-
/**
* Generate a self-signed certificate using the specified alias, dn string and
* validity period. If the keystore does not exist, it will be created using
@@ -494,8 +377,8 @@
* If the self-signed certificate cannot be generated.
*/
public static void generateSelfSignedCertificate(KeyStore ks, String ksType,
- String ksPath, KeyType keyType, String alias, char[] pwd, String dn, int validity)
- throws KeyStoreException
+ String ksPath, KeyType keyType, String alias, char[] pwd, String dn, int validity)
+ throws KeyStoreException
{
PlatformIMPL.generateSelfSignedCertificate(ks, ksType, ksPath, keyType, alias, pwd, dn, validity);
}
@@ -507,8 +390,6 @@
{
}
-
-
/**
* Test if a platform java vendor property starts with the specified vendor
* string.
@@ -539,4 +420,4 @@
Reject.ifTrue(cpuMultiplier < 0, "Multiplier must be a positive number");
return Math.max(minimumValue, (int)(Runtime.getRuntime().availableProcessors() * cpuMultiplier));
}
-}
+}
\ No newline at end of file
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/utility.properties b/opendj-server-legacy/src/messages/org/opends/messages/utility.properties
index fcb641f..428e26b 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/utility.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/utility.properties
@@ -352,14 +352,6 @@
null
ERR_CERTMGR_VALUE_INVALID_294=The argument %s is invalid because it \
is either null, or has zero length
-ERR_CERTMGR_CLASS_NOT_FOUND_295=A security class cannot be found \
-in this JVM because of the following reason: %s
-ERR_CERTMGR_SECURITY_296=The security classes could not be \
-initialized because of the following reason: %s
-ERR_CERTMGR_NO_METHOD_297=A method needed in the security classes \
-could not be located because of the following reason: %s
-ERR_CERTMGR_CERTGEN_NOT_FOUND_298=The CertAndKeyGen security class cannot be \
-found, consider setting -D%s=
WARN_EXPORT_LDIF_SET_PERMISSION_FAILED_300=An error occurred while \
setting file permissions for the LDIF file %s: %s
ERR_LDIF_READ_ATTR_SKIP_301=Skipping entry %s because the following error \
@@ -440,4 +432,4 @@
ERR_EMBEDDED_SERVER_LDIF_MANAGEMENT_CONTEXT_342=An error occurred while attempting to \
read the configuration file '%s'
ERR_EMBEDDED_SERVER_BUILD_VERSION_343=An error occurred while attempting to \
- retrieve the build version of the directory server: '%s'
\ No newline at end of file
+ retrieve the build version of the directory server: '%s'
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/DirectoryServerTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/DirectoryServerTestCase.java
index b456dee..a1ae527 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/DirectoryServerTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/DirectoryServerTestCase.java
@@ -13,6 +13,7 @@
*
* Copyright 2006-2008 Sun Microsystems, Inc.
* Portions Copyright 2013-2015 ForgeRock AS.
+ * Portions Copyright 2025 3A Systems LLC.
*/
package org.opends.server;
@@ -48,7 +49,7 @@
TestCaseUtils.suppressOutput();
}
- @AfterSuite
+ @AfterSuite(alwaysRun = true)
public final void shutdownServer() {
TestCaseUtils.shutdownServer(LocalizableMessage.raw("The current test suite has finished."));
TestCaseUtils.unsupressOutput();
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java b/opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java
index 1e4763c..c7a835b 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java
@@ -45,11 +45,12 @@
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringReader;
+import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
+import java.lang.management.MonitorInfo;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.net.BindException;
-import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
@@ -542,6 +543,9 @@
ErrorLogger.getInstance().addLogPublisher(
(ErrorLogPublisher) getServerStartupTextErrorPublisher(ERROR_TEXT_WRITER));
+ }
+
+ public static void setupTrace() {
DebugLogger.getInstance().addPublisherIfRequired(DEBUG_TEXT_WRITER);
}
@@ -742,11 +746,20 @@
{
for (; port > 1024;)
{
+ ServerSocket res=null;
try
{
- return bindPort(port--);
+ res=bindPort(port--);
+ return res;
}
- catch (BindException e){}
+ catch (BindException e){
+ if (res!=null) {
+ try {
+ res.close();
+ } catch (IOException ex) {}
+ }
+ res=null;
+ }
}
throw new BindException("Unable to bind to a free port");
}
@@ -1927,20 +1940,71 @@
public static String generateThreadDump() {
final StringBuilder dump = new StringBuilder();
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
- final ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds(), 100);
+ ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
for (ThreadInfo threadInfo : threadInfos) {
- dump.append('"');
- dump.append(threadInfo.getThreadName());
- dump.append("\" ");
- final Thread.State state = threadInfo.getThreadState();
- dump.append("\n java.lang.Thread.State: ");
- dump.append(state);
- final StackTraceElement[] stackTraceElements = threadInfo.getStackTrace();
- for (final StackTraceElement stackTraceElement : stackTraceElements) {
- dump.append("\n at ");
- dump.append(stackTraceElement);
+ dump.append("\"" + threadInfo.getThreadName() + "\"" +
+ (threadInfo.isDaemon() ? " daemon" : "") +
+ " prio=" + threadInfo.getPriority() +
+ " Id=" + threadInfo.getThreadId() + " " +
+ threadInfo.getThreadState());
+ if (threadInfo.getLockName() != null) {
+ dump.append(" on " + threadInfo.getLockName());
+ }
+ if (threadInfo.getLockOwnerName() != null) {
+ dump.append(" owned by \"" + threadInfo.getLockOwnerName() +
+ "\" Id=" + threadInfo.getLockOwnerId());
+ }
+ if (threadInfo.isSuspended()) {
+ dump.append(" (suspended)");
+ }
+ if (threadInfo.isInNative()) {
+ dump.append(" (in native)");
+ }
+ dump.append('\n');
+ StackTraceElement[] stackTrace = threadInfo.getStackTrace();
+ int i = 0;
+ for (; i < stackTrace.length; i++) {
+ StackTraceElement ste = stackTrace[i];
+ dump.append("\tat " + ste.toString());
+ dump.append('\n');
+ if (i == 0 && threadInfo.getLockInfo() != null) {
+ Thread.State ts = threadInfo.getThreadState();
+ switch (ts) {
+ case BLOCKED:
+ dump.append("\t- blocked on " + threadInfo.getLockInfo());
+ dump.append('\n');
+ break;
+ case WAITING:
+ case TIMED_WAITING:
+ dump.append("\t- waiting on " + threadInfo.getLockInfo());
+ dump.append('\n');
+ break;
+ default:
+ }
}
- dump.append("\n\n");
+
+ for (MonitorInfo mi : threadInfo.getLockedMonitors()) {
+ if (mi.getLockedStackDepth() == i) {
+ dump.append("\t- locked " + mi);
+ dump.append('\n');
+ }
+ }
+ }
+ if (i < stackTrace.length) {
+ dump.append("\t...");
+ dump.append('\n');
+ }
+
+ LockInfo[] locks = threadInfo.getLockedSynchronizers();
+ if (locks.length > 0) {
+ dump.append("\n\tNumber of locked synchronizers = " + locks.length);
+ dump.append('\n');
+ for (LockInfo li : locks) {
+ dump.append("\t- " + li);
+ dump.append('\n');
+ }
+ }
+ dump.append('\n');
}
return dump.toString();
}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/TestListener.java b/opendj-server-legacy/src/test/java/org/opends/server/TestListener.java
index 461d615..869017b 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/TestListener.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/TestListener.java
@@ -13,7 +13,7 @@
*
* Copyright 2008 Sun Microsystems, Inc.
* Portions Copyright 2013-2016 ForgeRock AS.
- * Portions Copyright 2023 3A Systems, LLC.
+ * Portions Copyright 2023-2025 3A Systems, LLC.
*/
package org.opends.server;
@@ -155,11 +155,26 @@
@Override
public void onStart(ITestContext testContext) {
super.onStart(testContext);
-
+
if (testContext.getAllTestMethods().length>0) {
TestCaseUtils.setTestName(testContext.getAllTestMethods()[0].getInstance().getClass().getName());
}
-
+ long testTimeout = 0;
+ try {
+ testTimeout = Long.parseLong(System.getProperty("org.opends.test.timeout", "0"));
+ } catch (NumberFormatException ignored) {}
+
+ for (int i = 0; i < testContext.getAllTestMethods().length; i++) {
+ testContext.getAllTestMethods()[i].setTimeOut(testTimeout);
+ }
+ if(System.getProperty("org.opends.test.trace.pattern") != null && testContext.getAllTestMethods().length > 0) {
+ String tracePattern = System.getProperty("org.opends.test.trace.pattern");
+ if(testContext.getAllTestMethods()[0].getInstance().getClass().getName().matches(tracePattern)) {
+ System.setProperty("org.opends.server.debug.target.1", "_global:enabled");
+ TestCaseUtils.setupTrace();
+ }
+ }
+
// Delete the previous report if it's there.
new File(testContext.getOutputDirectory(), REPORT_FILE_NAME).delete();
}
@@ -179,6 +194,7 @@
originalSystemErr.println("check state: "+paths.unitRoot);
}
}
+ System.clearProperty("org.opends.server.debug.target.1");
}
@Override
@@ -335,6 +351,7 @@
@Override
public void onTestStart(ITestResult tr) {
super.onTestStart(tr);
+ originalSystemOut.println("-- Executing test: " + tr.getMethod());
enforceTestClassTypeAndAnnotations(tr);
checkForInterleavedBetweenClasses(tr);
@@ -358,6 +375,11 @@
public void onTestFailure(ITestResult tr) {
super.onTestFailure(tr);
reportTestFailed(tr);
+ printThreadDump();
+ }
+
+ private void printThreadDump() {
+ originalSystemErr.println(TestCaseUtils.generateThreadDump());
}
private void reportTestFailed(ITestResult tr)
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java
index 62426ba..b452ce0 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java
@@ -921,6 +921,8 @@
replServer3 = createReplicationServer(replServerId3, true, testCase);
connectServer1ToReplServer(replServer1);
+ Thread.sleep(2000); //wait for all RS handshakes to complete
+
debugInfo("Expect genId are set in all replServers.");
waitForStableGenerationId(EMPTY_DN_GENID);
disconnectFromReplServer(replServer1);
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/SchemaReplicationTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/SchemaReplicationTest.java
index b778de7..fea63eb 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/SchemaReplicationTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/SchemaReplicationTest.java
@@ -13,6 +13,7 @@
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2012-2016 ForgeRock AS.
+ * Portions Copyright 2025 3A Systems LLC.
*/
package org.opends.server.replication;
@@ -234,6 +235,7 @@
@Override
public void call() throws Exception
{
+ assertTrue(schemaFile.exists());
String fileStr = readAsString(schemaFile);
assertTrue(fileStr.contains(stateStr), "The Schema persistentState (CSN:" + stateStr
+ ") has not been saved to " + schemaFile + " : " + fileStr);
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/service/FakeReplicationDomain.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/service/FakeReplicationDomain.java
index 276b039..90589a2 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/service/FakeReplicationDomain.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/service/FakeReplicationDomain.java
@@ -13,6 +13,7 @@
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2025 3A Systems LLC.
*/
package org.opends.server.replication.service;
@@ -42,8 +43,8 @@
private BlockingQueue<UpdateMsg> queue;
/** A string that will be exported should exportBackend be called. */
private String exportString;
- /** A StringBuilder that will be used to build a new String should the import be called. */
- private StringBuilder importString;
+ /** A StringBuffer that will be used to build a new String should the import be called. */
+ private StringBuffer importString;
private int exportedEntryCount;
private FakeReplicationDomain(DN baseDN, int serverID,
@@ -82,7 +83,7 @@
FakeReplicationDomain(DN baseDN, int serverID,
SortedSet<String> replicationServers, long heartbeatInterval,
- String exportString, StringBuilder importString, int exportedEntryCount)
+ String exportString, StringBuffer importString, int exportedEntryCount)
throws ConfigException
{
this(baseDN, serverID, replicationServers, 100, heartbeatInterval, 1);
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/service/ReplicationDomainTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/service/ReplicationDomainTest.java
index 50a6728..27e11d8 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/service/ReplicationDomainTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/service/ReplicationDomainTest.java
@@ -17,7 +17,10 @@
*/
package org.opends.server.replication.service;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
import static org.opends.messages.ReplicationMessages.*;
+import static org.opends.server.TestCaseUtils.generateThreadDump;
import static org.opends.server.util.CollectionUtils.*;
import static org.testng.Assert.*;
@@ -28,6 +31,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.opends.server.TestCaseUtils;
import org.opends.server.backends.task.Task;
@@ -42,6 +46,7 @@
import org.opends.server.replication.service.ReplicationDomain.ImportExportContext;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.DirectoryException;
+import org.opends.server.util.TestTimer;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -302,8 +307,7 @@
new ReplServerFakeConfiguration(replicationPort, dirName, 0, serverId, 0, windowSize, replServers));
}
- private void disable(ReplicationDomain... domains)
- {
+ private void disable(ReplicationDomain... domains) throws InterruptedException {
for (ReplicationDomain domain : domains)
{
if (domain != null)
@@ -348,7 +352,7 @@
domain1 = new FakeReplicationDomain(
testService, serverId1, servers, 0, exportedData, null, ENTRYCOUNT);
- StringBuilder importedData = new StringBuilder();
+ StringBuffer importedData = new StringBuffer();
domain2 = new FakeReplicationDomain(
testService, serverId2, servers, 0, null, importedData, 0);
@@ -419,10 +423,27 @@
domain1 = new FakeReplicationDomain(
testService, 1, servers1, 0, exportedData, null, ENTRYCOUNT);
- StringBuilder importedData = new StringBuilder();
+ StringBuffer importedData = new StringBuffer();
domain2 = new FakeReplicationDomain(
testService, 2, servers2, 0, null, importedData, 0);
+
+ //wait for domains topology initialization
+ {
+ TestTimer timer = new TestTimer.Builder()
+ .maxSleep(30, SECONDS)
+ .sleepTimes(100, MILLISECONDS)
+ .toTimer();
+ final FakeReplicationDomain finalDomain1 = domain1;
+ final FakeReplicationDomain finalDomain2 = domain2;
+ timer.repeatUntilSuccess(() -> {
+ assertFalse(finalDomain1.getReplicaInfos().isEmpty());
+ assertEquals(2, finalDomain1.getRsInfos().size());
+ assertFalse(finalDomain2.getReplicaInfos().isEmpty());
+ assertEquals(2, finalDomain2.getRsInfos().size());
+ });
+ }
+
domain2.initializeFromRemote(1, NO_INIT_TASK);
waitEndExport(exportedData, importedData);
@@ -445,18 +466,22 @@
return sb.toString();
}
- private void waitEndExport(String exportedData, StringBuilder importedData) throws Exception
+ private void waitEndExport(String exportedData, StringBuffer importedData) throws Exception
{
int count = 0;
while (importedData.length() < exportedData.length() && count < 500*5)
{
+ if(count % 100 == 0) { //capture thread dump on start and every 10 seconds
+ logger.debug(LocalizableMessage.raw("waitEndExport: thread dump on count=" + count));
+ logger.debug(LocalizableMessage.raw(generateThreadDump()));
+ }
count ++;
Thread.sleep(100);
}
}
private void assertExportSucessful(ReplicationDomain domain1,
- ReplicationDomain domain2, String exportedData, StringBuilder importedData)
+ ReplicationDomain domain2, String exportedData, StringBuffer importedData)
{
assertEquals(getLeftEntryCount(domain2), 0, "Wrong LeftEntryCount for export");
assertEquals(getLeftEntryCount(domain1), 0, "Wrong LeftEntryCount for import");
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/util/TestTimer.java b/opendj-server-legacy/src/test/java/org/opends/server/util/TestTimer.java
index ceeaa39..ab81ab2 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/util/TestTimer.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/util/TestTimer.java
@@ -12,13 +12,17 @@
* information: "Portions Copyright [year] [name of copyright owner]".
*
* Copyright 2015-2016 ForgeRock AS.
+ * Portions Copyright 2025 3A Systems LLC.
*/
package org.opends.server.util;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.util.Reject;
+import org.opends.server.TestCaseUtils;
/**
* Timer useful for testing: it helps to write loops that repeatedly runs code until some condition
@@ -153,6 +157,7 @@
/** A {@link TestTimer} that sleeps in steps and sleeps at maximum {@code nbSteps * sleepTimes}. */
public static class SteppingTimer implements TestTimer
{
+ private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
private final long sleepTime;
private final long totalNbSteps;
private long nbStepsRemaining;
@@ -204,6 +209,7 @@
{
if (hasTimedOutNoSleep())
{
+ logger.info(LocalizableMessage.raw("failed to wait for" + callable + "\n" + TestCaseUtils.generateThreadDump()));
throw e;
}
}
diff --git a/pom.xml b/pom.xml
index efc4a92..9d9d0fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,9 @@
<commons.version>3.0.0-SNAPSHOT</commons.version>
<freemarker.version>2.3.34</freemarker.version>
<metrics-core.version>4.2.30</metrics-core.version>
+ <bc.fips.version>2.1.1</bc.fips.version>
+ <bctls.fips.version>2.1.20</bctls.fips.version>
+ <bcpkix.fips.version>2.1.9</bcpkix.fips.version>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<!-- OSGi bundles properties -->
@@ -219,6 +222,22 @@
<artifactId>opendj-server-legacy</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bc-fips</artifactId>
+ <version>${bc.fips.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bctls-fips</artifactId>
+ <version>${bctls.fips.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-fips</artifactId>
+ <version>${bcpkix.fips.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
@@ -687,7 +706,7 @@
<jdk>[17,)</jdk>
</activation>
<properties>
- <argLine>-Xmx512m --add-exports java.base/sun.security.x509=ALL-UNNAMED --add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.util.regex=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.naming/javax.naming.spi=ALL-UNNAMED</argLine>
+ <argLine>-Xmx512m --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.util.regex=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.naming/javax.naming.spi=ALL-UNNAMED</argLine>
<maven.cargo.containerId>tomcat11x</maven.cargo.containerId>
</properties>
</profile>
--
Gitblit v1.10.0