From f93487455cc1b5d7062ea6577d99dea25bfd81b3 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Wed, 14 Oct 2026 07:27:37 +0000
Subject: [PATCH] [#1188] Serialize and replace atomically the writes of the ads-truststore, and report a certificate it cannot take or drop (#1189)
---
opendj-server-legacy/src/main/java/org/opends/server/backends/TrustStoreBackend.java | 156 +++++++++++++++++++++++++++++++++++-----------------
1 files changed, 105 insertions(+), 51 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/TrustStoreBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/TrustStoreBackend.java
index a1d58fd..07b410d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/TrustStoreBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/TrustStoreBackend.java
@@ -118,6 +118,15 @@
/** The certificate manager for the trust store. */
private CertificateManager certificateManager;
+ /**
+ * Held over every access to the trust store file and to the certificate manager. A change
+ * reads the file, changes that copy and writes the whole file back over the old one, and the
+ * certificate manager keeps the copy it read last. Replication replays the instance keys of
+ * cn=admin data on parallel threads, each of which changes the file here, and an SSL context
+ * is built from the file for every replication connection: unserialized, one of two changes
+ * is lost, and a reader finds the file half written (#1188).
+ */
+ private final Object trustStoreLock = new Object();
/** The server context. */
private ServerContext serverContext;
@@ -183,10 +192,13 @@
trustStorePIN = getTrustStorePIN(configuration, true);
final String keyStorePath = getFileForPath(trustStoreFile).getPath();
- certificateManager = new CertificateManager(keyStorePath, trustStoreType, trustStorePIN);
+ synchronized (trustStoreLock)
+ {
+ certificateManager = new CertificateManager(keyStorePath, trustStoreType, trustStorePIN);
- // Generate a self-signed certificate, if there is none.
- generateInstanceCertificateIfAbsent();
+ // Generate a self-signed certificate, if there is none.
+ generateInstanceCertificateIfAbsent();
+ }
// Construct the trust store base entry.
LinkedHashMap<ObjectClass,String> objectClasses = new LinkedHashMap<>(2);
@@ -327,7 +339,11 @@
try
{
- String[] aliases = certificateManager.getCertificateAliases();
+ String[] aliases;
+ synchronized (trustStoreLock)
+ {
+ aliases = certificateManager.getCertificateAliases();
+ }
if (aliases != null)
{
numEntries += aliases.length;
@@ -409,7 +425,11 @@
ByteString certValue;
try
{
- Certificate cert = certificateManager.getCertificate(certAlias);
+ Certificate cert;
+ synchronized (trustStoreLock)
+ {
+ cert = certificateManager.getCertificate(certAlias);
+ }
if (cert == null)
{
LocalizableMessage message = ERR_TRUSTSTORE_CERTIFICATE_NOT_FOUND.get(entryDN, certAlias);
@@ -468,7 +488,10 @@
if (parentDN.equals(getBaseDN()))
{
- addCertificate(entry);
+ synchronized (trustStoreLock)
+ {
+ addCertificate(entry);
+ }
}
else
{
@@ -494,7 +517,10 @@
throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
}
- deleteCertificate(entryDN);
+ synchronized (trustStoreLock)
+ {
+ deleteCertificate(entryDN);
+ }
}
@Override
@@ -538,7 +564,10 @@
String[] aliases = null;
try
{
- aliases = certificateManager.getCertificateAliases();
+ synchronized (trustStoreLock)
+ {
+ aliases = certificateManager.getCertificateAliases();
+ }
}
catch (KeyStoreException e)
{
@@ -772,12 +801,15 @@
if (ccr.getResultCode() == ResultCode.SUCCESS)
{
- trustStoreFile = newTrustStoreFile;
- trustStoreType = newTrustStoreType;
- trustStorePIN = newPIN;
- configuration = cfg;
- final String keyStorePath = getFileForPath(trustStoreFile).getPath();
- certificateManager = new CertificateManager(keyStorePath, trustStoreType, trustStorePIN);
+ synchronized (trustStoreLock)
+ {
+ trustStoreFile = newTrustStoreFile;
+ trustStoreType = newTrustStoreType;
+ trustStorePIN = newPIN;
+ configuration = cfg;
+ final String keyStorePath = getFileForPath(trustStoreFile).getPath();
+ certificateManager = new CertificateManager(keyStorePath, trustStoreType, trustStorePIN);
+ }
}
return ccr;
@@ -802,24 +834,28 @@
public KeyManager[] getKeyManagers()
throws DirectoryException
{
- final KeyStore keyStore = loadKeyStore();
-
- try
+ // the keys are opened with the PIN of the file they were read from, not that of a new one
+ synchronized (trustStoreLock)
{
- String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
- KeyManagerFactory keyManagerFactory =
- KeyManagerFactory.getInstance(keyManagerAlgorithm);
- keyManagerFactory.init(keyStore, trustStorePIN);
- return keyManagerFactory.getKeyManagers();
- }
- catch (Exception e)
- {
- logger.traceException(e);
+ final KeyStore keyStore = loadKeyStore();
- LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_CREATE_FACTORY.get(
- trustStoreFile, getExceptionMessage(e));
- throw new DirectoryException(DirectoryServer.getCoreConfigManager().getServerErrorResultCode(),
- message, e);
+ try
+ {
+ String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory keyManagerFactory =
+ KeyManagerFactory.getInstance(keyManagerAlgorithm);
+ keyManagerFactory.init(keyStore, trustStorePIN);
+ return keyManagerFactory.getKeyManagers();
+ }
+ catch (Exception e)
+ {
+ logger.traceException(e);
+
+ LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_CREATE_FACTORY.get(
+ trustStoreFile, getExceptionMessage(e));
+ throw new DirectoryException(DirectoryServer.getCoreConfigManager().getServerErrorResultCode(),
+ message, e);
+ }
}
}
@@ -864,16 +900,19 @@
private KeyStore loadKeyStore() throws DirectoryException
{
- try (FileInputStream inputStream = new FileInputStream(getFileForPath(trustStoreFile)))
+ synchronized (trustStoreLock)
{
- final KeyStore keyStore = KeyStore.getInstance(trustStoreType);
- keyStore.load(inputStream, trustStorePIN);
- return keyStore;
- }
- catch (Exception e)
- {
- LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_LOAD.get(trustStoreFile, getExceptionMessage(e));
- throw new DirectoryException(DirectoryServer.getCoreConfigManager().getServerErrorResultCode(), message, e);
+ try (FileInputStream inputStream = new FileInputStream(getFileForPath(trustStoreFile)))
+ {
+ final KeyStore keyStore = KeyStore.getInstance(trustStoreType);
+ keyStore.load(inputStream, trustStorePIN);
+ return keyStore;
+ }
+ catch (Exception e)
+ {
+ LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_LOAD.get(trustStoreFile, getExceptionMessage(e));
+ throw new DirectoryException(DirectoryServer.getCoreConfigManager().getServerErrorResultCode(), message, e);
+ }
}
}
@@ -925,20 +964,24 @@
public Key getKey(String alias)
throws DirectoryException
{
- KeyStore trustStore = loadKeyStore();
-
- try
+ // the key is opened with the PIN of the file it was read from, not that of a new one
+ synchronized (trustStoreLock)
{
- return trustStore.getKey(alias, trustStorePIN);
- }
- catch (Exception e)
- {
- logger.traceException(e);
+ KeyStore trustStore = loadKeyStore();
- LocalizableMessage message = ERR_TRUSTSTORE_ERROR_READING_KEY.get(
- alias, trustStoreFile, getExceptionMessage(e));
- throw new DirectoryException(DirectoryServer.getCoreConfigManager().getServerErrorResultCode(),
- message, e);
+ try
+ {
+ return trustStore.getKey(alias, trustStorePIN);
+ }
+ catch (Exception e)
+ {
+ logger.traceException(e);
+
+ LocalizableMessage message = ERR_TRUSTSTORE_ERROR_READING_KEY.get(
+ alias, trustStoreFile, getExceptionMessage(e));
+ throw new DirectoryException(DirectoryServer.getCoreConfigManager().getServerErrorResultCode(),
+ message, e);
+ }
}
}
@@ -1047,6 +1090,12 @@
}
}
}
+ catch (DirectoryException e)
+ {
+ // a refusal made above keeps its result code: an alias in use is an entry which exists,
+ // not a failure of the server
+ throw e;
+ }
catch (Exception e)
{
LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_ADD_CERT.get(
@@ -1079,6 +1128,11 @@
certificateManager.removeCertificate(certAlias);
}
+ catch (DirectoryException e)
+ {
+ // an alias not in use is an entry which does not exist, not a failure of the server
+ throw e;
+ }
catch (Exception e)
{
LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_DELETE_CERT.get(
--
Gitblit v1.10.0