From 70d9a179cdd8d975b44e1815c249e20d9f91097f Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Wed, 16 Sep 2026 08:10:15 +0000
Subject: [PATCH] [#912] Provision the ads-truststore from an existing key store at setup time (#984)
---
opendj-server-legacy/src/main/java/org/opends/server/util/CertificateManager.java | 124 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 124 insertions(+), 0 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/util/CertificateManager.java b/opendj-server-legacy/src/main/java/org/opends/server/util/CertificateManager.java
index 4b10875..cc3e997 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/util/CertificateManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/util/CertificateManager.java
@@ -13,13 +13,17 @@
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2013-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.server.util;
import java.io.File;
import java.io.FileInputStream;
+import java.security.GeneralSecurityException;
+import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
@@ -81,6 +85,8 @@
private static final String CERT_ALIAS_MSG = "certificate alias";
private static final String CERT_REQUEST_FILE_MSG =
"certificate request file";
+ private static final String SOURCE_KEYSTORE_MSG = "source key store";
+ private static final String CERT_MSG = "certificate";
/** The parsed key store backing this certificate manager. */
private KeyStore keyStore;
@@ -191,6 +197,17 @@
/**
+ * Retrieves the path of the key store this certificate manager works on.
+ *
+ * @return The path of the key store.
+ */
+ public String getKeyStorePath() {
+ return keyStorePath;
+ }
+
+
+
+ /**
* Indicates whether the provided alias is in use in the key store.
*
* @param alias The alias for which to make the determination. It must not
@@ -268,6 +285,113 @@
/**
+ * Retrieves the certificate chain of the key entry with the specified alias from the
+ * key store, the certificate the key belongs to first and its issuers next.
+ *
+ * @param alias The alias of the key entry whose chain to retrieve. It must not be
+ * {@code null} or empty.
+ *
+ * @return The certificate chain, or {@code null} if the key store holds no key entry
+ * under the specified alias.
+ *
+ * @throws KeyStoreException If a problem occurs while interacting with the key store,
+ * or the key store does not exist.
+ */
+ public Certificate[] getCertificateChain(String alias)
+ throws KeyStoreException {
+ ensureValid(alias, CERT_ALIAS_MSG);
+ KeyStore ks = getKeyStore();
+ if (ks == null) {
+ LocalizableMessage msg = ERR_CERTMGR_KEYSTORE_NONEXISTANT.get();
+ throw new KeyStoreException(msg.toString());
+ }
+ return ks.getCertificateChain(alias);
+ }
+
+
+ /**
+ * Copies the key entry with the specified alias from the provided key store into this
+ * one, with its whole certificate chain. The private key is re-encrypted with the
+ * password of this key store: the key managers of the server are initialised with the
+ * store password only, so a key which kept the password of the key store it comes from
+ * could not be read back.
+ * <p>
+ * The certificates of the chain are not added as trusted certificates, as only a
+ * trusted certificate entry is a trust anchor. Use {@link #addTrustedCertificate} for
+ * the issuers which have to be trusted.
+ *
+ * @param alias The alias to store the key entry under in this key store. It
+ * must not be {@code null} or empty.
+ * @param sourceManager The certificate manager of the key store holding the key entry
+ * to copy. It must not be {@code null}.
+ * @param sourceAlias The alias of the key entry to copy. It must not be
+ * {@code null} or empty.
+ *
+ * @throws KeyStoreException If the source key store holds no key entry under the
+ * provided alias, if its private key is protected by a
+ * password other than the one of the source key store, if
+ * the alias is already in use in this key store, or a
+ * problem occurs while interacting with either key store.
+ */
+ public void importKeyEntry(String alias, CertificateManager sourceManager, String sourceAlias)
+ throws KeyStoreException {
+ ensureValid(alias, CERT_ALIAS_MSG);
+ ensureValid(sourceAlias, CERT_ALIAS_MSG);
+ if (sourceManager == null) {
+ LocalizableMessage msg = ERR_CERTMGR_VALUE_INVALID.get(SOURCE_KEYSTORE_MSG);
+ throw new NullPointerException(msg.toString());
+ }
+
+ final Certificate[] chain = sourceManager.getCertificateChain(sourceAlias);
+ final Key privateKey;
+ try {
+ privateKey = sourceManager.getKeyStore().getKey(sourceAlias, sourceManager.password);
+ } catch (UnrecoverableKeyException e) {
+ // The key is protected by a password of its own. The key managers of the server
+ // unlock private keys with the store password only, so this is the same limitation
+ // the key store already has for LDAPS: say so rather than "Cannot recover key".
+ throw new KeyStoreException(
+ ERR_CERTMGR_KEY_PASSWORD_DIFFERS.get(sourceAlias, sourceManager.keyStorePath).toString(), e);
+ } catch (GeneralSecurityException e) {
+ throw new KeyStoreException(
+ ERR_CERTMGR_IMPORT_KEY_ENTRY.get(sourceAlias, e.getMessage()).toString(), e);
+ }
+ if (privateKey == null || chain == null || chain.length == 0) {
+ LocalizableMessage msg =
+ ERR_CERTMGR_NO_KEY_ENTRY.get(sourceAlias, sourceManager.keyStorePath);
+ throw new KeyStoreException(msg.toString());
+ }
+
+ keyStore = null;
+ Platform.importKeyEntry(getKeyStore(), keyStoreType, keyStorePath, alias, password, privateKey, chain);
+ }
+
+
+ /**
+ * Adds the provided certificate to the key store as a trusted certificate entry. Only
+ * such an entry is a trust anchor: of a key entry, the trust managers take the
+ * certificate the key belongs to and none of its issuers.
+ *
+ * @param alias The alias to use for the certificate. It must not be
+ * {@code null} or empty.
+ * @param certificate The certificate to trust. It must not be {@code null}.
+ *
+ * @throws KeyStoreException If the alias is already in use, or a problem occurs while
+ * interacting with the key store.
+ */
+ public void addTrustedCertificate(String alias, Certificate certificate)
+ throws KeyStoreException {
+ ensureValid(alias, CERT_ALIAS_MSG);
+ if (certificate == null) {
+ LocalizableMessage msg = ERR_CERTMGR_VALUE_INVALID.get(CERT_MSG);
+ throw new NullPointerException(msg.toString());
+ }
+ keyStore = null;
+ Platform.addTrustedCertificate(getKeyStore(), keyStoreType, keyStorePath, alias, password, certificate);
+ }
+
+
+ /**
* Generates a self-signed certificate using the provided information.
*
* @param keyType Specifies the key size, key and signature algorithms.
--
Gitblit v1.10.0