mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

david_page
04.07.2007 20647a465c91a899d91fe482c81cc174a563bd70
Issue 466 (partial)
CryptoManager
More secret key stuff; testcases.
3 files modified
495 ■■■■ changed files
opends/src/server/org/opends/server/types/CryptoManager.java 324 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java 105 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java 66 ●●●● patch | view | raw | blame | history
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);
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();
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.
     */
}