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