From 47d00be20f4dd199f7dc444adbd070cca7642be1 Mon Sep 17 00:00:00 2001
From: david_page <david_page@localhost>
Date: Tue, 25 Sep 2007 20:27:29 +0000
Subject: [PATCH] Issue 466 (partial) Add some secret key handling code.
---
opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java | 46 +++++++++++
opends/src/server/org/opends/server/types/CryptoManager.java | 158 +++++++++++++++++++++++++++++++++++++++
2 files changed, 204 insertions(+), 0 deletions(-)
diff --git a/opends/src/server/org/opends/server/types/CryptoManager.java b/opends/src/server/org/opends/server/types/CryptoManager.java
index 5df13f2..1f63fc8a 100644
--- a/opends/src/server/org/opends/server/types/CryptoManager.java
+++ b/opends/src/server/org/opends/server/types/CryptoManager.java
@@ -56,11 +56,15 @@
import org.opends.server.api.Backend;
import org.opends.server.backends.TrustStoreBackend;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.AddOperation;
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
import static org.opends.server.util.StaticUtils.*;
import org.opends.server.util.Validator;
import org.opends.server.util.SelectableCertificateKeyManager;
+import org.opends.server.util.StaticUtils;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalSearchOperation;
/**
* This class provides the interface to the Directory Server
@@ -220,6 +224,160 @@
/**
+ * Returns this instance's instance-key public-key certificate from
+ * the local keystore (i.e., from the truststore-backend and not
+ * from the ADS backed keystore). If the certificate entry does not
+ * yet exist in the truststore backend, the truststore is signaled
+ * to initialized that entry, and the newly generated certificate
+ * is then retrieved and returned.
+ * @return This instance's instance-key public-key certificate from
+ * the local truststore backend.
+ * @throws CryptoManagerException If the certificate cannot be
+ * retrieved.
+ */
+ public byte[] getInstanceKeyCertificate()
+ throws CryptoManagerException {
+ final String DN_ADS_CERTIFICATE = ConfigConstants.ATTR_CERT_ALIAS
+ + "=" + ConfigConstants.ADS_CERTIFICATE_ALIAS + ","
+ + ConfigConstants.DN_TRUST_STORE_ROOT; // TODO: constant
+ final String FILTER_OC_INSTANCE_KEY
+ = new StringBuilder("(objectclass=")
+ .append(ConfigConstants.OC_INSTANCE_KEY)
+ .append(")").toString();
+ final String ATTR_INSTANCE_KEY_CERTIFICATE_BINARY
+ = "ds-cfg-public-key-certificate;binary";
+ final LinkedHashSet<String> requestedAttributes
+ = new LinkedHashSet<String>();
+ requestedAttributes.add(ATTR_INSTANCE_KEY_CERTIFICATE_BINARY);
+ final InternalClientConnection icc
+ = InternalClientConnection.getRootConnection();
+ byte[] certificate = null;
+ try {
+ for (int i = 0; i < 2; ++i) {
+ try {
+ /* If the entry does not exist in the instance's truststore
+ backend, add it (which induces the CryptoManager to create
+ the public-key certificate attribute), then repeat the
+ search. */
+ InternalSearchOperation searchOp = icc.processSearch(
+ DN.decode(DN_ADS_CERTIFICATE),
+ SearchScope.BASE_OBJECT,
+ DereferencePolicy.NEVER_DEREF_ALIASES,
+ /* size limit */ 0, /* time limit */ 0,
+ /* types only */ false,
+ SearchFilter.createFilterFromString(
+ FILTER_OC_INSTANCE_KEY),
+ requestedAttributes);
+ final Entry e = searchOp.getSearchEntries().getFirst();
+ /* attribute ds-cfg-public-key-certificate is a MUST in the
+ schema */
+ final List<Attribute> attrs
+ = e.getAttribute(DirectoryServer.getAttributeType(
+ ConfigConstants.ATTR_ADS_CERTIFICATE));
+ final Attribute a = attrs.get(0);
+ final AttributeValue v = a.getValues().iterator().next();
+ certificate = v.getValueBytes();
+ break;
+ }
+ catch (DirectoryException ex) {
+ if (0 == i
+ && ResultCode.NO_SUCH_OBJECT == ex.getResultCode()){
+ final Entry e = new Entry(DN.decode(DN_ADS_CERTIFICATE),
+ null, null, null);
+ final AttributeType ocAttrType
+ = DirectoryServer.getAttributeType("objectclass");
+ e.addObjectClass(new AttributeValue(ocAttrType, "top"));
+ e.addObjectClass(new AttributeValue(ocAttrType,
+ "ds-cfg-self-signed-cert-request"));
+ AddOperation addOperation = icc.processAdd(e.getDN(),
+ e.getObjectClasses(),
+ e.getUserAttributes(),
+ e.getOperationalAttributes());
+ if (ResultCode.SUCCESS != addOperation.getResultCode()) {
+ throw new DirectoryException(
+ addOperation.getResultCode(),
+ Message.raw("Failed to add entry %s.",
+ e.getDN().toString()));
+ }
+ }
+ else {
+ throw ex;
+ }
+ }
+ }
+ }
+ catch (DirectoryException ex) {
+ throw new CryptoManagerException(
+ // TODO: i18n
+ Message.raw("Failed to retrieve %s.", DN_ADS_CERTIFICATE), ex);
+ }
+ return(certificate);
+ }
+
+
+ /**
+ * Return the identifier of this instance's instance-key. An
+ * instance-key identifier is the MD5 hash of an instance's
+ * instance-key public-key certificate.
+ * @return This instance's instance-key identifier.
+ * @throws CryptoManagerException If there is a problem retrieving
+ * the instance-key public-key certificate or computing its MD5
+ * hash.
+ */
+ public byte[] getInstanceKeyID()
+ throws CryptoManagerException {
+ MessageDigest md;
+ final String mdAlgorithmName = "MD5";
+ try {
+ md = MessageDigest.getInstance(mdAlgorithmName);
+ }
+ catch (NoSuchAlgorithmException ex) {
+ throw new CryptoManagerException(
+ // TODO: i18n
+ Message.raw("Failed to get MessageDigest instance for %s",
+ mdAlgorithmName), ex);
+ }
+ return md.digest(getInstanceKeyCertificate());
+ }
+
+
+ /**
+ * Unwraps the supplied symmetric key attribute value and re-wraps
+ * it with the public key referred to by the requested instance key
+ * identifier. The symmetric key attribute must be wrapped in this
+ * instance's instance-key-pair public key.
+ * @param symmetricKeyAttribute The symmetric key attribute value to
+ * unwrap and rewrap.
+ * @param requestedInstanceKeyID The key identifier of the public
+ * key to use in the re-wrapping.
+ * @return The symmetric key re-wrapped in the requested public key.
+ * @throws CryptoManagerException If there is a problem unwrapping
+ * the supplied symmetric key attribute value or retrieving the
+ * requested public key.
+ */
+ public byte[] rewrapSymmetricKeyAttribute(
+ final byte[] symmetricKeyAttribute,
+ final byte[] requestedInstanceKeyID)
+ throws CryptoManagerException {
+ final byte[] instanceKeyID = getInstanceKeyID();
+ final byte[] keyIDPrefix = Arrays.copyOf(symmetricKeyAttribute,
+ instanceKeyID.length);
+ if (! Arrays.equals(keyIDPrefix, instanceKeyID)) {
+ throw new CryptoManagerException(
+ // TODO: i18n
+ Message.raw("The instance-key identifier tag %s of" +
+ " the supplied symmetric key attribute does" +
+ " not match this instance's instance-key" +
+ " identifier %s, and hence the symmetric key" +
+ " cannot be decrypted for processing.",
+ StaticUtils.bytesToColonDelimitedHex(keyIDPrefix),
+ StaticUtils.bytesToColonDelimitedHex(instanceKeyID)));
+ }
+ return symmetricKeyAttribute; // TODO: really unwrap and rewrap
+ }
+
+
+ /**
* Retrieves the name of the preferred message digest algorithm.
*
* @return The name of the preferred message digest algorithm
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java
index c139d10..b95a609 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java
@@ -34,6 +34,8 @@
import org.opends.server.TestCaseUtils;
import org.opends.server.core.DirectoryServer;
+import org.opends.admin.ads.ServerDescriptor;
+import org.opends.admin.ads.util.ConnectionUtils;
import java.io.File;
import java.io.FileInputStream;
@@ -44,6 +46,7 @@
import java.util.LinkedList;
import java.util.Arrays;
import java.lang.reflect.Method;
+import java.security.MessageDigest;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -51,6 +54,9 @@
import org.testng.annotations.DataProvider;
import javax.crypto.Mac;
+import javax.naming.directory.*;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.InitialLdapContext;
/**
This class tests the CryptoManager.
@@ -78,6 +84,42 @@
@Test
+ public void testGetInstanceKeyCertificate()
+ throws Exception {
+ final CryptoManager cm = DirectoryServer.getCryptoManager();
+ final byte[] cert = cm.getInstanceKeyCertificate();
+ assertNotNull(cert);
+
+ // The certificate should now be accessible in the truststore backend via LDAP.
+ final InitialLdapContext ctx = ConnectionUtils.createLdapContext(
+ "ldap://" + "127.0.0.1" + ":"
+ + String.valueOf(TestCaseUtils.getServerLdapPort()),
+ "cn=Directory Manager", "password",
+ ConnectionUtils.getDefaultLDAPTimeout(), null);
+ // TODO: the below dn should be in ConfigConstants
+ final String dnStr = "ds-cfg-key-id=ads-certificate,cn=ads-truststore";
+ final LdapName dn = new LdapName(dnStr);
+ final SearchControls searchControls = new SearchControls();
+ searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
+ final String attrIDs[] = { "ds-cfg-public-key-certificate;binary" };
+ searchControls.setReturningAttributes(attrIDs);
+ final SearchResult certEntry = ctx.search(dn,
+ "(objectclass=ds-cfg-instance-key)", searchControls).next();
+ final javax.naming.directory.Attribute certAttr
+ = certEntry.getAttributes().get(attrIDs[0]);
+ /* attribute ds-cfg-public-key-certificate is a MUST in the schema */
+ assertNotNull(certAttr);
+ byte[] ldapCert = (byte[])certAttr.get();
+ // Compare the certificate values.
+ assertTrue(Arrays.equals(ldapCert, cert));
+
+ // Compare the MD5 hash of the LDAP attribute with the one
+ // retrieved from the CryptoManager.
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ assertTrue(Arrays.equals(md.digest(ldapCert), cm.getInstanceKeyID()));
+ }
+
+ @Test
public void testMacSuccess()
throws Exception {
final CryptoManager cm = DirectoryServer.getCryptoManager();
@@ -94,6 +136,7 @@
assertTrue(Arrays.equals(calculatedSignature, signedHash));
}
+ // TODO: other-than-default MAC
/**
Cipher parameters
@@ -249,4 +292,7 @@
// ignore - requires Java 6
}
}
+
+ // TODO: ensure ciphers using IV output differs for successive
+ // encryptions of the same clear-text.
}
--
Gitblit v1.10.0