From 92de86f477ec7fd109aeaa0e5a2fd14714ff39d8 Mon Sep 17 00:00:00 2001
From: david_page <david_page@localhost>
Date: Thu, 04 Oct 2007 20:07:29 +0000
Subject: [PATCH] Issue 466 (partial) CryptoManager More secret key stuff; testcases.
---
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java | 66 ++++++-
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java | 105 +++++++++--
opendj-sdk/opends/src/server/org/opends/server/types/CryptoManager.java | 324 ++++++++++++++++++++++++-----------
3 files changed, 361 insertions(+), 134 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/CryptoManager.java b/opendj-sdk/opends/src/server/org/opends/server/types/CryptoManager.java
index 7bc6388..e94d9fa 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/CryptoManager.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/CryptoManager.java
@@ -49,12 +49,12 @@
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509ExtendedKeyManager;
-import org.opends.server.config.ConfigException;
-import org.opends.server.config.ConfigConstants;
-
+import org.opends.admin.ads.ADSContext;
import org.opends.server.admin.std.server.CryptoManagerCfg;
import org.opends.server.api.Backend;
import org.opends.server.backends.TrustStoreBackend;
+import org.opends.server.config.ConfigException;
+import org.opends.server.config.ConfigConstants;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.AddOperation;
import static org.opends.server.loggers.debug.DebugLogger.*;
@@ -70,7 +70,6 @@
import org.opends.server.schema.DirectoryStringSyntax;
import org.opends.server.schema.IntegerSyntax;
import org.opends.server.schema.BinarySyntax;
-import org.opends.admin.ads.ADSContext;
/**
* This class provides the interface to the Directory Server
@@ -103,11 +102,15 @@
private static AttributeType attrInitVectorLength;
private static AttributeType attrKeyLength;
private static AttributeType attrCompromisedTime;
+ private static ObjectClass ocInstanceKey;
private static ObjectClass ocCipherKey;
private static ObjectClass ocMacKey;
- // The DN of the administration suffix.
- private static DN adminSuffixDN;
+ // The DN of the local truststore backend.
+ private static DN localTruststoreDN;
+
+ // The DN of the ADS instance keys container.
+ private static DN instanceKeysDN;
// The DN of the ADS secret keys container.
private static DN secretKeysDN;
@@ -199,6 +202,8 @@
ConfigConstants.ATTR_CRYPTO_KEY_LENGTH_BITS);
attrCompromisedTime = DirectoryServer.getAttributeType(
ConfigConstants.ATTR_CRYPTO_KEY_COMPROMISED_TIME);
+ ocInstanceKey = DirectoryServer.getObjectClass(
+ ConfigConstants.OC_CRYPTO_INSTANCE_KEY);
ocCipherKey = DirectoryServer.getObjectClass(
ConfigConstants.OC_CRYPTO_CIPHER_KEY);
ocMacKey = DirectoryServer.getObjectClass(
@@ -206,8 +211,12 @@
try
{
- adminSuffixDN = DN.decode(
- ADSContext.getAdministrationSuffixDN());
+ localTruststoreDN
+ = DN.decode(ConfigConstants.DN_TRUST_STORE_ROOT);
+ DN adminSuffixDN = DN.decode(
+ ADSContext.getAdministrationSuffixDN());
+ instanceKeysDN = adminSuffixDN.concat(
+ DN.decode("cn=instance keys"));
secretKeysDN = adminSuffixDN.concat(
DN.decode("cn=secret keys"));
}
@@ -334,84 +343,86 @@
* @throws CryptoManagerException If the certificate cannot be
* retrieved.
*/
- public byte[] getInstanceKeyCertificate()
- throws CryptoManagerException {
- final String DN_ADS_CERTIFICATE =
- ConfigConstants.ATTR_CRYPTO_KEY_ID
- + "=" + ConfigConstants.ADS_CERTIFICATE_ALIAS + ","
- + ConfigConstants.DN_TRUST_STORE_ROOT; // TODO: constant
- final String FILTER_OC_INSTANCE_KEY
- = new StringBuilder("(objectclass=")
- .append(ConfigConstants.OC_CRYPTO_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(attrPublicKeyCertificate);
- 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);
- }
+ public byte[] getInstanceKeyCertificateFromLocalTruststore()
+ throws CryptoManagerException {
+ // Construct the key entry DN.
+ final AttributeValue distinguishedValue = new AttributeValue(
+ attrKeyID, ConfigConstants.ADS_CERTIFICATE_ALIAS);
+ final DN entryDN = localTruststoreDN.concat(
+ RDN.create(attrKeyID, distinguishedValue));
+ // Construct the search filter.
+ final String FILTER_OC_INSTANCE_KEY =
+ new StringBuilder("(objectclass=")
+ .append(ocInstanceKey.getNameOrOID())
+ .append(")").toString();
+ // Construct the attribute list.
+ final LinkedHashSet<String> requestedAttributes
+ = new LinkedHashSet<String>();
+ requestedAttributes.add(attrPublicKeyCertificate.getNameOrOID());
+
+ // Retrieve the certificate from the entry.
+ 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(
+ entryDN,
+ SearchScope.BASE_OBJECT,
+ DereferencePolicy.NEVER_DEREF_ALIASES,
+ /* size limit */ 0, /* time limit */ 0,
+ /* types only */ false,
+ SearchFilter.createFilterFromString(
+ FILTER_OC_INSTANCE_KEY),
+ requestedAttributes);
+ for (Entry e : searchOp.getSearchEntries()) {
+ /* attribute ds-cfg-public-key-certificate is a MUST in
+ the schema */
+ certificate = e.getAttributeValue(
+ attrPublicKeyCertificate, BinarySyntax.DECODER);
+ break;
+ }
+ break;
+ }
+ catch (DirectoryException ex) {
+ if (0 == i
+ && ResultCode.NO_SUCH_OBJECT == ex.getResultCode()){
+ final Entry e = new Entry(entryDN, 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.", entryDN.toString()),
+ ex);
+ }
+ return(certificate);
+ }
/**
@@ -426,7 +437,8 @@
*/
public String getInstanceKeyID()
throws CryptoManagerException {
- return getInstanceKeyID(getInstanceKeyCertificate());
+ return getInstanceKeyID(
+ getInstanceKeyCertificateFromLocalTruststore());
}
@@ -460,12 +472,117 @@
/**
+ Publishes the instance key entry in ADS, if it does not already
+ exist.
+
+ TODO: The ADS configuration retrieves an instance's instance key
+ certificate via ServerDescriptor and publishes it via ADSContext in
+ that instance's ADS suffix (in the case a stand-alone instance is
+ being configured) or in an existing ADS suffix (in the case the
+ instance is being added to an existing ADS domain). Instead, have
+ the instance call this routine at startup (after the backends and
+ CryptoManager have been initialized), and change ADS configuration
+ to retrieve the instance key from the ADS suffix in the second
+ case, above (the first case would be unecessary).
+
+ @throws CryptoManagerException In case there is a problem
+ searching for the entry, or, if necessary, adding it.
+
+ @see org.opends.admin.ads.ServerDescriptor
+ #updatePublicKeyCertificate(
+ org.opends.admin.ads.ServerDescriptor,
+ javax.naming.ldap.InitialLdapContext)
+
+ @see org.opends.admin.ads.ADSContext
+ #registerInstanceKeyCertificate(
+ java.util.Map, javax.naming.ldap.LdapName)
+ */
+ public void publishInstanceKeyEntryInADS()
+ throws CryptoManagerException {
+ final byte[] instanceKeyCertificate
+ = getInstanceKeyCertificateFromLocalTruststore();
+ final String instanceKeyID
+ = getInstanceKeyID(instanceKeyCertificate);
+ // Construct the key entry DN.
+ final AttributeValue distinguishedValue =
+ new AttributeValue(attrKeyID, instanceKeyID);
+ final DN entryDN = instanceKeysDN.concat(
+ RDN.create(attrKeyID, distinguishedValue));
+ // Construct the search filter.
+ final String FILTER_OC_INSTANCE_KEY =
+ new StringBuilder("(objectclass=")
+ .append(ocInstanceKey.getNameOrOID())
+ .append(")").toString();
+ // Construct the attribute list.
+ final LinkedHashSet<String> requestedAttributes
+ = new LinkedHashSet<String>();
+ requestedAttributes.add("dn");
+
+ // Check for the entry. If it does not exist, create it.
+ final InternalClientConnection icc
+ = InternalClientConnection.getRootConnection();
+ try {
+ final InternalSearchOperation searchOp
+ = icc.processSearch( entryDN, SearchScope.BASE_OBJECT,
+ DereferencePolicy.NEVER_DEREF_ALIASES,
+ /* size limit */ 0, /* time limit */ 0,
+ /* types only */ false,
+ SearchFilter.createFilterFromString(
+ FILTER_OC_INSTANCE_KEY),
+ requestedAttributes);
+ if (0 == searchOp.getSearchEntries().size()) {
+ final Entry e = new Entry(entryDN, null, null, null);
+ e.addObjectClass(DirectoryServer.getTopObjectClass());
+ e.addObjectClass(ocInstanceKey);
+ // Add the key ID attribute.
+ final LinkedHashSet<AttributeValue> keyIDValueSet =
+ new LinkedHashSet<AttributeValue>(1);
+ keyIDValueSet.add(distinguishedValue);
+ final Attribute keyIDAttr = new Attribute(
+ attrKeyID,
+ attrKeyID.getNameOrOID(),
+ keyIDValueSet);
+ e.addAttribute(keyIDAttr, new ArrayList<AttributeValue>(0));
+ // Add the public key certificate attribute.
+ final LinkedHashSet<AttributeValue> certificateValueSet =
+ new LinkedHashSet<AttributeValue>(1);
+ final AttributeValue certificateValue = new AttributeValue(
+ attrPublicKeyCertificate,
+ ByteStringFactory.create(instanceKeyCertificate));
+ certificateValueSet.add(certificateValue);
+ final Attribute certificateAttr = new Attribute(
+ attrPublicKeyCertificate,
+ attrPublicKeyCertificate.getNameOrOID(),
+ certificateValueSet);
+ e.addAttribute(certificateAttr,
+ new ArrayList<AttributeValue>(0));
+
+ 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()));
+ }
+ }
+ } catch (DirectoryException ex) {
+ throw new CryptoManagerException(
+ // TODO: i18n
+ Message.raw("Failed to publish %s.", entryDN.toString()), ex);
+ }
+ }
+
+
+ /**
Return the set of valid (i.e., not tagged as compromised) instance
key-pair public-key certificate entries in ADS.
@return The set of valid (i.e., not tagged as compromised) instance
key-pair public-key certificate entries in ADS represented as a Map
- from ds-cfg-key-id value to ds-cfg-public-key-certificate;binary
- value. Note that the collection might be empty.
+ from ds-cfg-key-id value to ds-cfg-public-key-certificate value.
+ Note that the collection might be empty.
@throws CryptoManagerException In case of a problem with the
search operation.
@see org.opends.admin.ads.ADSContext#getTrustedCertificates()
@@ -474,9 +591,8 @@
throws CryptoManagerException {
final Map<String, byte[]> certificateMap
= new HashMap<String, byte[]>();
- final String baseDNStr = ADSContext.getInstanceKeysContainerDN();
try {
- final DN baseDN = DN.decode(baseDNStr);
+ // Construct the search filter.
final String FILTER_OC_INSTANCE_KEY
= new StringBuilder("(objectclass=")
.append(ConfigConstants.OC_CRYPTO_INSTANCE_KEY)
@@ -488,24 +604,24 @@
.append(FILTER_OC_INSTANCE_KEY)
.append(FILTER_NOT_COMPROMISED)
.append(")").toString();
+ // Construct the attribute list.
final LinkedHashSet<String> requestedAttributes
= new LinkedHashSet<String>();
requestedAttributes.add(ConfigConstants.ATTR_CRYPTO_KEY_ID);
- final String ATTR_INSTANCE_KEY_CERTIFICATE_BINARY
- = ConfigConstants.ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE
- + ";binary";
- requestedAttributes.add(ATTR_INSTANCE_KEY_CERTIFICATE_BINARY);
+ requestedAttributes.add(
+ attrPublicKeyCertificate.getNameOrOID());
+ // Invoke the search operation.
final InternalClientConnection icc
= InternalClientConnection.getRootConnection();
InternalSearchOperation searchOp = icc.processSearch(
- baseDN,
+ instanceKeysDN,
SearchScope.SINGLE_LEVEL,
DereferencePolicy.NEVER_DEREF_ALIASES,
/* size limit */ 0, /* time limit */ 0,
/* types only */ false,
SearchFilter.createFilterFromString(searchFilter),
requestedAttributes);
-
+ // Evaluate the search response.
for (Entry e : searchOp.getSearchEntries()) {
/* attribute ds-cfg-key-id is the RDN and attribute
ds-cfg-public-key-certificate is a MUST in the schema */
@@ -521,7 +637,7 @@
// TODO: i18n
Message.raw("Error retrieving instance-key public key" +
" certificates from ADS container %s.",
- baseDNStr), ex);
+ instanceKeysDN.toString()), ex);
}
return(certificateMap);
}
@@ -742,15 +858,16 @@
final SecretKey secretKey
= decodeSymmetricKeyAttribute(symmetricKeyAttribute);
final Map<String, byte[]> certMap = getTrustedCertificates();
- if (! certMap.containsKey(requestedInstanceKeyID)) {
+ if (! (certMap.containsKey(requestedInstanceKeyID)
+ && null != certMap.get(requestedInstanceKeyID))) {
throw new CryptoManagerException(
// TODO: i18n
Message.raw("The public key certificate specified by" +
" the identifier %s cannot be found.",
requestedInstanceKeyID));
}
- final byte[] wrappingKeyCert
- = certMap.get(requestedInstanceKeyID);
+ final byte[] wrappingKeyCert =
+ certMap.get(requestedInstanceKeyID);
return encodeSymmetricKeyAttribute(
requestedInstanceKeyID, wrappingKeyCert, secretKey);
}
@@ -2220,7 +2337,7 @@
// Need to add our own instance certificate.
byte[] instanceKeyCertificate =
- cryptoManager.getInstanceKeyCertificate();
+ cryptoManager.getInstanceKeyCertificateFromLocalTruststore();
trustedCerts.put(getInstanceKeyID(instanceKeyCertificate),
instanceKeyCertificate);
@@ -2263,6 +2380,7 @@
}
}
+
/**
* Initializes a secret key entry from the supplied parameters,
* validates it, and registers it in the supplied map. The
@@ -2684,7 +2802,7 @@
// Need to add our own instance certificate.
byte[] instanceKeyCertificate =
- cryptoManager.getInstanceKeyCertificate();
+ cryptoManager.getInstanceKeyCertificateFromLocalTruststore();
trustedCerts.put(getInstanceKeyID(instanceKeyCertificate),
instanceKeyCertificate);
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java
index a76eebd..9464bd5 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java
@@ -30,16 +30,22 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.CryptoManager;
+import org.opends.server.schema.DirectoryStringSyntax;
+import org.opends.server.config.ConfigConstants;
+import org.opends.server.types.*;
import org.opends.server.core.ExtendedOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.util.ServerConstants;
+import org.opends.server.util.TimeThread;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.admin.ads.ADSContext;
import static org.testng.Assert.*;
import static org.testng.Assert.assertEquals;
+import java.util.LinkedHashSet;
+
/**
* A set of test cases for the symmetric key extended operation.
*/
@@ -60,32 +66,93 @@
- @Test(enabled=false)
+ @Test(enabled=true)
public void testValidRequest() throws Exception
{
- CryptoManager cm = DirectoryServer.getCryptoManager();
+ final CryptoManager cm = DirectoryServer.getCryptoManager();
+ final String secretMessage = "zyxwvutsrqponmlkjihgfedcba";
+ final String cipherTransformationName = "AES/CBC/PKCS5Padding";
+ final int cipherKeyLength = 128;
- // TODO use a proper symmetric key value
- String symmetricKey = cm.getInstanceKeyID();
- String instanceKeyID = cm.getInstanceKeyID();
+ cm.publishInstanceKeyEntryInADS();
- ASN1OctetString requestValue =
- GetSymmetricKeyExtendedOperation.encodeRequestValue(
- symmetricKey, instanceKeyID);
+ // Initial encryption ensures a cipher key entry is in ADS.
+ final byte[] cipherText = cm.encrypt(cipherTransformationName,
+ cipherKeyLength, secretMessage.getBytes());
- InternalClientConnection internalConnection =
+ // Retrieve all uncompromised cipher key entries corresponding to the
+ // specified transformation and key length.
+ final String baseDNStr // TODO: is this DN defined elsewhere as a constant?
+ = "cn=secret keys," + ADSContext.getAdministrationSuffixDN();
+ final DN baseDN = DN.decode(baseDNStr);
+ final String FILTER_OC_INSTANCE_KEY
+ = new StringBuilder("(objectclass=")
+ .append(ConfigConstants.OC_CRYPTO_CIPHER_KEY)
+ .append(")").toString();
+ final String FILTER_NOT_COMPROMISED = new StringBuilder("(!(")
+ .append(ConfigConstants.ATTR_CRYPTO_KEY_COMPROMISED_TIME)
+ .append("=*))").toString();
+ final String FILTER_CIPHER_TRANSFORMATION_NAME = new StringBuilder("(")
+ .append(ConfigConstants.ATTR_CRYPTO_CIPHER_TRANSFORMATION_NAME)
+ .append("=").append(cipherTransformationName)
+ .append(")").toString();
+ final String FILTER_CIPHER_KEY_LENGTH = new StringBuilder("(")
+ .append(ConfigConstants.ATTR_CRYPTO_KEY_LENGTH_BITS)
+ .append("=").append(String.valueOf(cipherKeyLength))
+ .append(")").toString();
+ final String searchFilter = new StringBuilder("(&")
+ .append(FILTER_OC_INSTANCE_KEY)
+ .append(FILTER_NOT_COMPROMISED)
+ .append(FILTER_CIPHER_TRANSFORMATION_NAME)
+ .append(FILTER_CIPHER_KEY_LENGTH)
+ .append(")").toString();
+ final LinkedHashSet<String> requestedAttributes
+ = new LinkedHashSet<String>();
+ requestedAttributes.add(ConfigConstants.ATTR_CRYPTO_SYMMETRIC_KEY);
+ final InternalClientConnection icc
+ = InternalClientConnection.getRootConnection();
+ InternalSearchOperation searchOp = icc.processSearch(
+ baseDN,
+ SearchScope.SINGLE_LEVEL,
+ DereferencePolicy.NEVER_DEREF_ALIASES,
+ /* size limit */ 0, /* time limit */ 0,
+ /* types only */ false,
+ SearchFilter.createFilterFromString(searchFilter),
+ requestedAttributes);
+ assertTrue(0 < searchOp.getSearchEntries().size());
+
+ final InternalClientConnection internalConnection =
InternalClientConnection.getRootConnection();
- ExtendedOperation extendedOperation =
- internalConnection.processExtendedOperation(
- ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP, requestValue);
-
- assertEquals(extendedOperation.getResultCode(), ResultCode.SUCCESS);
- assertEquals(extendedOperation.getResponseValue().stringValue(),
- symmetricKey);
+ final String instanceKeyID = cm.getInstanceKeyID();
+ final AttributeType attrSymmetricKey = DirectoryServer.getAttributeType(
+ ConfigConstants.ATTR_CRYPTO_SYMMETRIC_KEY);
+ for (Entry e : searchOp.getSearchEntries()) {
+ final String symmetricKeyAttributeValue
+ = e.getAttributeValue(attrSymmetricKey, DirectoryStringSyntax.DECODER);
+ final ASN1OctetString requestValue =
+ GetSymmetricKeyExtendedOperation.encodeRequestValue(
+ symmetricKeyAttributeValue, instanceKeyID);
+ final ExtendedOperation extendedOperation =
+ internalConnection.processExtendedOperation(
+ ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP,
+ requestValue);
+ assertEquals(extendedOperation.getResultCode(), ResultCode.SUCCESS);
+ // The key should be re-wrapped, and hence have a different binary
+ // representation....
+ final String responseValue
+ = extendedOperation.getResponseValue().stringValue();
+ assertFalse(symmetricKeyAttributeValue.equals(responseValue));
+ // ... but the keyIDs should be equal (ideally, the validity of
+ // the returned value would be checked by decoding the
+ // returned ds-cfg-symmetric-key attribute value; however, there
+ // is no non-private method to call.
+ assertEquals(responseValue.split(":")[0],
+ symmetricKeyAttributeValue.split(":")[0]);
+ }
}
- @Test(enabled=false)
+ @Test()
public void testInvalidRequest() throws Exception
{
CryptoManager cm = DirectoryServer.getCryptoManager();
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java
index 973cf74..a07c4be 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java
@@ -85,8 +85,7 @@
*/
@AfterClass()
public void CleanUp() throws Exception {
- DirectoryServer.restart(this.getClass().getName(),
- Message.raw("CryptoManager: clean-up internal key caches."));
+ // TODO: remove at least secret key entries added in this exercise.
}
@@ -94,7 +93,7 @@
public void testGetInstanceKeyCertificate()
throws Exception {
final CryptoManager cm = DirectoryServer.getCryptoManager();
- final byte[] cert = cm.getInstanceKeyCertificate();
+ final byte[] cert = cm.getInstanceKeyCertificateFromLocalTruststore();
assertNotNull(cert);
// The certificate should now be accessible in the truststore backend via LDAP.
@@ -103,7 +102,7 @@
+ String.valueOf(TestCaseUtils.getServerLdapPort()),
"cn=Directory Manager", "password",
ConnectionUtils.getDefaultLDAPTimeout(), null);
- // TODO: the below dn should be in ConfigConstants
+ // TODO: should the below dn 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();
@@ -125,6 +124,10 @@
MessageDigest md = MessageDigest.getInstance("MD5");
assertTrue(StaticUtils.bytesToHexNoSpace(
md.digest(ldapCert)).equals(cm.getInstanceKeyID()));
+
+ // Call twice to ensure idempotent.
+ cm.publishInstanceKeyEntryInADS();
+ cm.publishInstanceKeyEntryInADS();
}
@Test
@@ -342,12 +345,14 @@
/**
- Mark a key compromised; ensure 1) subsequent encryption requests use a new
- key; 2) ciphertext produced using the compromised key can still be decrypted.
+ Mark a key compromised; ensure 1) subsequent encryption requests use a
+ new key; 2) ciphertext produced using the compromised key can still be
+ decrypted; 3) once the compromised key entry is removed, confirm ciphertext
+ produced using the compromised key can no longer be decrypted.
@throws Exception In case something exceptional happens.
*/
- @Test(enabled=true)
+ @Test()
public void testCompromisedKey() throws Exception {
final CryptoManager cm = DirectoryServer.getCryptoManager();
final String secretMessage = "zyxwvutsrqponmlkjihgfedcba";
@@ -360,7 +365,7 @@
// Retrieve all uncompromised cipher key entries corresponding to the
// specified transformation and key length. Mark each entry compromised.
- final String baseDNStr // TODO: is this DN a constant?
+ final String baseDNStr // TODO: is this DN defined elsewhere as a constant?
= "cn=secret keys," + ADSContext.getAdministrationSuffixDN();
final DN baseDN = DN.decode(baseDNStr);
final String FILTER_OC_INSTANCE_KEY
@@ -397,8 +402,8 @@
/* types only */ false,
SearchFilter.createFilterFromString(searchFilter),
requestedAttributes);
-
assertTrue(0 < searchOp.getSearchEntries().size());
+
String compromisedTime = TimeThread.getGeneralizedTime();
for (Entry e : searchOp.getSearchEntries()) {
TestCaseUtils.applyModifications(
@@ -414,18 +419,55 @@
final byte[] cipherText2 = cm.encrypt(cipherTransformationName,
cipherKeyLength, secretMessage.getBytes());
- // test for identical keys
+ // 1. Test for distinct keys.
final byte[] keyID = new byte[16];
final byte[] keyID2 = new byte[16];
System.arraycopy(cipherText, 0, keyID, 0, 16);
System.arraycopy(cipherText2, 0, keyID2, 0, 16);
assertTrue(! Arrays.equals(keyID, keyID2));
- // confirm ciphertext produced using compromised key can still
- // be decrypted.
+ // 2. Confirm ciphertext produced using the compromised key can still be
+ // decrypted.
final byte[] plainText = cm.decrypt(cipherText);
assertEquals((new String(plainText)), secretMessage);
+ // 3. Delete the compromised entry(ies) and ensure ciphertext produced
+ // using a compromised key can no longer be decrypted.
+ for (Entry e : searchOp.getSearchEntries()) {
+ TestCaseUtils.applyModifications(
+ "dn: " + e.getDN().toNormalizedString(),
+ "changetype: delete");
+ }
+ Thread.sleep(1000); // Clearing the cache is asynchronous.
+ try {
+ cm.decrypt(cipherText);
+ }
+ catch (CryptoManager.CryptoManagerException ex) {
+ // TODO: if reasons are added to CryptoManagerException, check for
+ // expected cause.
+ }
}
+ /**
+ TODO: Test the secret key synchronization protocol.
+
+ 1. Create the first instance; add reversible password storage scheme
+ to password policy; add entry using explicit password policy; confirm
+ secret key entry has been produced.
+
+ 2. Create and initialize the second instance into the existing ADS domain.
+ The secret key entries should be propagated to the second instance via
+ replication. Then the new instance should detect that the secret key
+ entries are missing ds-cfg-symmetric-key attribute values for that
+ instance, inducing the key synchronization protocol.
+
+ 3. Confirm the second instance can decrypt the password of the entry
+ added in step 1; e.g., bind as that user.
+
+ 4. Stop the second instance. At the first instance, enable a different
+ reversible password storage scheme (different cipher transformation,
+ and hence secret key entry); add another entry using that password
+ storage scheme; start the second instance; ensure the password can
+ be decrypted at the second instance.
+ */
}
--
Gitblit v1.10.0