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

Yuriy Movchan
30.08.2021 2cf46088b7e69b4f424a821291607afe6faa7e4f
Add FIPS support (#176)

2 files added
24 files modified
649 ■■■■■ changed files
opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java 60 ●●●● patch | view | raw | blame | history
opendj-cli/src/main/java/com/forgerock/opendj/cli/Utils.java 3 ●●●●● patch | view | raw | blame | history
opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java 3 ●●●●● patch | view | raw | blame | history
opendj-core/pom.xml 16 ●●●●● patch | view | raw | blame | history
opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java 30 ●●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/TrustManagers.java 17 ●●●●● patch | view | raw | blame | history
opendj-core/src/main/resources/com/forgerock/opendj/ldap/core.properties 2 ●●●●● patch | view | raw | blame | history
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java 33 ●●●● patch | view | raw | blame | history
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java 11 ●●●●● patch | view | raw | blame | history
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java 3 ●●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CryptoManagerConfiguration.xml 4 ●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/PKCS11TrustManagerProviderConfiguration.xml 52 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java 10 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/admin/ads/util/ApplicationTrustManager.java 5 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/admin/ads/util/ConnectionWrapper.java 14 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/Installer.java 69 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/SetupLauncher.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ServerController.java 11 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/config/ConfigurationHandler.java 11 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java 3 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedTrustManagerProvider.java 12 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/PKCS11TrustManagerProvider.java 188 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureDS.java 52 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tools/InstallDS.java 18 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/util/StaticUtils.java 15 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/messages/org/opends/messages/extension.properties 3 ●●●●● patch | view | raw | blame | history
opendj-cli/src/main/java/com/forgerock/opendj/cli/ConnectionFactoryProvider.java
@@ -34,12 +34,15 @@
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
@@ -63,6 +66,8 @@
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.util.Options;
import com.forgerock.opendj.util.StaticUtils;
/** A connection factory designed for use with command line tools. */
public final class ConnectionFactoryProvider {
    /** The Logger. */
@@ -356,7 +361,10 @@
     *         If an SSL context could not be created.
     */
    public static List<String> getDefaultProtocols() throws NoSuchAlgorithmException {
        List<String> enabled = Arrays.asList(SSLContext.getDefault().createSSLEngine().getEnabledProtocols());
        return getDefaultProtocols(SSLContext.getDefault());
    }
    public static List<String> getDefaultProtocols(SSLContext sslContext) throws NoSuchAlgorithmException {
        List<String> enabled = Arrays.asList(sslContext.createSSLEngine().getEnabledProtocols());
        final String property = System.getProperty("org.opends.ldaps.protocols");
        final List<String> defaults = new ArrayList<>();
        if (property != null && property.length() != 0) {
@@ -445,6 +453,8 @@
                        if (akm != null && clientAlias != null) {
                            keyManager = KeyManagers.useSingleCertificate(clientAlias, akm);
                        } else {
                            keyManager = akm;
                        }
                        sslContext =
@@ -462,7 +472,7 @@
                try {
                    options.set(SSL_CONTEXT, sslContext)
                            .set(SSL_USE_STARTTLS, useStartTLSArg.isPresent())
                            .set(SSL_ENABLED_PROTOCOLS, getDefaultProtocols());
                            .set(SSL_ENABLED_PROTOCOLS, getDefaultProtocols(sslContext));
                } catch (NoSuchAlgorithmException e) {
                    throw new ArgumentException(ERR_LDAP_CONN_CANNOT_INITIALIZE_SSL.get(e.toString()), e);
                }
@@ -694,9 +704,10 @@
     *             If a problem occurs while loading with the key store.
     * @throws CertificateException
     *             If a problem occurs while loading with the key store.
     * @throws UnrecoverableKeyException
     */
    public X509KeyManager getKeyManager(String keyStoreFile) throws KeyStoreException,
            IOException, NoSuchAlgorithmException, CertificateException {
            IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
        if (keyStoreFile == null) {
            // Lookup the file name through the JDK property.
            keyStoreFile = getKeyStore();
@@ -712,11 +723,29 @@
            keyStorePIN = keyStorePass.toCharArray();
        }
        final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        try (final FileInputStream fos = new FileInputStream(keyStoreFile)) {
            keystore.load(fos, keyStorePIN);
        boolean isFips = StaticUtils.isFips();
        final String keyStoreType = KeyStore.getDefaultType();
        final KeyStore keystore = KeyStore.getInstance(keyStoreType);
        if (isFips) {
            keystore.load(null, keyStorePIN);
        } else {
            try (final FileInputStream fos = new FileInputStream(keyStoreFile)) {
                keystore.load(fos, keyStorePIN);
            }
        }
        if (isFips) {
            String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(keyManagerAlgorithm);
            keyManagerFactory.init(keystore, keyStorePIN);
            for (final KeyManager km : keyManagerFactory.getKeyManagers()) {
                if (km instanceof X509KeyManager) {
                    return (X509KeyManager) km;
                }
            }
        }
        return new ApplicationKeyManager(keystore, keyStorePIN);
    }
@@ -802,16 +831,25 @@
            return TrustManagers.trustAll();
        }
        boolean isFips = StaticUtils.isFips();
        X509TrustManager tm = null;
        if (trustStorePathArg.isPresent() && trustStorePathArg.getValue().length() > 0) {
            tm = TrustManagers.checkValidityDates(TrustManagers.checkHostName(hostNameArg.getValue(),
                    TrustManagers.checkUsingTrustStore(trustStorePathArg.getValue(), getTrustStorePIN(), null)));
            if (isFips) {
                tm = TrustManagers.checkUsingTrustStore(trustStorePathArg.getValue(), getTrustStorePIN(), null);
            } else {
                tm = TrustManagers.checkValidityDates(TrustManagers.checkHostName(hostNameArg.getValue(),
                        TrustManagers.checkUsingTrustStore(trustStorePathArg.getValue(), getTrustStorePIN(), null)));
            }
        } else if (getTrustStore() != null) {
            tm = TrustManagers.checkValidityDates(TrustManagers.checkHostName(hostNameArg.getValue(),
                    TrustManagers.checkUsingTrustStore(getTrustStore(), getTrustStorePIN(), null)));
            if (isFips) {
                tm = TrustManagers.checkUsingTrustStore(getTrustStore(), getTrustStorePIN(), null);
            } else {
                tm = TrustManagers.checkValidityDates(TrustManagers.checkHostName(hostNameArg.getValue(),
                        TrustManagers.checkUsingTrustStore(getTrustStore(), getTrustStorePIN(), null)));
            }
        }
        if (app != null && !app.isQuiet()) {
        if (app != null && !app.isQuiet() && !isFips) {
            return new PromptingTrustManager(app, tm);
        }
opendj-cli/src/main/java/com/forgerock/opendj/cli/Utils.java
@@ -29,6 +29,8 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.Provider;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
@@ -729,4 +731,5 @@
    public static LocalizableMessage conflictingArgsErrorMessage(final Argument arg1, final Argument arg2) {
        return ERR_TOOL_CONFLICTING_ARGS.get(arg1.getLongIdentifier(), arg2.getLongIdentifier());
    }
}
opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
@@ -28,6 +28,8 @@
import static org.forgerock.opendj.config.PropertyOption.*;
import static org.forgerock.opendj.config.dsconfig.ArgumentExceptionFactory.*;
import static com.forgerock.opendj.util.StaticUtils.registerBcProvider;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
@@ -1053,6 +1055,7 @@
    private int run(String[] args) {
        // Register global arguments and sub-commands.
        try {
            registerBcProvider();
            initializeGlobalArguments();
            initializeSubCommands();
        } catch (ArgumentException e) {
opendj-core/pom.xml
@@ -90,10 +90,26 @@
          <groupId>com.sun.xml.bind</groupId>
          <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>
    </dependencies>
    <properties>
        <bc.fips.version>1.0.2.1</bc.fips.version>
        <bctls.fips.version>1.0.9</bctls.fips.version>
        <opendj.osgi.import.additional>
            com.sun.security.auth*;resolution:=optional
        </opendj.osgi.import.additional>
opendj-core/src/main/java/com/forgerock/opendj/util/StaticUtils.java
@@ -42,6 +42,9 @@
import org.forgerock.util.Reject;
import org.forgerock.util.Utils;
import static com.forgerock.opendj.ldap.CoreMessages.INFO_BC_PROVIDER_REGISTER;
import static com.forgerock.opendj.ldap.CoreMessages.INFO_BC_PROVIDER_REGISTERED_ALREADY;
/**
 * Common utility methods.
 */
@@ -786,4 +789,31 @@
        }
    }
    public static boolean isFips() {
        java.security.Provider[] providers = java.security.Security.getProviders();
        for (int i = 0; i < providers.length; i++) {
            if (providers[i].getName().toLowerCase().contains("fips"))
                return true;
        }
        return false;
    }
    public static void registerBcProvider()
    {
        if (!isFips()) {
            return;
        }
        org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider bouncyCastleProvider = (org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider) java.security.Security.getProvider(org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider.PROVIDER_NAME);
        if (bouncyCastleProvider == null) {
            logger.info(INFO_BC_PROVIDER_REGISTER.get());
            bouncyCastleProvider = new org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider();
            java.security.Security.insertProviderAt(bouncyCastleProvider, 1);
        } else {
            logger.info(INFO_BC_PROVIDER_REGISTERED_ALREADY.get());
        }
    }
}
opendj-core/src/main/java/org/forgerock/opendj/ldap/TrustManagers.java
@@ -24,6 +24,8 @@
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
@@ -498,7 +500,10 @@
        Reject.ifNull(file);
        final File trustStoreFile = new File(file);
        final String trustStoreFormat = format != null ? format : KeyStore.getDefaultType();
        boolean isFips = isFips();
        final String defaultType = isFips ? "JKS" : KeyStore.getDefaultType();
        final String trustStoreFormat = format != null ? format : defaultType;
        final KeyStore keyStore = KeyStore.getInstance(trustStoreFormat);
        try (FileInputStream fos = new FileInputStream(trustStoreFile)) {
@@ -517,6 +522,16 @@
        throw new NoSuchAlgorithmException();
    }
    public static boolean isFips() {
        Provider[] providers = Security.getProviders();
        for (int i = 0; i < providers.length; i++) {
            if (providers[i].getName().toLowerCase().contains("fips"))
                return true;
        }
        return false;
    }
    /**
     * Wraps the provided {@code X509TrustManager} by adding additional
     * validation which rejects certificate chains containing certificates which
opendj-core/src/main/resources/com/forgerock/opendj/ldap/core.properties
@@ -616,6 +616,8 @@
INFO_RESULT_OFFSET_RANGE_ERROR=Offset Range Error
INFO_RESULT_VIRTUAL_LIST_VIEW_ERROR=Virtual List View Error
INFO_RESULT_NO_OPERATION=No Operation
INFO_BC_PROVIDER_REGISTER=Registering Bouncy Castle Provider
INFO_BC_PROVIDER_REGISTERED_ALREADY=Bouncy Castle Provider was registered already
#
# Protocol messages
#
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
@@ -87,6 +87,8 @@
import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
import org.glassfish.grizzly.ssl.SSLFilter;
import com.forgerock.opendj.util.StaticUtils;
/** LDAP connection implementation. */
final class GrizzlyLDAPConnection implements LDAPConnectionImpl, TimeoutEventListener {
    static final int LDAP_V3 = 3;
@@ -95,12 +97,15 @@
     * config. This prevents Grizzly from needlessly using JVM defaults which
     * may be incorrectly configured.
     */
    private static final SSLEngineConfigurator DUMMY_SSL_ENGINE_CONFIGURATOR;
    private static SSLEngineConfigurator DUMMY_SSL_ENGINE_CONFIGURATOR = null;
    static {
        try {
            DUMMY_SSL_ENGINE_CONFIGURATOR =
                    new SSLEngineConfigurator(new SSLContextBuilder().setTrustManager(
                            TrustManagers.distrustAll()).getSSLContext());
            // We need to use FIPS compatible Trust Manasger in FIPS mode
            if (!StaticUtils.isFips()) {
                DUMMY_SSL_ENGINE_CONFIGURATOR =
                        new SSLEngineConfigurator(new SSLContextBuilder().setTrustManager(
                                TrustManagers.distrustAll()).getSSLContext());
            }
        } catch (GeneralSecurityException e) {
            // This should never happen.
            throw new IllegalStateException("Unable to create Dummy SSL Engine Configurator", e);
@@ -823,14 +828,30 @@
            sslEngineConfigurator.setEnabledCipherSuites(cipherSuites.isEmpty() ? null : cipherSuites
                    .toArray(new String[cipherSuites.size()]));
            sslEngineConfigurator.setCipherConfigured(true);
            final SSLFilter sslFilter = new SSLFilter(DUMMY_SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
            SSLEngineConfigurator serverSslEngineConfigurator = buildServerSSLEngineConfigurator(sslContext);
            final SSLFilter sslFilter = new SSLFilter(serverSslEngineConfigurator, sslEngineConfigurator);
            sslFilter.setHandshakeTimeout(getLongProperty("org.forgerock.opendj.grizzly.handshakeTimeout", sslFilter.getHandshakeTimeout(TimeUnit.MILLISECONDS)), TimeUnit.MILLISECONDS);
            installFilter(sslFilter);
            sslFilter.handshake(connection, completionHandler);
        }
    }
    private LdapException adaptRequestIOException(final IOException e) {
    private SSLEngineConfigurator buildServerSSLEngineConfigurator(SSLContext sslContext) {
        if (DUMMY_SSL_ENGINE_CONFIGURATOR != null) {
            return DUMMY_SSL_ENGINE_CONFIGURATOR;
        }
        if (sslContext == null) {
            throw new IllegalStateException("SSL context should be defined in FIPS mode");
        }
        SSLEngineConfigurator sslEngineConfigurator = new SSLEngineConfigurator(sslContext);
        return sslEngineConfigurator;
    }
    private LdapException adaptRequestIOException(final IOException e) {
        // FIXME: what other sort of IOExceptions can be thrown?
        // FIXME: Is this the best result code?
        final Result errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java
@@ -28,6 +28,7 @@
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
@@ -71,6 +72,7 @@
import org.glassfish.grizzly.filterchain.FilterChainBuilder;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import org.glassfish.grizzly.ssl.SSLContextConfigurator;
import org.glassfish.grizzly.ssl.SSLFilter;
import org.glassfish.grizzly.ssl.SSLUtils;
import org.reactivestreams.Publisher;
@@ -386,6 +388,15 @@
                    return false;
                }
                SSLUtils.setSSLEngine(connection, sslEngine);
                Properties props = System.getProperties();
                // Workaround for PKCS11
                String keyStoreFile = props.getProperty(SSLContextConfigurator.KEY_STORE_FILE);
                if ("none".equalsIgnoreCase(keyStoreFile)) {
                    System.setProperty(SSLContextConfigurator.TRUST_STORE_FILE, "NONE");
                }
                SSLFilter sslFilter = new SSLFilter();
                sslFilter.setHandshakeTimeout(getLongProperty("org.forgerock.opendj.grizzly.handshakeTimeout", sslFilter.getHandshakeTimeout(TimeUnit.MILLISECONDS)), TimeUnit.MILLISECONDS);
                installFilter(startTls ? new StartTLSFilter(sslFilter) : sslFilter);
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java
@@ -26,6 +26,8 @@
import static com.forgerock.opendj.ldap.tools.LDAPToolException.newToolParamException;
import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
import static com.forgerock.opendj.util.StaticUtils.registerBcProvider;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -463,6 +465,7 @@
    @VisibleForTesting
    static int runTool(final ToolConsoleApplication tool, final String... args) {
        try {
            registerBcProvider();
            return tool.run(args);
        } catch (final LDAPToolException e) {
            e.printErrorMessage(tool);
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CryptoManagerConfiguration.xml
@@ -48,7 +48,7 @@
    </adm:requires-admin-action>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>SHA-1</adm:value>
        <adm:value>SHA-256</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
@@ -75,7 +75,7 @@
    </adm:requires-admin-action>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>HmacSHA1</adm:value>
        <adm:value>HmacSHA256</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/PKCS11TrustManagerProviderConfiguration.xml
New file
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
  The contents of this file are subject to the terms of the Common Development and
  Distribution License (the License). You may not use this file except in compliance with the
  License.
  You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
  specific language governing permission and limitations under the License.
  When distributing Covered Software, include this CDDL Header Notice in each file and include
  the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
  Header, with the fields enclosed by brackets [] replaced by your own identifying
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2007-2008 Sun Microsystems, Inc.
  Portions Copyright 2011 ForgeRock AS.
  ! -->
<adm:managed-object name="pkcs11-trust-manager-provider"
  plural-name="pkcs11-trust-manager-providers"
  package="org.forgerock.opendj.server.config" extends="trust-manager-provider"
  xmlns:adm="http://opendj.forgerock.org/admin"
  xmlns:ldap="http://opendj.forgerock.org/admin-ldap">
  <adm:synopsis>
    The
    <adm:user-friendly-name />
    enables the server to access the private
    key information through the PKCS11 interface.
  </adm:synopsis>
  <adm:description>
    This standard interface is used by cryptographic accelerators and
    hardware security modules.
  </adm:description>
  <adm:profile name="ldap">
    <ldap:object-class>
      <ldap:name>ds-cfg-pkcs11-trust-manager-provider</ldap:name>
      <ldap:superior>ds-cfg-trust-manager-provider</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property-override name="java-class" advanced="true">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          org.opends.server.extensions.PKCS11TrustManagerProvider
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property-reference name="trust-store-pin" />
  <adm:property-reference name="trust-store-pin-property" />
  <adm:property-reference name="trust-store-pin-environment-variable" />
  <adm:property-reference name="trust-store-pin-file" />
</adm:managed-object>
opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
@@ -22,6 +22,8 @@
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static com.forgerock.opendj.util.StaticUtils.isFips;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -92,6 +94,8 @@
import com.forgerock.reactive.ReactiveHandler;
import com.forgerock.reactive.Stream;
import java.security.Provider;
import java.security.Security;
/**
 * This class defines a connection handler that will be used for communicating with clients over LDAP. It is actually
@@ -939,7 +943,11 @@
            final TrustManager[] trustManagers =
                    trustMgrDN == null ? null : serverContext.getTrustManagerProvider(trustMgrDN).getTrustManagers();
            SSLContext sslContext = SSLContext.getInstance(SSL_CONTEXT_INSTANCE_NAME);
            sslContext.init(keyManagers, trustManagers, null);
            if (isFips()) {
                sslContext.init(keyManagerProvider.getKeyManagers(), trustManagers, null);
            } else {
                sslContext.init(keyManagers, trustManagers, null);
            }
            return sslContext;
        } catch (Exception e) {
            logger.traceException(e);
opendj-server-legacy/src/main/java/org/opends/admin/ads/util/ApplicationTrustManager.java
@@ -458,4 +458,9 @@
    }
    return hostMatch;
  }
  public X509TrustManager getX509TrustManager() {
    return trustManager;
  }
}
opendj-server-legacy/src/main/java/org/opends/admin/ads/util/ConnectionWrapper.java
@@ -26,6 +26,7 @@
import java.io.Closeable;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.KeyManager;
@@ -152,9 +153,18 @@
    if (isLdaps || isStartTls)
    {
      try {
        options.set(SSL_CONTEXT, getSSLContext(trustManager, keyManager))
        SSLContext sslContext = getSSLContext(trustManager, keyManager);
        List<String> defaultProtocols;
        if (trustManager == null) {
            defaultProtocols = ConnectionFactoryProvider.getDefaultProtocols();
        } else {
            defaultProtocols = ConnectionFactoryProvider.getDefaultProtocols(sslContext);
        }
        options.set(SSL_CONTEXT, sslContext)
                .set(SSL_USE_STARTTLS, isStartTls)
                .set(SSL_ENABLED_PROTOCOLS, ConnectionFactoryProvider.getDefaultProtocols());
                .set(SSL_ENABLED_PROTOCOLS, defaultProtocols);
      } catch (NoSuchAlgorithmException e) {
          throw newLdapException(CLIENT_SIDE_PARAM_ERROR, "Unable to perform SSL initialization:" + e.getMessage());
      }
opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/Installer.java
@@ -27,6 +27,7 @@
import static org.opends.admin.ads.ServerDescriptor.ServerProperty.*;
import static org.opends.admin.ads.util.ConnectionUtils.*;
import static org.opends.admin.ads.util.PreferredConnection.Type.*;
import static org.opends.messages.AdminMessages.WARN_ADMIN_SET_PERMISSIONS_FAILED;
import static org.opends.messages.QuickSetupMessages.*;
import static org.opends.quicksetup.Step.*;
import static org.opends.quicksetup.installer.DataReplicationOptions.Type.*;
@@ -37,10 +38,15 @@
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -53,6 +59,8 @@
import java.util.Set;
import javax.naming.ldap.Rdn;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.swing.JPanel;
import org.forgerock.i18n.LocalizableMessage;
@@ -125,6 +133,8 @@
import org.opends.server.backends.task.TaskState;
import org.opends.server.tools.BackendTypeHelper;
import org.opends.server.tools.BackendTypeHelper.BackendTypeUIAdapter;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.FilePermission;
import org.opends.server.types.HostPort;
import org.opends.server.util.CertificateManager;
import org.opends.server.util.CollectionUtils;
@@ -205,6 +215,8 @@
  private char[] selfSignedCertPw;
  private ApplicationTrustManager trustManager;
  private boolean registeredNewServerOnRemote;
  private boolean createdAdministrator;
  private boolean createdRemoteAds;
@@ -1363,6 +1375,8 @@
      case PKCS11:
        configureKeyAndTrustStore(CertificateManager.KEY_STORE_PATH_PKCS11, CertificateManager.KEY_STORE_TYPE_PKCS11,
            CertificateManager.KEY_STORE_TYPE_JKS, sec);
        configureAdminKeyAndTrustStore(CertificateManager.KEY_STORE_PATH_PKCS11, CertificateManager.KEY_STORE_TYPE_PKCS11,
                CertificateManager.KEY_STORE_TYPE_JKS, sec);
        break;
      default:
@@ -1394,6 +1408,38 @@
    }
  }
  private void configureAdminKeyAndTrustStore(final String keyStorePath, final String keyStoreType,
      final String trustStoreType, final SecurityOptions sec) throws Exception
  {
    final String keystorePassword = sec.getKeystorePassword();
    final String trustStorePath = getPath2("admin-truststore");
    CertificateManager certManager = new CertificateManager(keyStorePath, keyStoreType, keystorePassword);
    for (String keyStoreAlias : sec.getAliasesToUse())
    {
      SetupUtils.exportCertificate(certManager, keyStoreAlias, getTemporaryCertificatePath());
      configureAdminTrustStore(trustStorePath, trustStoreType, keyStoreAlias, keystorePassword);
    }
    // Set default trustManager to allow check server startup status
    if (com.forgerock.opendj.util.StaticUtils.isFips()) {
        KeyStore truststore = null;
        try (final FileInputStream fis = new FileInputStream(trustStorePath))
        {
          truststore = KeyStore.getInstance(trustStoreType);
          truststore.load(fis, keystorePassword.toCharArray());
        }
        catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e)
        {
          // Nothing to do: if this occurs we will systematically refuse the certificates.
          // Maybe we should avoid this and be strict, but we are in a best effort mode.
          logger.warn(LocalizableMessage.raw("Error with the truststore"), e);
        }
        this.trustManager = new ApplicationTrustManager(truststore);
    }
  }
  private void configureTrustStore(final String type, final String keyStoreAlias, final String password)
      throws Exception
  {
@@ -1406,6 +1452,28 @@
    f.delete();
  }
  private void configureAdminTrustStore(final String trustStorePath, final String type, final String keyStoreAlias, final String password)
      throws Exception
  {
    final String alias = keyStoreAlias != null ? keyStoreAlias : SELF_SIGNED_CERT_ALIASES[0];
    final CertificateManager trustMgr = new CertificateManager(trustStorePath, type, password);
    trustMgr.addCertificate(alias, new File(getTemporaryCertificatePath()));
    createProtectedFile(getKeystorePinPath(), password);
    final File f = new File(getTemporaryCertificatePath());
    f.delete();
  }
  @Override
  public ApplicationTrustManager getTrustManager()
  {
    if (trustManager != null) {
        return trustManager;
    }
    return super.getTrustManager();
  }
  private void addCertificateArguments(SecurityOptions sec, List<String> argList)
  {
    final Collection<String> aliasInKeyStore = sec.getAliasesToUse();
@@ -4602,6 +4670,7 @@
    FileManager fileManager = new FileManager();
    fileManager.synchronize(getInstallation().getTemplateDirectory(), getInstallation().getInstanceDirectory());
  }
}
/** Class used to be able to cancel long operations. */
opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/SetupLauncher.java
@@ -20,6 +20,8 @@
import static org.opends.messages.ToolMessages.*;
import static org.opends.server.util.ServerConstants.*;
import static com.forgerock.opendj.util.StaticUtils.registerBcProvider;
import org.forgerock.i18n.LocalizableMessage;
import org.opends.quicksetup.CliApplication;
import org.opends.quicksetup.Installation;
@@ -91,6 +93,8 @@
    try
    {
      argParser.parseArguments(args);
      registerBcProvider();
      if (argParser.isVersionArgumentPresent())
      {
opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ServerController.java
@@ -23,6 +23,8 @@
import java.util.List;
import java.util.Map;
import javax.net.ssl.TrustManager;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -39,6 +41,7 @@
import org.opends.server.util.SetupUtils;
import com.forgerock.opendj.cli.CliConstants;
import com.forgerock.opendj.util.StaticUtils;
import static com.forgerock.opendj.cli.ArgumentConstants.*;
import static com.forgerock.opendj.cli.Utils.*;
@@ -308,6 +311,7 @@
   * connect to the server after starting to verify that it is listening.
   * @param suppressOutput indicating that ouput to standard output streams
   * from the server should be suppressed.
   * @param trustManager can be null
   * @throws org.opends.quicksetup.ApplicationException if something goes wrong.
   */
  private void startServer(boolean verifyCanConnect, boolean suppressOutput)
@@ -454,6 +458,11 @@
      userDn = null;
      userPw = null;
    }
    TrustManager trustManager = null;
    if (StaticUtils.isFips()) {
      trustManager = application.getTrustManager().getX509TrustManager();
    }
    for (int i=0; i<50 && !connected; i++)
    {
@@ -463,7 +472,7 @@
        timeout = application.getUserData().getConnectTimeout();
      }
      HostPort hp = new HostPort(getHostName(i), port);
      try (ConnectionWrapper conn = new ConnectionWrapper(hp, LDAPS, userDn, userPw, timeout, null))
      try (ConnectionWrapper conn = new ConnectionWrapper(hp, LDAPS, userDn, userPw, timeout, trustManager))
      {
        return;
      }
opendj-server-legacy/src/main/java/org/opends/server/config/ConfigurationHandler.java
@@ -589,10 +589,12 @@
   *          The original entry that is being replaced.
   * @param newEntry
   *          The new entry to use in place of the existing entry with the same DN.
   * @param structuralUpdate
   *          Force objectClass update.
   * @throws DirectoryException
   *           If a problem occurs while trying to replace the entry.
   */
  public void replaceEntry(final Entry oldEntry, final Entry newEntry) throws DirectoryException
  public void replaceEntry(final Entry oldEntry, final Entry newEntry, final boolean structuralUpdate) throws DirectoryException
  {
    final DN newEntryDN = newEntry.getName();
    if (!backend.contains(newEntryDN))
@@ -601,7 +603,7 @@
          ERR_CONFIG_FILE_MODIFY_NO_SUCH_ENTRY.get(oldEntry), getMatchedDN(newEntryDN), null);
    }
    if (!Entries.getStructuralObjectClass(oldEntry, serverContext.getSchema()).equals(
    if (!structuralUpdate && !Entries.getStructuralObjectClass(oldEntry, serverContext.getSchema()).equals(
        Entries.getStructuralObjectClass(newEntry, serverContext.getSchema())))
    {
      throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
@@ -657,6 +659,11 @@
    }
  }
  public void replaceEntry(final Entry oldEntry, final Entry newEntry) throws DirectoryException
  {
      replaceEntry(oldEntry, newEntry, false);
  }
  @Override
  public void registerAddListener(final DN dn, final ConfigAddListener listener)
  {
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -27,6 +27,8 @@
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static com.forgerock.opendj.util.StaticUtils.registerBcProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -1403,6 +1405,7 @@
      // The core Directory Server configuration.
      coreConfigManager.initializeCoreConfig();
      registerBcProvider();
      initializeCryptoManager();
      rotationPolicyConfigManager = new LogRotationPolicyConfigManager(serverContext);
opendj-server-legacy/src/main/java/org/opends/server/extensions/FileBasedTrustManagerProvider.java
@@ -43,6 +43,8 @@
import static org.opends.server.extensions.FileBasedKeyManagerProvider.getKeyStorePIN;
import static org.opends.server.util.StaticUtils.*;
import static com.forgerock.opendj.util.StaticUtils.isFips;
/**
 * This class defines a trust manager provider that will reference certificates
 * stored in a file located on the Directory Server filesystem.
@@ -122,9 +124,13 @@
      trustManagerFactory.init(trustStore);
      TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
      TrustManager[] newTrustManagers = new TrustManager[trustManagers.length];
      for (int i=0; i < trustManagers.length; i++)
      {
        newTrustManagers[i] = new ExpirationCheckTrustManager((X509TrustManager) trustManagers[i]);
      if (isFips()) {
          newTrustManagers = trustManagers;
      } else {
          for (int i=0; i < trustManagers.length; i++)
          {
            newTrustManagers[i] = new ExpirationCheckTrustManager((X509TrustManager) trustManagers[i]);
          }
      }
      return newTrustManagers;
    }
opendj-server-legacy/src/main/java/org/opends/server/extensions/PKCS11TrustManagerProvider.java
New file
@@ -0,0 +1,188 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2006-2010 Sun Microsystems, Inc.
 * Portions Copyright 2021 Gluu, Inc.
 */
package org.opends.server.extensions;
import org.forgerock.i18n.LocalizableMessage;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.util.List;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.forgerock.opendj.config.server.ConfigurationChangeListener;
import org.forgerock.opendj.server.config.server.TrustManagerProviderCfg;
import org.forgerock.opendj.server.config.server.PKCS11TrustManagerProviderCfg;
import org.opends.server.api.TrustManagerProvider;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.forgerock.opendj.config.server.ConfigChangeResult;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.util.ExpirationCheckTrustManager;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.extensions.FileBasedKeyManagerProvider.getKeyStorePIN;
import static org.opends.server.util.StaticUtils.*;
/**
 * This class defines a trust manager provider that will reference certificates
 * stored in a file located on the Directory Server filesystem.
 */
public class PKCS11TrustManagerProvider
       extends TrustManagerProvider<PKCS11TrustManagerProviderCfg>
       implements ConfigurationChangeListener<PKCS11TrustManagerProviderCfg>
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The truststore type to use when accessing the PKCS#11 keystore. */
  private static final String PKCS11_TRUSTSTORE_TYPE = "PKCS11";
  /** The PIN needed to access the trust store. */
  private char[] trustStorePIN;
  /** The handle to the configuration for this trust manager. */
  private PKCS11TrustManagerProviderCfg currentConfig;
  /**
   * Creates a new instance of this file-based trust manager provider.  The
   * <CODE>initializeTrustManagerProvider</CODE> method must be called on the
   * resulting object before it may be used.
   */
  public PKCS11TrustManagerProvider()
  {
    // No implementation is required.
  }
  @Override
  public void initializeTrustManagerProvider(PKCS11TrustManagerProviderCfg cfg)
          throws ConfigException, InitializationException
  {
    final ConfigChangeResult ccr = new ConfigChangeResult();
    currentConfig = cfg;
    trustStorePIN = getTrustStorePIN(cfg, ccr);
    if (!ccr.getMessages().isEmpty())
    {
      throw new InitializationException(ccr.getMessages().get(0));
    }
    cfg.addPKCS11ChangeListener(this);
  }
  @Override
  public void finalizeTrustManagerProvider()
  {
    currentConfig.removePKCS11ChangeListener(this);
  }
  @Override
  public TrustManager[] getTrustManagers() throws DirectoryException
  {
    KeyStore trustStore;
    try {
      trustStore = KeyStore.getInstance(PKCS11_TRUSTSTORE_TYPE);
      trustStore.load(null, trustStorePIN);
    }
    catch (Exception e)
    {
      logger.traceException(e);
      LocalizableMessage message = ERR_PKCS11_KEYMANAGER_CANNOT_LOAD.get(getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getCoreConfigManager().getServerErrorResultCode(), message, e);
    }
    try
    {
      String trustManagerAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
      TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(trustManagerAlgorithm);
      trustManagerFactory.init(trustStore);
      TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
      return trustManagers;
    }
    catch (Exception e)
    {
      logger.traceException(e);
      LocalizableMessage message =
              ERR_PKCS11_TRUSTMANAGER_CANNOT_CREATE_FACTORY.get(getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getCoreConfigManager().getServerErrorResultCode(), message, e);
    }
  }
  @Override
  public boolean isConfigurationAcceptable(TrustManagerProviderCfg cfg, List<LocalizableMessage> unacceptableReasons)
  {
    PKCS11TrustManagerProviderCfg config = (PKCS11TrustManagerProviderCfg) cfg;
    return isConfigurationChangeAcceptable(config, unacceptableReasons);
  }
  @Override
  public boolean isConfigurationChangeAcceptable(PKCS11TrustManagerProviderCfg cfg,
                                                 List<LocalizableMessage> unacceptableReasons)
  {
    int startSize = unacceptableReasons.size();
    final ConfigChangeResult ccr = new ConfigChangeResult();
    getTrustStorePIN(cfg, ccr);
    unacceptableReasons.addAll(ccr.getMessages());
    return startSize == unacceptableReasons.size();
  }
  @Override
  public ConfigChangeResult applyConfigurationChange(PKCS11TrustManagerProviderCfg cfg)
  {
    final ConfigChangeResult ccr = new ConfigChangeResult();
    char[] newPIN = getTrustStorePIN(cfg, ccr);
    if (ccr.getResultCode() == ResultCode.SUCCESS)
    {
      currentConfig = cfg;
      trustStorePIN   = newPIN;
    }
    return ccr;
  }
  private char[] getTrustStorePIN(PKCS11TrustManagerProviderCfg cfg, ConfigChangeResult ccr)
  {
    try
    {
      return FileBasedKeyManagerProvider.getKeyStorePIN(cfg.getTrustStorePinProperty(),
                            cfg.getTrustStorePinEnvironmentVariable(),
                            cfg.getTrustStorePinFile(),
                            cfg.getTrustStorePin(),
                            cfg.dn(),
                            ERR_FILE_TRUSTMANAGER_PIN_PROPERTY_NOT_SET,
                            ERR_FILE_TRUSTMANAGER_PIN_ENVAR_NOT_SET,
                            ERR_FILE_TRUSTMANAGER_PIN_NO_SUCH_FILE,
                            ERR_FILE_TRUSTMANAGER_PIN_FILE_CANNOT_READ,
                            ERR_FILE_TRUSTMANAGER_PIN_FILE_EMPTY);
    }
    catch (InitializationException e)
    {
      ccr.setResultCode(DirectoryServer.getCoreConfigManager().getServerErrorResultCode());
      ccr.addMessage(e.getMessageObject());
      return null;
    }
  }
}
opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureDS.java
@@ -85,6 +85,7 @@
import com.forgerock.opendj.cli.FileBasedArgument;
import com.forgerock.opendj.cli.IntegerArgument;
import com.forgerock.opendj.cli.StringArgument;
import com.forgerock.opendj.util.StaticUtils;
/**
 * This class provides a very basic tool that can be used to configure some of
@@ -187,6 +188,8 @@
      + "ds-cfg-trust-store-type: JCEKS" + NEW_LINE
      + "ds-cfg-trust-store-file: config/truststore" + NEW_LINE;
  private static final String DN_ADMIN_KEY_MANAGER = "cn=Administration,cn=Key Manager Providers," + DN_CONFIG_ROOT;
  /** The DN of the configuration entry defining the LDAP connection handler. */
  private static final String DN_LDAP_CONNECTION_HANDLER = "cn=LDAP Connection Handler," + DN_CONNHANDLER_BASE;
  /** The DN of the configuration entry defining the Administration connector. */
@@ -878,6 +881,9 @@
      putKeyManagerConfigAttribute(enableStartTLS, DN_LDAP_CONNECTION_HANDLER);
      putKeyManagerConfigAttribute(ldapsPort, DN_LDAPS_CONNECTION_HANDLER);
      putKeyManagerConfigAttribute(ldapsPort, DN_HTTP_CONNECTION_HANDLER);
      if (StaticUtils.isFips()) {
          putAdminKeyManagerConfigAttribute(ldapsPort, DN_ADMIN_KEY_MANAGER);
      }
      if (keyManagerPath.isPresent())
      {
@@ -917,6 +923,39 @@
    }
  }
  private void putAdminKeyManagerConfigAttribute(final Argument arg, final String attributeDN)
      throws ConfigureDSException
  {
    if (arg.isPresent())
    {
      try
      {
        updateConfigEntryByRemovingAttribute(attributeDN, ATTR_KEYSTORE_TYPE);
        updateConfigEntryByRemovingAttribute(attributeDN, ATTR_KEYSTORE_FILE);
        updateConfigEntryWithObjectClasses(
                attributeDN,
                "top", "ds-cfg-pkcs11-key-manager-provider", "ds-cfg-key-manager-provider");
        updateConfigEntryWithAttribute(
            attributeDN,
            ATTR_KEYMANAGER_CLASS,
            CoreSchema.getDirectoryStringSyntax(),
            "org.opends.server.extensions.PKCS11KeyManagerProvider");
        updateConfigEntryWithAttribute(
                attributeDN,
                ATTR_KEYSTORE_PIN_FILE,
                CoreSchema.getDirectoryStringSyntax(),
                "config/keystore.pin");
      }
      catch (final Exception e)
      {
        throw new ConfigureDSException(e, ERR_CONFIGDS_CANNOT_UPDATE_KEYMANAGER_REFERENCE.get(e));
      }
    }
  }
  private void updateTrustManager() throws ConfigureDSException
  {
    if (trustManagerProviderDN.isPresent())
@@ -1127,6 +1166,15 @@
    configHandler.replaceEntry(configEntry, Converters.from(newEntry));
  }
  /** Update a config entry with the provided objectCLass parameters. */
  private void updateConfigEntryWithObjectClasses(String entryDn, Object...objectCLasses)
      throws DirectoryException, ConfigException
  {
    org.forgerock.opendj.ldap.Entry configEntry = configHandler.getEntry(DN.valueOf(entryDn));
    final org.forgerock.opendj.ldap.Entry newEntry = putAttribute(configEntry, ATTR_OBJECTCLASS, CoreSchema.getOIDSyntax(), objectCLasses);
    configHandler.replaceEntry(configEntry, newEntry, true);
  }
  /**
   * Duplicate the provided entry, and put an attribute to the duplicated entry.
   * <p>
@@ -1158,7 +1206,7 @@
    {
      if (t.hasNameOrOID(attrName))
      {
        entry.getUserAttributes().remove(t);
        duplicateEntry.getUserAttributes().remove(t);
        return duplicateEntry;
      }
    }
@@ -1167,7 +1215,7 @@
    {
      if (t.hasNameOrOID(attrName))
      {
        entry.getOperationalAttributes().remove(t);
        duplicateEntry.getOperationalAttributes().remove(t);
        return duplicateEntry;
      }
    }
opendj-server-legacy/src/main/java/org/opends/server/tools/InstallDS.java
@@ -825,7 +825,7 @@
      certType = SecurityOptions.CertificateType.NO_CERTIFICATE;
    }
    Collection<String> certNicknames = argParser.certNicknameArg.getValues();
    Collection<String> certNicknames = getCertNickNames();
    if (pathToCertificat != null)
    {
      checkCertificateInKeystore(certType, pathToCertificat, pwd, certNicknames, errorMessages, keystoreAliases);
@@ -840,6 +840,20 @@
    uData.setSecurityOptions(securityOptions);
  }
  private List<String> getCertNickNames() {
      List<String> certNicknames = argParser.certNicknameArg.getValues();
      if ((certNicknames == null) || (certNicknames.size() == 0)) {
          return certNicknames;
      }
      List<String> splitedCertNicknames = new ArrayList<>();
      for (String certNickname : certNicknames) {
          splitedCertNicknames.addAll(StaticUtils.splittedStringAsList(certNickname, " "));
      }
      return splitedCertNicknames;
  }
  private void checkCanUsePort(int port, List<LocalizableMessage> errorMessages)
  {
    if (!SetupUtils.canUseAsPort(port))
@@ -1943,7 +1957,7 @@
      boolean enableStartTLS, int ldapsPort) throws UserDataException, ClientException
  {
    String path;
    Collection<String> certNicknames = argParser.certNicknameArg.getValues();
    Collection<String> certNicknames = getCertNickNames();
    String pwd = argParser.getKeyStorePassword();
    if (pwd != null && pwd.length() == 0)
    {
opendj-server-legacy/src/main/java/org/opends/server/util/StaticUtils.java
@@ -71,6 +71,8 @@
import com.forgerock.opendj.cli.Argument;
import com.forgerock.opendj.cli.ArgumentException;
import java.security.Provider;
import java.security.Security;
/**
 * This class defines a number of static utility methods that may be used
@@ -2579,5 +2581,18 @@
      }
    }
  }
  public static List<String> splittedStringAsList(String str, String delim) {
      final List<String> result = new ArrayList<String>();
      if ((str != null) && !str.isEmpty()) {
          final String[] array = str.split(delim);
          if (array.length > 0) {
              result.addAll(Arrays.asList(array));
          }
      }
      return result;
  }
}
opendj-server-legacy/src/messages/org/opends/messages/extension.properties
@@ -175,6 +175,9 @@
ERR_FILE_TRUSTMANAGER_INVALID_TYPE_106=The trust store type %s \
 specified in attribute ds-cfg-trust-store-type of configuration entry %s is \
 not valid: %s
ERR_PKCS11_TRUSTMANAGER_CANNOT_CREATE_FACTORY_107=An error occurred while \
 trying to create a trust manager factory to access the contents of the PKCS#11 \
 truststore: %s
ERR_SEDCM_NO_PEER_CERTIFICATE_118=Could not map the provided certificate \
 chain to a user entry because no peer certificate was available
ERR_SEDCM_PEER_CERT_NOT_X509_119=Could not map the provided certificate \