001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2013-2016 ForgeRock AS.
016 */
017package org.opends.server.crypto;
018
019import java.io.IOException;
020
021import org.forgerock.i18n.LocalizableMessage;
022import org.forgerock.opendj.server.config.server.
023GetSymmetricKeyExtendedOperationHandlerCfg;
024import org.opends.server.api.ExtendedOperationHandler;
025import org.forgerock.opendj.config.server.ConfigException;
026import org.opends.server.core.DirectoryServer;
027import org.opends.server.core.ExtendedOperation;
028import org.forgerock.i18n.slf4j.LocalizedLogger;
029import org.forgerock.opendj.io.ASN1;
030import org.forgerock.opendj.ldap.DecodeException;
031import org.forgerock.opendj.io.ASN1Reader;
032import org.forgerock.opendj.io.ASN1Writer;
033import org.opends.server.types.*;
034import org.forgerock.opendj.ldap.ResultCode;
035import org.forgerock.opendj.ldap.ByteString;
036import org.forgerock.opendj.ldap.ByteStringBuilder;
037import org.opends.server.util.ServerConstants;
038import org.opends.server.util.StaticUtils;
039
040import static org.opends.messages.ExtensionMessages.*;
041
042/**
043 * This class implements the get symmetric key extended operation, an OpenDS
044 * proprietary extension used for distribution of symmetric keys amongst
045 * servers.
046 */
047public class GetSymmetricKeyExtendedOperation
048     extends ExtendedOperationHandler<
049                  GetSymmetricKeyExtendedOperationHandlerCfg>
050{
051  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
052
053  /**
054   * The BER type value for the symmetric key element of the operation value.
055   */
056  public static final byte TYPE_SYMMETRIC_KEY_ELEMENT = (byte) 0x80;
057
058  /**
059   * The BER type value for the instance key ID element of the operation value.
060   */
061  public static final byte TYPE_INSTANCE_KEY_ID_ELEMENT = (byte) 0x81;
062
063  /**
064   * Create an instance of this symmetric key extended operation.  All
065   * initialization should be performed in the
066   * <CODE>initializeExtendedOperationHandler</CODE> method.
067   */
068  public GetSymmetricKeyExtendedOperation()
069  {
070    super();
071  }
072
073  /** {@inheritDoc} */
074  @Override
075  public void initializeExtendedOperationHandler(
076       GetSymmetricKeyExtendedOperationHandlerCfg config)
077         throws ConfigException, InitializationException
078  {
079    super.initializeExtendedOperationHandler(config);
080  }
081
082  /**
083   * Processes the provided extended operation.
084   *
085   * @param  operation  The extended operation to be processed.
086   */
087  @Override
088  public void processExtendedOperation(ExtendedOperation operation)
089  {
090    // Initialize the variables associated with components that may be included
091    // in the request.
092    String requestSymmetricKey = null;
093    String instanceKeyID       = null;
094
095
096
097    // Parse the encoded request, if there is one.
098    ByteString requestValue = operation.getRequestValue();
099    if (requestValue == null)
100    {
101      // The request must always have a value.
102      LocalizableMessage message = ERR_GET_SYMMETRIC_KEY_NO_VALUE.get();
103      operation.appendErrorMessage(message);
104      return;
105    }
106
107    try
108    {
109      ASN1Reader reader = ASN1.getReader(requestValue);
110      reader.readStartSequence();
111      if(reader.hasNextElement() &&
112          reader.peekType() == TYPE_SYMMETRIC_KEY_ELEMENT)
113      {
114        requestSymmetricKey = reader.readOctetStringAsString();
115      }
116      if(reader.hasNextElement() &&
117          reader.peekType() == TYPE_INSTANCE_KEY_ID_ELEMENT)
118      {
119        instanceKeyID = reader.readOctetStringAsString();
120      }
121      reader.readEndSequence();
122    }
123    catch (DecodeException e)
124    {
125      logger.traceException(e);
126      operation.appendErrorMessage(ERR_GET_SYMMETRIC_KEY_ASN1_DECODE_EXCEPTION.get(e.getMessage()));
127      return;
128    }
129    catch (Exception e)
130    {
131      logger.traceException(e);
132
133      operation.setResultCode(ResultCode.PROTOCOL_ERROR);
134
135      LocalizableMessage message = ERR_GET_SYMMETRIC_KEY_DECODE_EXCEPTION.get(
136           StaticUtils.getExceptionMessage(e));
137      operation.appendErrorMessage(message);
138      return;
139    }
140
141    CryptoManagerImpl cm = DirectoryServer.getCryptoManager();
142    try
143    {
144      String responseSymmetricKey = cm.reencodeSymmetricKeyAttribute(
145           requestSymmetricKey, instanceKeyID);
146
147      operation.setResponseOID(
148           ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP);
149      operation.setResponseValue(ByteString.valueOfUtf8(responseSymmetricKey));
150      operation.setResultCode(ResultCode.SUCCESS);
151    }
152    catch (CryptoManagerException e)
153    {
154      operation.setResultCode(DirectoryServer.getServerErrorResultCode());
155      operation.appendErrorMessage(e.getMessageObject());
156    }
157    catch (Exception e)
158    {
159      operation.setResultCode(DirectoryServer.getServerErrorResultCode());
160      operation.appendErrorMessage(StaticUtils.getExceptionMessage(e));
161    }
162  }
163
164  /**
165   * Encodes the provided information into an ASN.1 octet string suitable for
166   * use as the value for this extended operation.
167   *
168   * @param  symmetricKey   The wrapped key to use for this request control.
169   * @param  instanceKeyID  The requesting server instance key ID to use for
170   *                        this request control.
171   *
172   * @return  An ASN.1 octet string containing the encoded request value.
173   */
174  public static ByteString encodeRequestValue(
175       String symmetricKey,
176       String instanceKeyID)
177  {
178    ByteStringBuilder builder = new ByteStringBuilder();
179    ASN1Writer writer = ASN1.getWriter(builder);
180
181    try
182    {
183      writer.writeStartSequence();
184      writer.writeOctetString(TYPE_SYMMETRIC_KEY_ELEMENT, symmetricKey);
185      writer.writeOctetString(TYPE_INSTANCE_KEY_ID_ELEMENT, instanceKeyID);
186      writer.writeEndSequence();
187    }
188    catch (IOException e)
189    {
190      // TODO: DO something
191    }
192
193    return builder.toByteString();
194  }
195
196  /** {@inheritDoc} */
197  @Override
198  public String getExtendedOperationOID()
199  {
200    return ServerConstants.OID_GET_SYMMETRIC_KEY_EXTENDED_OP;
201  }
202
203  /** {@inheritDoc} */
204  @Override
205  public String getExtendedOperationName()
206  {
207    return "Get Symmetric Key";
208  }
209}