From b93c8bf6f5bb9560e9ba219eb6be1ea9bb12f3be Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Thu, 26 May 2016 11:15:14 +0000
Subject: [PATCH] OPENDJ-3027 Delete all references to old keys when importing new ones via replication

---
 opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java     |   14 ++++++++++++--
 opendj-server-legacy/src/test/java/org/opends/server/crypto/CryptoManagerTestCase.java |   37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
index 958f159..3e546dc 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
@@ -1640,7 +1640,12 @@
       }
       getCipher(keyEntry, Cipher.DECRYPT_MODE, iv);
 
-      // Cache new entry.
+      // Cache new entry, make sure it is the only one using the given transformation / key length.
+      CipherKeyEntry oldKeyEntry = getKeyEntry(cryptoManager, transformation, secretKeyLengthBits);
+      if (oldKeyEntry != null)
+      {
+        cryptoManager.cipherKeyEntryCache.remove(oldKeyEntry.getKeyID());
+      }
       cryptoManager.cipherKeyEntryCache.put(keyEntry.getKeyID(), keyEntry);
 
       return keyEntry;
@@ -2097,7 +2102,12 @@
       // Validate new entry.
       getMacEngine(keyEntry);
 
-      // Cache new entry.
+      // Cache new entry, make sure it is the only one using the given transformation / key length.
+      MacKeyEntry oldKeyEntry = getKeyEntry(cryptoManager, algorithm, secretKeyLengthBits);
+      if (oldKeyEntry != null)
+      {
+        cryptoManager.macKeyEntryCache.remove(oldKeyEntry.getKeyID());
+      }
       cryptoManager.macKeyEntryCache.put(keyEntry.getKeyID(),
               keyEntry);
 
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/crypto/CryptoManagerTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/crypto/CryptoManagerTestCase.java
index 6a4362d..765c86c 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/crypto/CryptoManagerTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/crypto/CryptoManagerTestCase.java
@@ -24,6 +24,7 @@
 import java.security.MessageDigest;
 import java.util.Arrays;
 import java.util.List;
+import java.util.UUID;
 
 import javax.crypto.Mac;
 
@@ -33,6 +34,7 @@
 import org.opends.admin.ads.ADSContext;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.protocols.ldap.LDAPAttribute;
@@ -41,19 +43,24 @@
 import org.opends.server.types.CryptoManager;
 import org.opends.server.types.CryptoManagerException;
 import org.forgerock.opendj.ldap.DN;
+import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
 import org.opends.server.util.EmbeddedUtils;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.TimeThread;
+import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import static org.assertj.core.api.Assertions.*;
+import static org.forgerock.opendj.ldap.ModificationType.*;
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.protocols.internal.Requests.*;
+import static org.opends.server.types.Attributes.create;
 import static org.testng.Assert.*;
 
 /**
@@ -74,6 +81,36 @@
     TestCaseUtils.restartServer();
   }
 
+  @Test(expectedExceptions = CryptoManagerException.class)
+  public void testImportKeysReplacesExistingKeys()
+      throws Exception {
+    final CryptoManagerImpl cm = DirectoryServer.getCryptoManager();
+    final int keyLength = 56;
+    final String cipher = "DES/CFB/NoPadding";
+    byte[] cipherText = cm.encrypt(cipher, keyLength, new byte[56]);
+    Entry oldKey = getKeyForCipher(cipher, keyLength);
+    // Force import by changing the keyID
+    Modification mod = new Modification(REPLACE, create("ds-cfg-key-id", UUID.randomUUID().toString()));
+    oldKey.applyModification(mod);
+    cm.importCipherKeyEntry(oldKey);
+    try
+    {
+      cm.decrypt(cipherText);
+      Assert.fail("Was expecting a CryptoManager exception, the key should be invalid.");
+    }
+    finally
+    {
+    }
+  }
+
+  private Entry getKeyForCipher(String cipher, int keyLength) throws DirectoryException
+  {
+    SearchRequest request = newSearchRequest("cn=secret keys, cn=admin data", SearchScope.WHOLE_SUBTREE,
+        "&(ds-cfg-cipher-transformation-name=" + cipher + ")(ds-cfg-key-length-bits=" + keyLength + ")");
+    InternalClientConnection conn = getRootConnection();
+    InternalSearchOperation search = conn.processSearch(request);
+    return search.getSearchEntries().get(0);
+  }
 
   @Test
   public void testGetInstanceKeyCertificate()

--
Gitblit v1.10.0