From 58841cd1273d5238691e74b1d9f44318486fe42a Mon Sep 17 00:00:00 2001
From: coulbeck <coulbeck@localhost>
Date: Tue, 25 Sep 2007 22:11:45 +0000
Subject: [PATCH] Implement Get Symmetric Key Extended Operation for crypto manager symmetric key distribution.

---
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java |  111 +++++++++++++
 opends/src/messages/messages/backend.properties                                                                      |    2 
 opends/src/server/org/opends/server/backends/TrustStoreBackend.java                                                  |   58 +++++++
 opends/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperation.java                                 |  266 +++++++++++++++++++++++++++++++++
 opends/resource/config/config.ldif                                                                                   |    7 
 opends/src/messages/messages/extension.properties                                                                    |    9 +
 opends/src/server/org/opends/server/util/ServerConstants.java                                                        |    8 +
 7 files changed, 461 insertions(+), 0 deletions(-)

diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index df90bcc..9b60f5f 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -539,6 +539,13 @@
 ds-cfg-extended-operation-handler-class: org.opends.server.extensions.StartTLSExtendedOperation
 ds-cfg-extended-operation-handler-enabled: true
 
+dn: cn=Get Symmetric Key,cn=Extended Operations,cn=config
+objectClass: top
+objectClass: ds-cfg-extended-operation-handler
+cn: Get Symmetric Key
+ds-cfg-extended-operation-handler-class: org.opends.server.extensions.GetSymmetricKeyExtendedOperation
+ds-cfg-extended-operation-handler-enabled: true
+
 dn: cn=Who Am I,cn=Extended Operations,cn=config
 objectClass: top
 objectClass: ds-cfg-extended-operation-handler
diff --git a/opends/src/messages/messages/backend.properties b/opends/src/messages/messages/backend.properties
index 8e1fc52..71e97e1 100644
--- a/opends/src/messages/messages/backend.properties
+++ b/opends/src/messages/messages/backend.properties
@@ -1030,3 +1030,5 @@
  does not exist
 MILD_ERR_LDIF_BACKEND_NUM_SUBORDINATES_NO_SUCH_ENTRY_366=The target entry %s \
  does not exist
+SEVERE_ERR_TRUSTSTORE_ERROR_READING_KEY_367=Error reading key %s from key \
+ store %s: %s
diff --git a/opends/src/messages/messages/extension.properties b/opends/src/messages/messages/extension.properties
index dfb31a3..0fe023b 100644
--- a/opends/src/messages/messages/extension.properties
+++ b/opends/src/messages/messages/extension.properties
@@ -1589,3 +1589,12 @@
  encrypt a value using password storage scheme %s:  %s
 SEVERE_ERR_PWSCHEME_CANNOT_DECRYPT_560=An error occurred while trying to \
  decrypt a value using password storage scheme %s:  %s
+MILD_ERR_GET_SYMMETRIC_KEY_NO_VALUE_561=Cannot decode the provided \
+ symmetric key extended operation because it does not have a value
+MILD_ERR_GET_SYMMETRIC_KEY_INVALID_TYPE_562=Cannot decode the provided \
+ symmetric key extended operation because the value sequence has an element \
+ with an invalid type of %s
+MILD_ERR_GET_SYMMETRIC_KEY_ASN1_DECODE_EXCEPTION_563=Cannot decode the \
+ provided symmetric key extended request: %s
+MILD_ERR_GET_SYMMETRIC_KEY_DECODE_EXCEPTION_564=An unexpected error occurred \
+ while attempting to decode the symmetric key extended request sequence: %s
diff --git a/opends/src/server/org/opends/server/backends/TrustStoreBackend.java b/opends/src/server/org/opends/server/backends/TrustStoreBackend.java
index 4c85335..89e9c22 100644
--- a/opends/src/server/org/opends/server/backends/TrustStoreBackend.java
+++ b/opends/src/server/org/opends/server/backends/TrustStoreBackend.java
@@ -39,6 +39,7 @@
 import java.util.*;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
