mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Maxim Thomas
03.30.2025 61dac86bceb9d727e1bd707982c41ab9467c6d5a
Switch from sun.security.x509 to Bouncy Castle API (#560)

Co-authored-by: Valera V Harseko <vharseko@3a-systems.ru>
28 files modified
679 ■■■■■ changed files
.github/workflows/build.yml 56 ●●●●● patch | view | raw | blame | history
opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java 2 ●●● patch | view | raw | blame | history
opendj-core/pom.xml 10 ●●●● patch | view | raw | blame | history
opendj-core/src/main/java/com/forgerock/opendj/util/FipsStaticUtils.java 6 ●●●● patch | view | raw | blame | history
opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java 2 ●●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/TrustManagers.java 4 ●●●● patch | view | raw | blame | history
opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java 54 ●●●● patch | view | raw | blame | history
opendj-server-legacy/pom.xml 6 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/bin/_script-util.bat 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/bin/_script-util.sh 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedKeyManagerProvider.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedTrustManagerProvider.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationBroker.java 13 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java 24 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tools/InstallDS.java 5 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tools/SSLConnectionFactory.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/types/HostPort.java 14 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java 263 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/messages/org/opends/messages/utility.properties 8 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/DirectoryServerTestCase.java 3 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java 94 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/TestListener.java 24 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java 2 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/SchemaReplicationTest.java 2 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/service/FakeReplicationDomain.java 7 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/service/ReplicationDomainTest.java 37 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/util/TestTimer.java 6 ●●●●● patch | view | raw | blame | history
pom.xml 21 ●●●●● patch | view | raw | blame | history
.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:   |
opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java
@@ -852,7 +852,7 @@
        }
        if (isFips) {
            return TrustManagers.checkUsingPkcs11TrustStore();
            return TrustManagers.checkUsingPkcs12TrustStore();
        }
        return tm;
opendj-core/pom.xml
@@ -96,13 +96,14 @@
        <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>
        </dependency>
         <dependency>
@@ -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
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;
        }
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;
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 =
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);
            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];
            chain[0]=keyGen.getSelfCertificate(new X500Name("CN=localhost"), (long)1*3600);
            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();
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>
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
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
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();
      }
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);
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();
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)
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
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();
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;
    }
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,104 +123,11 @@
   */
  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
    {
@@ -264,8 +150,6 @@
      }
    }
    private final void addCertificate(KeyStore ks, String ksType, String ksPath,
        String alias, char[] pwd, String certPath) throws KeyStoreException
    {
@@ -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
    {
      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);
    }
    /**
@@ -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.
@@ -444,8 +331,6 @@
    IMPL.addCertificate(ks, ksType, ksPath, alias, pwd, certPath);
  }
  /**
   * Delete the specified alias from the provided keystore.
   *
@@ -466,8 +351,6 @@
    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
@@ -507,8 +390,6 @@
  {
  }
  /**
   * Test if a platform java vendor property starts with the specified vendor
   * string.
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 \
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();
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());
        }
        dump.append("\n\n");
      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:
          }
        }
        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();
  }
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;
@@ -159,6 +159,21 @@
    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)
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);
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);
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);
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");
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;
          }
        }
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>