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

david_page
25.27.2007 47d00be20f4dd199f7dc444adbd070cca7642be1
Issue 466 (partial)
Add some secret key handling code.
2 files modified
204 ■■■■■ changed files
opends/src/server/org/opends/server/types/CryptoManager.java 158 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/CryptoManagerTestCase.java 46 ●●●●● patch | view | raw | blame | history
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
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.
}