+import java.security.Key;
 
 import org.opends.server.api.Backend;
 import org.opends.server.config.ConfigException;
@@ -1425,6 +1426,63 @@
   }
 
 
+  /**
+   * Returns the key associated with the given alias, using the trust
+   * store pin to recover it.
+   *
+   * @param   alias The alias name.
+   *
+   * @return  The requested key, or null if the given alias does not exist
+   *          or does not identify a key-related entry.
+   *
+   * @throws  DirectoryException  If an error occurs while retrieving the key.
+   */
+  public Key getKey(String alias)
+         throws DirectoryException
+  {
+    KeyStore trustStore;
+    try
+    {
+      trustStore = KeyStore.getInstance(trustStoreType);
+
+      FileInputStream inputStream =
+           new FileInputStream(getFileForPath(trustStoreFile));
+      trustStore.load(inputStream, trustStorePIN);
+      inputStream.close();
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_TRUSTSTORE_CANNOT_LOAD.get(
+          trustStoreFile, getExceptionMessage(e));
+      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+                                   message, e);
+    }
+
+
+    try
+    {
+      return trustStore.getKey(alias, trustStorePIN);
+    }
+    catch (Exception e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message = ERR_TRUSTSTORE_ERROR_READING_KEY.get(
+           alias, trustStoreFile, getExceptionMessage(e));
+      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
+                                   message, e);
+    }
+  }
+
+
   private void addCertificate(Entry entry)
        throws DirectoryException
   {
diff --git a/opends/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperation.java b/opends/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperation.java
new file mode 100644
index 0000000..23ac4e6
--- /dev/null
+++ b/opends/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperation.java
@@ -0,0 +1,266 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.extensions;
+
+import org.opends.server.admin.std.server.ExtendedOperationHandlerCfg;
+import org.opends.server.api.ExtendedOperationHandler;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.loggers.debug.DebugLogger;
+import org.opends.server.types.*;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ExtendedOperation;
+import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.asn1.ASN1Element;
+import org.opends.server.protocols.asn1.ASN1Exception;
+import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.util.StaticUtils;
+import org.opends.server.util.ServerConstants;
+import org.opends.messages.Message;
+import static org.opends.messages.ExtensionMessages.*;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.ArrayList;
+
+/**
+ * This class implements the get symmetric key extended operation, an OpenDS
+ * proprietary extension used for distribution of symmetric keys amongst
+ * servers.
+ */
+public class GetSymmetricKeyExtendedOperation
+     extends ExtendedOperationHandler<ExtendedOperationHandlerCfg>
+{
+  /**
+   * The tracer object for the debug logger.
+   */
+  private static final DebugTracer TRACER = DebugLogger.getTracer();
+
+
+
+  /**
+   * The BER type value for the symmetric key element of the operation value.
+   */
+  public static final byte TYPE_SYMMETRIC_KEY_ELEMENT = (byte) 0x80;
+
+
+
+  /**
+   * The BER type value for the instance key ID element of the operation value.
+   */
+  public static final byte TYPE_INSTANCE_KEY_ID_ELEMENT = (byte) 0x81;
+
+
+
+  // The default set of supported control OIDs for this extended operation.
+  private Set<String> supportedControlOIDs = new HashSet<String>(0);
+
+
+
+  /**
+   * Create an instance of this symmetric key extended operation.  All
+   * initialization should be performed in the
+   * <CODE>initializeExtendedOperationHandler</CODE> method.
+   */
+  public GetSymmetricKeyExtendedOperation()
+  {
+    super();
+
+  }
+
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void initializeExtendedOperationHandler(
+       ExtendedOperationHandlerCfg config)
+         throws ConfigException, InitializationException
+  {
+    supportedControlOIDs = new HashSet<String>();
+
+
+    DirectoryServer.registerSupportedExtension(
+         ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP, this);
+
+    registerControlsAndFeatures();
+  }
+
+
+
+  /**
+   * Performs any finalization that may be necessary for this extended
+   * operation handler.  By default, no finalization is performed.
+   */
+  public void finalizeExtendedOperationHandler()
+  {
+    DirectoryServer.deregisterSupportedExtension(
+         ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP);
+
+    deregisterControlsAndFeatures();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public Set<String> getSupportedControls()
+  {
+    return supportedControlOIDs;
+  }
+
+
+
+  /**
+   * Processes the provided extended operation.
+   *
+   * @param  operation  The extended operation to be processed.
+   */
+  public void processExtendedOperation(ExtendedOperation operation)
+  {
+    // Initialize the variables associated with components that may be included
+    // in the request.
+    byte[] requestSymmetricKey = null;
+    byte[] instanceKeyID       = null;
+
+
+
+    // Parse the encoded request, if there is one.
+    ByteString requestValue = operation.getRequestValue();
+    if (requestValue == null)
+    {
+      // The request must always have a value.
+      Message message = ERR_GET_SYMMETRIC_KEY_NO_VALUE.get();
+      operation.appendErrorMessage(message);
+      return;
+    }
+
+    try
+    {
+      ASN1Sequence valueSequence =
+           ASN1Sequence.decodeAsSequence(requestValue.value());
+      for (ASN1Element e : valueSequence.elements())
+      {
+        switch (e.getType())
+        {
+          case TYPE_SYMMETRIC_KEY_ELEMENT:
+            requestSymmetricKey =
+                 ASN1OctetString.decodeAsOctetString(e).value();
+            break;
+
+          case TYPE_INSTANCE_KEY_ID_ELEMENT:
+            instanceKeyID = ASN1OctetString.decodeAsOctetString(e).value();
+            break;
+
+          default:
+            Message message = ERR_GET_SYMMETRIC_KEY_INVALID_TYPE.get(
+                 StaticUtils.byteToHex(e.getType()));
+            operation.appendErrorMessage(message);
+            return;
+        }
+      }
+    }
+    catch (ASN1Exception ae)
+    {
+      if (DebugLogger.debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, ae);
+      }
+
+      Message message = ERR_GET_SYMMETRIC_KEY_ASN1_DECODE_EXCEPTION.get(
+           ae.getMessage());
+      operation.appendErrorMessage(message);
+      return;
+    }
+    catch (Exception e)
+    {
+      if (DebugLogger.debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      operation.setResultCode(ResultCode.PROTOCOL_ERROR);
+
+      Message message = ERR_GET_SYMMETRIC_KEY_DECODE_EXCEPTION.get(
+           StaticUtils.getExceptionMessage(e));
+      operation.appendErrorMessage(message);
+      return;
+    }
+
+    CryptoManager cm = DirectoryServer.getCryptoManager();
+    try
+    {
+      byte[] responseSymmetricKey = cm.rewrapSymmetricKeyAttribute(
+           requestSymmetricKey, instanceKeyID);
+
+      operation.setResponseOID(
+           ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP);
+      operation.setResponseValue(new ASN1OctetString(responseSymmetricKey));
+      operation.setResultCode(ResultCode.SUCCESS);
+    }
+    catch (CryptoManager.CryptoManagerException e)
+    {
+      operation.setResultCode(DirectoryServer.getServerErrorResultCode());
+      operation.appendErrorMessage(e.getMessageObject());
+    }
+  }
+
+  /**
+   * Encodes the provided information into an ASN.1 octet string suitable for
+   * use as the value for this extended operation.
+   *
+   * @param  symmetricKey   The wrapped key to use for this request control.
+   * @param  instanceKeyID  The requesting server instance key ID to use for
+   *                        this request control.
+   *
+   * @return  An ASN.1 octet string containing the encoded request value.
+   */
+  public static ASN1OctetString encodeRequestValue(
+       byte[] symmetricKey,
+       byte[] instanceKeyID)
+  {
+    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
+
+    ASN1OctetString symmetricKeyElement =
+         new ASN1OctetString(TYPE_SYMMETRIC_KEY_ELEMENT, symmetricKey);
+    elements.add(symmetricKeyElement);
+
+    ASN1OctetString instanceKeyIDElement =
+         new ASN1OctetString(TYPE_INSTANCE_KEY_ID_ELEMENT,
+                             instanceKeyID);
+    elements.add(instanceKeyIDElement);
+
+    ASN1Sequence valueSequence = new ASN1Sequence(elements);
+    return new ASN1OctetString(valueSequence.encode());
+  }
+
+
+}
diff --git a/opends/src/server/org/opends/server/util/ServerConstants.java b/opends/src/server/org/opends/server/util/ServerConstants.java
index b018028..b8706bb 100644
--- a/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -775,6 +775,14 @@
 
 
   /**
+   * The request OID for the get symmetric key extended operation.
+   */
+  public static final String OID_GET_SYMMETRIC_KEY_EXTENDED_OP =
+       "1.3.6.1.4.1.26027.1.6.3";
+
+
+
+  /**
    * The name of the standard "ldapSubentry" objectclass (which is a special
    * type of objectclass that makes a kind of "operational" entry), formatted
    * in camel case.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java
new file mode 100644
index 0000000..5e419d2
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GetSymmetricKeyExtendedOperationTestCase.java
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.extensions;
+
+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.core.ExtendedOperation;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.util.ServerConstants;
+import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+
+import java.util.Arrays;
+
+/**
+ * A set of test cases for the symmetric key extended operation.
+ */
+public class GetSymmetricKeyExtendedOperationTestCase
+     extends ExtensionsTestCase
+{
+  /**
+   * Ensures that the Directory Server is running.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @BeforeClass()
+  public void startServer()
+         throws Exception
+  {
+    TestCaseUtils.startServer();
+  }
+
+
+
+  @Test
+  public void testValidRequest() throws Exception
+  {
+    CryptoManager cm = DirectoryServer.getCryptoManager();
+
+    // TODO use a proper symmetric key value
+    byte[] symmetricKey = cm.getInstanceKeyID();
+    byte[] instanceKeyID =  cm.getInstanceKeyID();
+
+    ASN1OctetString requestValue =
+         GetSymmetricKeyExtendedOperation.encodeRequestValue(
+              symmetricKey, instanceKeyID);
+
+    InternalClientConnection internalConnection =
+         InternalClientConnection.getRootConnection();
+    ExtendedOperation extendedOperation =
+         internalConnection.processExtendedOperation(
+              ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP, requestValue);
+
+    assertEquals(extendedOperation.getResultCode(), ResultCode.SUCCESS);
+    assertTrue(Arrays.equals(
+         extendedOperation.getResponseValue().value(), symmetricKey));
+  }
+
+
+  @Test
+  public void testInvalidRequest() throws Exception
+  {
+    CryptoManager cm = DirectoryServer.getCryptoManager();
+
+//    byte[] symmetricKey  = new byte[1]; // FIXME causes ArrayOutOfBounds!
+    byte[] symmetricKey  = new byte[16];
+    byte[] instanceKeyID = cm.getInstanceKeyID();
+
+    ASN1OctetString requestValue =
+         GetSymmetricKeyExtendedOperation.encodeRequestValue(
+              symmetricKey, instanceKeyID);
+
+    InternalClientConnection internalConnection =
+         InternalClientConnection.getRootConnection();
+    ExtendedOperation extendedOperation =
+         internalConnection.processExtendedOperation(
+              ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP, requestValue);
+
+    assertFalse(extendedOperation.getResultCode() == ResultCode.SUCCESS);
+  }
+}

--
Gitblit v1.10.0