001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    
028    package org.opends.server.crypto;
029    
030    import org.opends.server.admin.std.server.
031                GetSymmetricKeyExtendedOperationHandlerCfg;
032    import org.opends.server.api.ExtendedOperationHandler;
033    import org.opends.server.loggers.debug.DebugTracer;
034    import org.opends.server.loggers.debug.DebugLogger;
035    import org.opends.server.types.*;
036    import org.opends.server.config.ConfigException;
037    import org.opends.server.core.DirectoryServer;
038    import org.opends.server.core.ExtendedOperation;
039    import org.opends.server.protocols.asn1.ASN1Sequence;
040    import org.opends.server.protocols.asn1.ASN1Element;
041    import org.opends.server.protocols.asn1.ASN1Exception;
042    import org.opends.server.protocols.asn1.ASN1OctetString;
043    import org.opends.server.util.StaticUtils;
044    import org.opends.server.util.ServerConstants;
045    import org.opends.messages.Message;
046    import static org.opends.messages.ExtensionMessages.*;
047    
048    import java.util.Set;
049    import java.util.HashSet;
050    import java.util.ArrayList;
051    
052    /**
053     * This class implements the get symmetric key extended operation, an OpenDS
054     * proprietary extension used for distribution of symmetric keys amongst
055     * servers.
056     */
057    public class GetSymmetricKeyExtendedOperation
058         extends ExtendedOperationHandler<
059                      GetSymmetricKeyExtendedOperationHandlerCfg>
060    {
061      /**
062       * The tracer object for the debug logger.
063       */
064      private static final DebugTracer TRACER = DebugLogger.getTracer();
065    
066    
067    
068      /**
069       * The BER type value for the symmetric key element of the operation value.
070       */
071      public static final byte TYPE_SYMMETRIC_KEY_ELEMENT = (byte) 0x80;
072    
073    
074    
075      /**
076       * The BER type value for the instance key ID element of the operation value.
077       */
078      public static final byte TYPE_INSTANCE_KEY_ID_ELEMENT = (byte) 0x81;
079    
080    
081    
082      // The default set of supported control OIDs for this extended operation.
083      private Set<String> supportedControlOIDs = new HashSet<String>(0);
084    
085    
086    
087      /**
088       * Create an instance of this symmetric key extended operation.  All
089       * initialization should be performed in the
090       * <CODE>initializeExtendedOperationHandler</CODE> method.
091       */
092      public GetSymmetricKeyExtendedOperation()
093      {
094        super();
095    
096      }
097    
098    
099    
100    
101      /**
102       * {@inheritDoc}
103       */
104      public void initializeExtendedOperationHandler(
105           GetSymmetricKeyExtendedOperationHandlerCfg config)
106             throws ConfigException, InitializationException
107      {
108        supportedControlOIDs = new HashSet<String>();
109    
110    
111        DirectoryServer.registerSupportedExtension(
112             ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP, this);
113    
114        registerControlsAndFeatures();
115      }
116    
117    
118    
119      /**
120       * Performs any finalization that may be necessary for this extended
121       * operation handler.  By default, no finalization is performed.
122       */
123      public void finalizeExtendedOperationHandler()
124      {
125        DirectoryServer.deregisterSupportedExtension(
126             ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP);
127    
128        deregisterControlsAndFeatures();
129      }
130    
131    
132    
133      /**
134       * {@inheritDoc}
135       */
136      @Override()
137      public Set<String> getSupportedControls()
138      {
139        return supportedControlOIDs;
140      }
141    
142    
143    
144      /**
145       * Processes the provided extended operation.
146       *
147       * @param  operation  The extended operation to be processed.
148       */
149      public void processExtendedOperation(ExtendedOperation operation)
150      {
151        // Initialize the variables associated with components that may be included
152        // in the request.
153        String requestSymmetricKey = null;
154        String instanceKeyID       = null;
155    
156    
157    
158        // Parse the encoded request, if there is one.
159        ByteString requestValue = operation.getRequestValue();
160        if (requestValue == null)
161        {
162          // The request must always have a value.
163          Message message = ERR_GET_SYMMETRIC_KEY_NO_VALUE.get();
164          operation.appendErrorMessage(message);
165          return;
166        }
167    
168        try
169        {
170          ASN1Sequence valueSequence =
171               ASN1Sequence.decodeAsSequence(requestValue.value());
172          for (ASN1Element e : valueSequence.elements())
173          {
174            switch (e.getType())
175            {
176              case TYPE_SYMMETRIC_KEY_ELEMENT:
177                requestSymmetricKey =
178                     ASN1OctetString.decodeAsOctetString(e).stringValue();
179                break;
180    
181              case TYPE_INSTANCE_KEY_ID_ELEMENT:
182                instanceKeyID =
183                     ASN1OctetString.decodeAsOctetString(e).stringValue();
184                break;
185    
186              default:
187                Message message = ERR_GET_SYMMETRIC_KEY_INVALID_TYPE.get(
188                     StaticUtils.byteToHex(e.getType()));
189                operation.appendErrorMessage(message);
190                return;
191            }
192          }
193        }
194        catch (ASN1Exception ae)
195        {
196          if (DebugLogger.debugEnabled())
197          {
198            TRACER.debugCaught(DebugLogLevel.ERROR, ae);
199          }
200    
201          Message message = ERR_GET_SYMMETRIC_KEY_ASN1_DECODE_EXCEPTION.get(
202               ae.getMessage());
203          operation.appendErrorMessage(message);
204          return;
205        }
206        catch (Exception e)
207        {
208          if (DebugLogger.debugEnabled())
209          {
210            TRACER.debugCaught(DebugLogLevel.ERROR, e);
211          }
212    
213          operation.setResultCode(ResultCode.PROTOCOL_ERROR);
214    
215          Message message = ERR_GET_SYMMETRIC_KEY_DECODE_EXCEPTION.get(
216               StaticUtils.getExceptionMessage(e));
217          operation.appendErrorMessage(message);
218          return;
219        }
220    
221        CryptoManagerImpl cm = DirectoryServer.getCryptoManager();
222        try
223        {
224          String responseSymmetricKey = cm.reencodeSymmetricKeyAttribute(
225               requestSymmetricKey, instanceKeyID);
226    
227          operation.setResponseOID(
228               ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP);
229          operation.setResponseValue(new ASN1OctetString(responseSymmetricKey));
230          operation.setResultCode(ResultCode.SUCCESS);
231        }
232        catch (CryptoManagerException e)
233        {
234          operation.setResultCode(DirectoryServer.getServerErrorResultCode());
235          operation.appendErrorMessage(e.getMessageObject());
236        }
237        catch (Exception e)
238        {
239          operation.setResultCode(DirectoryServer.getServerErrorResultCode());
240          operation.appendErrorMessage(StaticUtils.getExceptionMessage(e));
241        }
242      }
243    
244      /**
245       * Encodes the provided information into an ASN.1 octet string suitable for
246       * use as the value for this extended operation.
247       *
248       * @param  symmetricKey   The wrapped key to use for this request control.
249       * @param  instanceKeyID  The requesting server instance key ID to use for
250       *                        this request control.
251       *
252       * @return  An ASN.1 octet string containing the encoded request value.
253       */
254      public static ASN1OctetString encodeRequestValue(
255           String symmetricKey,
256           String instanceKeyID)
257      {
258        ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
259    
260        ASN1OctetString symmetricKeyElement =
261             new ASN1OctetString(TYPE_SYMMETRIC_KEY_ELEMENT, symmetricKey);
262        elements.add(symmetricKeyElement);
263    
264        ASN1OctetString instanceKeyIDElement =
265             new ASN1OctetString(TYPE_INSTANCE_KEY_ID_ELEMENT,
266                                 instanceKeyID);
267        elements.add(instanceKeyIDElement);
268    
269        ASN1Sequence valueSequence = new ASN1Sequence(elements);
270        return new ASN1OctetString(valueSequence.encode());
271      }
272    
273    
274    }