From cc16fe0a84cebd87f66d5ee647538f6889b80024 Mon Sep 17 00:00:00 2001
From: Abhishek Koneru <akoneru@redhat.com>
Date: Wed, 26 Feb 2014 13:15:57 -0500
Subject: [PATCH] Changes to KeyClient on the java side.

The KeyClient class on the java side is modified to
have a similar design as the KeyClient class on the python side.
---
 .../src/com/netscape/certsrv/key/KeyClient.java    | 789 ++++++++++++++++++---
 .../src/com/netscape/certsrv/key/KeyData.java      |  12 +-
 .../netscape/certsrv/key/KeyRequestResponse.java   |  11 +
 .../src/com/netscape/certsrv/kra/KRAClient.java    |  13 +-
 .../src/com/netscape/cmstools/key/KeyFindCLI.java  |   2 +-
 .../netscape/cmstools/key/KeyRequestFindCLI.java   |   2 +-
 .../src/com/netscape/cms/servlet/test/DRMTest.java | 256 +++----
 7 files changed, 819 insertions(+), 266 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java
index 0fa1f264e8c3723b5eec02794b5d0b66408a090f..bb71c990bf00743a1ae7234aa2e9318bd053d0f9 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyClient.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java
@@ -17,29 +17,60 @@
 //--- END COPYRIGHT BLOCK ---
 package com.netscape.certsrv.key;
 
+import java.io.IOException;
 import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
 import java.util.List;
+import java.util.Random;
 
 import javax.ws.rs.core.Response;
 
+import org.mozilla.jss.CertDatabaseException;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
+import org.mozilla.jss.KeyDatabaseException;
+import org.mozilla.jss.crypto.AlreadyInitializedException;
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.util.IncorrectPasswordException;
+import org.mozilla.jss.util.Password;
+
 import com.netscape.certsrv.base.ResourceMessage;
 import com.netscape.certsrv.client.Client;
 import com.netscape.certsrv.client.PKIClient;
 import com.netscape.certsrv.dbs.keydb.KeyId;
 import com.netscape.certsrv.request.RequestId;
+import com.netscape.cmsutil.crypto.CryptoUtil;
 import com.netscape.cmsutil.util.Utils;
 
 /**
  * @author Endi S. Dewata
+ * @author Abhishek Koneru
  */
 public class KeyClient extends Client {
 
     public KeyResource keyClient;
     public KeyRequestResource keyRequestClient;
 
-    public KeyClient(PKIClient client, String subsystem) throws URISyntaxException {
+    private CryptoOperationStore crypto;
+    private String transportCert;
+
+    public KeyClient(PKIClient client, String subsystem) throws URISyntaxException, KeyDatabaseException,
+            CertDatabaseException, GeneralSecurityException, NotInitializedException, IncorrectPasswordException,
+            TokenException {
         super(client, subsystem, "key");
         init();
+        crypto = new CryptoOperationStore(client);
     }
 
     public void init() throws URISyntaxException {
@@ -47,54 +78,58 @@ public class KeyClient extends Client {
         keyRequestClient = createProxy(KeyRequestResource.class);
     }
 
-    public KeyInfoCollection findKeys(String clientKeyID, String status, Integer maxSize, Integer maxTime,
+    public void setTransportCert(String transportCert) {
+        this.transportCert = transportCert;
+    }
+
+    /**
+     * List/Search archived secrets in the DRM.
+     *
+     * @param clientKeyID -- Client Key Identifier
+     * @param status -- Status of the keys to be listed
+     * @param maxSize -- Maximum number of keys to be fetched
+     * @param maxTime -- Maximum time for the operation to take
+     * @param start -- Start index of list
+     * @param size -- Size of the list to be returned.
+     * @return a KeyInfoCollection object.
+     */
+    public KeyInfoCollection listKeys(String clientKeyID, String status, Integer maxSize, Integer maxTime,
             Integer start, Integer size) {
         Response response = keyClient.listKeys(clientKeyID, status, maxSize, maxTime, start, size);
         return client.getEntity(response, KeyInfoCollection.class);
     }
 
-    public KeyInfo getActiveKeyInfo(String clientKeyID) {
-        Response response = keyClient.getActiveKeyInfo(clientKeyID);
-        return client.getEntity(response, KeyInfo.class);
-    }
-
-    public KeyData retrieveKey(KeyId keyId, RequestId requestId, byte[] rpwd, byte[] rkey, byte[] nonceData) {
-        // create recovery request
-        KeyRecoveryRequest data = new KeyRecoveryRequest();
-        data.setKeyId(keyId);
-        data.setRequestId(requestId);
-        if (rkey != null) {
-            data.setTransWrappedSessionKey(Utils.base64encode(rkey));
-        }
-        if (rpwd != null) {
-            data.setSessionWrappedPassphrase(Utils.base64encode(rpwd));
-        }
-
-        if (nonceData != null) {
-            data.setNonceData(Utils.base64encode(nonceData));
-        }
-
-        return retrieveKey(data);
-    }
-
-    public KeyData retrieveKey(KeyRecoveryRequest data) {
-        Response response = keyClient.retrieveKey(data);
-        return client.getEntity(response, KeyData.class);
-    }
-
-    public KeyRequestInfoCollection findRequests(String requestState, String requestType) {
-        return findRequests(
+    /**
+     * Search key requests in the DRM based on the state/type of the requests.
+     *
+     * @param requestState -- State of the requests to be queried.
+     * @param requestType -- Type of the requests to be queried.
+     * @return KeyRequestCollection object.
+     */
+    public KeyRequestInfoCollection listRequests(String requestState, String requestType) {
+        return listRequests(
                 requestState,
                 requestType,
                 null,
                 new RequestId(0),
                 100,
                 100,
-                10
-        );
+                10);
     }
 
-    public KeyRequestInfoCollection findRequests(
+    /**
+     * List/Search key requests in the DRM
+     *
+     * @param requestState
+     * @param requestType
+     * @param clientKeyID
+     * @param start
+     * @param pageSize
+     * @param maxResults
+     * @param maxTime
+     * @return
+     */
+    public KeyRequestInfoCollection listRequests(
             String requestState,
             String requestType,
             String clientKeyID,
@@ -113,105 +148,645 @@ public class KeyClient extends Client {
         return client.getEntity(response, KeyRequestInfoCollection.class);
     }
 
+    /**
+     * Return a KeyRequestInfo object for a specific request.
+     *
+     * @param id -- A Request Id object
+     * @return
+     */
     public KeyRequestInfo getRequestInfo(RequestId id) {
+        if (id == null) {
+            throw new IllegalArgumentException("Request Id must be specified.");
+        }
         Response response = keyRequestClient.getRequestInfo(id);
         return client.getEntity(response, KeyRequestInfo.class);
     }
 
-    public KeyRequestResponse archiveSecurityData(String clientKeyId, String dataType,
-            String algorithm, int strength, byte[] pkiArchiveOptions) {
-        // create archival request
-        KeyArchivalRequest data = new KeyArchivalRequest();
-        data.setPKIArchiveOptions(Utils.base64encode(pkiArchiveOptions));
-        data.setClientKeyId(clientKeyId);
-        data.setDataType(dataType);
-        data.setKeyAlgorithm(algorithm);
-        data.setKeySize(strength);
-
-        return createRequest(data);
-    }
-
-    public KeyRequestResponse archiveSecurityData(String clientKeyId, String dataType,
-            String algorithm, int strength, byte[] wrappedPrivateData,
-            byte[] wrappedSessionKey, String algorithmOID, byte[] algParams) {
-        // create archival request
-        KeyArchivalRequest data = new KeyArchivalRequest();
-        data.setTransWrappedSessionKey(Utils.base64encode(wrappedSessionKey));
-        data.setWrappedPrivateData(Utils.base64encode(wrappedPrivateData));
-        data.setAlgorithmOID(algorithmOID);
-        data.setSymmetricAlgorithmParams(Utils.base64encode(algParams));
-        data.setClientKeyId(clientKeyId);
-        data.setDataType(dataType);
-        data.setKeyAlgorithm(algorithm);
-        data.setKeySize(strength);
-
-        return createRequest(data);
-    }
-
-    public KeyRequestResponse requestRecovery(KeyId keyId, byte[] rpwd, byte[] rkey, byte[] nonceData) {
-        // create recovery request
-        KeyRecoveryRequest data = new KeyRecoveryRequest();
-        data.setKeyId(keyId);
-        if (rpwd != null) {
-            data.setSessionWrappedPassphrase(Utils.base64encode(rpwd));
-        }
-        if (rkey != null) {
-            data.setTransWrappedSessionKey(Utils.base64encode(rkey));
-        }
-
-        if (nonceData != null) {
-            data.setNonceData(Utils.base64encode(nonceData));
+    /**
+     * Get the info in the KeyRecord for a specific secret in the DRM.
+     *
+     * @param id -- S KeyId object
+     * @return
+     */
+    public KeyInfo getKeyInfo(KeyId id) {
+        if (id == null) {
+            throw new IllegalArgumentException("Key Id must be specified.");
         }
-
-        return createRequest(data);
-    }
-
-    public KeyRequestResponse requestKeyRecovery(String keyId, String b64Certificate) {
-        // create key recovery request
-        KeyRecoveryRequest data = new KeyRecoveryRequest();
-        data.setKeyId(new KeyId(keyId));
-        data.setCertificate(b64Certificate);
-
-        return createRequest(data);
+        Response response = keyClient.getKeyInfo(id);
+        return client.getEntity(response, KeyInfo.class);
     }
 
-    public KeyRequestResponse generateKey(String clientKeyId, String keyAlgorithm, int keySize, List<String> usages) {
-        SymKeyGenerationRequest data = new SymKeyGenerationRequest();
-        data.setClientKeyId(clientKeyId);
-        data.setKeyAlgorithm(keyAlgorithm);
-        data.setKeySize(new Integer(keySize));
-        data.setUsages(usages);
-
-        return createRequest(data);
+    /**
+     * Get the info in the KeyRecord for the active secret in the DRM.
+     *
+     * @param clientKeyID -- Client Key Identifier
+     * @return
+     */
+    public KeyInfo getActiveKeyInfo(String clientKeyID) {
+        if (clientKeyID == null) {
+            throw new IllegalArgumentException("Client Key Id must be specified.");
+        }
+        Response response = keyClient.getActiveKeyInfo(clientKeyID);
+        return client.getEntity(response, KeyInfo.class);
     }
 
-    public KeyRequestResponse createRequest(ResourceMessage data) {
-        Response response = keyRequestClient.createRequest(data);
-        return client.getEntity(response, KeyRequestResponse.class);
+    /**
+     * Modify the status of a key
+     *
+     * @param id -- KeyId object
+     * @param status -- Status to be set for the key
+     */
+    public void modifyKeyStatus(KeyId id, String status) {
+        if (id == null || status == null) {
+            throw new IllegalArgumentException("Key Id and status must be specified.");
+        }
+        Response response = keyClient.modifyKeyStatus(id, status);
+        client.getEntity(response, Void.class);
     }
 
+    /**
+     * Approve a secret recovery request
+     *
+     * @param id -- A RequestId object
+     */
     public void approveRequest(RequestId id) {
+        if (id == null) {
+            throw new IllegalArgumentException("Request Id must be specified.");
+        }
         Response response = keyRequestClient.approveRequest(id);
         client.getEntity(response, Void.class);
     }
 
+    /**
+     * Reject a secret recovery request
+     *
+     * @param id -- A RequestId object
+     */
     public void rejectRequest(RequestId id) {
+        if (id == null) {
+            throw new IllegalArgumentException("Request Id must be specified.");
+        }
         Response response = keyRequestClient.rejectRequest(id);
         client.getEntity(response, Void.class);
     }
 
+    /**
+     * Cancel a secret recovery request
+     *
+     * @param id -- A RequestId object
+     */
     public void cancelRequest(RequestId id) {
+        if (id == null) {
+            throw new IllegalArgumentException("Request Id must be specified.");
+        }
         Response response = keyRequestClient.cancelRequest(id);
         client.getEntity(response, Void.class);
     }
 
-    public KeyInfo getKeyInfo(KeyId id) {
-        Response response = keyClient.getKeyInfo(id);
-        return client.getEntity(response, KeyInfo.class);
+    /**
+     * Submit an archival, recovery or key generation request
+     * to the DRM.
+     *
+     * @param data -- A KeyArchivalRequest/KeyRecoveryRequest/SymKeyGenerationRequest object
+     * @return A KeyRequestResponse object
+     */
+    public KeyRequestResponse createRequest(ResourceMessage request) {
+        if (request == null) {
+            throw new IllegalArgumentException("No Request specified.");
+        }
+        Response response = keyRequestClient.createRequest(request);
+        return client.getEntity(response, KeyRequestResponse.class);
     }
 
-    public void modifyKeyStatus(KeyId id, String status) {
-        Response response  = keyClient.modifyKeyStatus(id, status);
-        client.getEntity(response, Void.class);
+    /**
+     * Create a request to recover a secret.
+     *
+     * To retrieve a symmetric key or passphrase, the only parameter that is required is
+     * the KeyId object. It is possible (but not required) to pass in the session keys/passphrase
+     * and nonceData for the retrieval at this time.
+     *
+     * To retrieve an asymmetric key, the keyId and the the base-64 encoded certificate
+     * is required.
+     *
+     * @param keyId -- The KeyId object
+     * @param sessionWrappedPassphrase -- A passphrase wrapped by a session key
+     * @param transWrappedSessionKey -- The session key, used to wrap the passphrase, wrapped by the DRM transport cert.
+     * @param nonceData -- IV parameter used while encrypting the passphrase using the session key.
+     * @param b64Certificate -- A certificate in encoded using Base64
+     * @return
+     */
+    public KeyRequestResponse recoverKey(KeyId keyId, byte[] sessionWrappedPassphrase, byte[] transWrappedSessionKey,
+            byte[] nonceData, String b64Certificate) {
+        // create recovery request
+        if (keyId == null) {
+            throw new IllegalArgumentException("KeyId has to be specified.");
+        }
+        KeyRecoveryRequest data = new KeyRecoveryRequest();
+        data.setKeyId(keyId);
+        if (sessionWrappedPassphrase != null) {
+            data.setSessionWrappedPassphrase(Utils.base64encode(sessionWrappedPassphrase));
+        }
+        if (transWrappedSessionKey != null) {
+            data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
+        }
+
+        if (nonceData != null) {
+            data.setNonceData(Utils.base64encode(nonceData));
+        }
+        if (b64Certificate != null) {
+            data.setCertificate(b64Certificate);
+        }
+
+        return createRequest(data);
+    }
+
+    /**
+     * Retrieve a secret from the DRM.
+     *
+     * @param data -- a KeyRecoveryRequest containing the keyId of the
+     *            secret being retrieved, the request_id of the approved recovery
+     *            request and a wrapping mechanism.
+     * @return A KeyData object containing the wrapped secret.
+     */
+    public KeyData retrieveKeyData(KeyRecoveryRequest data) {
+        if (data == null) {
+            throw new IllegalArgumentException("No data to to retrieve key");
+        }
+        Response response = keyClient.retrieveKey(data);
+        return client.getEntity(response, KeyData.class);
+    }
+
+    /**
+     * Retrieve a secret (passphrase or symmetric key) from the DRM.
+     *
+     * This function generates a key recovery request, approves it, and retrieves
+     * the secret referred to by key_id.
+     * This assumes that only one approval is required to authorize the recovery.
+     *
+     * To ensure data security in transit, the data will be returned encrypted by a session
+     * key (168 bit 3DES symmetric key) - which is first wrapped (encrypted) by the public
+     * key of the DRM transport certificate before being sent to the DRM. The
+     * parameter trans_wrapped_session_key refers to this wrapped session key.
+     *
+     * There are two ways of using this function:
+     *
+     * 1) transWrappedSessionKey is not provided by caller.
+     *
+     * In this case, the function will call CryptoUtil methods to generate and wrap the
+     * session key. The function will return the KeyData object, but with the secret
+     * set to the variable privateData. (The decryption of the wrappedPrivateData is done
+     * on the client side i.e. the secret is not transmitted as it is by the server.)
+     *
+     * 2) The transWrappedSessionKey is provided by the caller.
+     *
+     * In this case, the function will simply pass the data to the DRM, and will return the secret
+     * wrapped in the session key. The secret will still need to be unwrapped by the caller.
+     *
+     * @param keyId
+     * @param transWrappedSessionKey
+     * @return
+     * @throws NoSuchAlgorithmException
+     * @throws IllegalStateException
+     * @throws TokenException
+     * @throws CertificateEncodingException
+     * @throws InvalidKeyException
+     * @throws InvalidAlgorithmParameterException
+     * @throws BadPaddingException
+     * @throws IllegalBlockSizeException
+     */
+    public KeyData retrieveKey(KeyId keyId, byte[] transWrappedSessionKey) throws NoSuchAlgorithmException,
+            IllegalStateException, TokenException, CertificateEncodingException, InvalidKeyException,
+            InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException {
+
+        if (keyId == null) {
+            throw new IllegalArgumentException("KeyId has to be specified.");
+        }
+
+        boolean isKeyProvided = (transWrappedSessionKey == null) ? false : true;
+        SymmetricKey sessionKey = null;
+        if (!isKeyProvided) {
+            // The default key algorithm used is KeyGenAlgorithm.DES3
+            sessionKey = crypto.generateSessionKey();
+            transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
+        }
+
+        KeyRequestResponse keyData = recoverKey(keyId, null, null, null, null);
+        approveRequest(keyData.getRequestId());
+
+        KeyRecoveryRequest recoveryRequest = new KeyRecoveryRequest();
+        recoveryRequest.setKeyId(keyId);
+        recoveryRequest.setRequestId(keyData.getRequestId());
+        recoveryRequest.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
+
+        KeyData data = retrieveKeyData(recoveryRequest);
+
+        if (!isKeyProvided) {
+            data.setPrivateData(
+                    crypto.unwrapUsingSessionKey(data.getWrappedPrivateData(), sessionKey,
+                            data.getNonceData())
+                    );
+        }
+
+        return data;
+    }
+
+    /**
+     * This function generates a key recovery request, approves it, and retrieves
+     * the secret referred to by key_id. This assumes that only one approval is required
+     * to authorize the recovery.
+     *
+     * The secret is secured in transit by wrapping the secret with a passphrase using
+     * PBE encryption.
+     *
+     * There are two ways of using this function:
+     *
+     * 1) A passphrase is provided by the caller.
+     * In this case, CryptoUtil methods will be called to create the data to securely send the
+     *
+     * passphrase to the DRM. Basically, three pieces of data will be sent:
+     *
+     * - the passphrase wrapped by a 168 bit 3DES symmetric key (the session key). This
+     * is referred to as the parameter sessionWrappedPassphrase above.
+     *
+     * - the session key wrapped with the public key in the DRM transport certificate. This
+     * is referred to as the transWrappedSessionKey above.
+     *
+     * - ivps nonce data, referred to as nonceData
+     *
+     * The function will return the KeyData
+     *
+     * 2) The caller provides the trans_wrapped_session_key, session_wrapped_passphrase
+     * and nonce_data.
+     *
+     * In this case, the data will simply be passed to the DRM. The function will return
+     * the secret encrypted by the passphrase using PBE Encryption. The secret will still
+     * need to be decrypted by the caller.
+     *
+     * @param keyId
+     * @param passphrase
+     * @param transWrappedSessionKey
+     * @param sessionWrappedPassphrase
+     * @param nonceData
+     * @return
+     * @throws TokenException
+     * @throws InvalidAlgorithmParameterException
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidKeyException
+     * @throws CertificateEncodingException
+     * @throws IOException
+     * @throws BadPaddingException
+     * @throws IllegalBlockSizeException
+     */
+    public KeyData retrieveKeyByPassphrase(KeyId keyId, String passphrase, byte[] transWrappedSessionKey,
+            byte[] sessionWrappedPassphrase, byte[] nonceData) throws CertificateEncodingException,
+            InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, TokenException,
+            IllegalBlockSizeException, BadPaddingException, IOException {
+
+        if (keyId == null) {
+            throw new IllegalArgumentException("KeyId has to be specified.");
+        }
+
+        if (sessionWrappedPassphrase == null) {
+            if (passphrase == null) {
+                throw new IllegalArgumentException("No form of passphrase provided.");
+            } else {
+                SymmetricKey sessionKey = crypto.generateSessionKey();
+                transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
+                nonceData = CryptoOperationStore.getNonceData(8);
+                sessionWrappedPassphrase = crypto.wrapUsingSessionKey(nonceData, passphrase, sessionKey);
+            }
+        } else {
+            if (transWrappedSessionKey == null || nonceData == null) {
+                throw new IllegalArgumentException(
+                        "No way to extract passphrase. Both transWrappedSessionKey and the nonceData are required.");
+            }
+        }
+
+        // Need to pass the sessionWrappedPassphrase and transWrappedSessionKey when the
+        // both request and recovery are done at the same time. So the KeyRequestResounse itself
+        // contains the KeyData
+        RequestId requestId = recoverKey(keyId, null, null, null, null).getRequestId();
+        approveRequest(requestId);
+
+        KeyRecoveryRequest data = new KeyRecoveryRequest();
+        data.setKeyId(keyId);
+        data.setRequestId(requestId);
+        if (transWrappedSessionKey != null) {
+            data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
+        }
+        if (sessionWrappedPassphrase != null) {
+            data.setSessionWrappedPassphrase(Utils.base64encode(sessionWrappedPassphrase));
+        }
+        if (nonceData != null) {
+            data.setNonceData(Utils.base64encode(nonceData));
+        }
+
+        // Just return the KeyData as the wrappedPrivateData contains the key wrapped by the passphrase
+        // and the the nonceData, to recover extract the key.
+        return retrieveKeyData(data);
+
+    }
+
+    /**
+     * Retrieve an asymmetric private key and return it as PKCS12 data.
+     *
+     * This function generates a key recovery request, approves it, and retrieves
+     * the secret referred to by key_id in a PKCS12 file. This assumes that only
+     * one approval is required to authorize the recovery.
+     *
+     * @param keyId -- The KeyId object
+     * @param certificate -- the certificate associated with the private key
+     * @param passphrase -- A passphrase for the pkcs12 file.
+     * @return
+     */
+    public KeyData retrieveKeyByPKCS12(KeyId keyId, String certificate, String passphrase) {
+        if (keyId == null || certificate == null || passphrase == null) {
+            throw new IllegalArgumentException("KeyId, certificate and passphrase have to be specified.");
+        }
+        KeyRequestResponse keyData = recoverKey(keyId, null, null, null, certificate);
+        approveRequest(keyData.getRequestId());
+
+        KeyRecoveryRequest recoveryRequest = new KeyRecoveryRequest();
+        recoveryRequest.setKeyId(keyId);
+        recoveryRequest.setRequestId(keyData.getRequestId());
+        recoveryRequest.setPassphrase(passphrase);
+
+        return retrieveKeyData(recoveryRequest);
+    }
+
+    /**
+     * Archive a secret (symmetric key or passphrase) on the DRM.
+     *
+     * Requires a user-supplied client ID. There can be only one active
+     * key with a specified client ID. If a record for a duplicate active
+     * key exists, a BadRequestException is thrown.
+     *
+     * dataType can be one of the following:
+     * KeyClient.SYMMETRIC_KEY_TYPE,
+     * KeyClient.ASYMMETRIC_KEY_TYPE,
+     * KeyClient.PASS_PHRASE_TYPE
+     *
+     * algorithm and key_size are applicable to symmetric keys only.
+     * If a symmetric key is being archived, these parameters are required.
+     *
+     * privateData is the raw secret to be archived.
+     * It will be wrapped and sent to the DRM.
+     * To be implemented for the case where the clientId and the data are passed.
+     *
+     * @param clinetKeyId
+     * @param dataType
+     * @param wrappedPrivateData
+     * @param algorithm
+     * @param strength
+     * @return
+     * @throws TokenException
+     * @throws IllegalStateException
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidAlgorithmParameterException
+     * @throws InvalidKeyException
+     * @throws CertificateEncodingException
+     * @throws IOException
+     * @throws BadPaddingException
+     * @throws IllegalBlockSizeException
+     */
+    public KeyRequestResponse archiveKey(String clientKeyId, String dataType, String privateData, String keyAlgorithm,
+            int keySize) throws NoSuchAlgorithmException, IllegalStateException, TokenException,
+            CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException,
+            IllegalBlockSizeException, BadPaddingException, IOException {
+
+        if (clientKeyId == null || dataType == null) {
+            throw new IllegalArgumentException("Client key id and data type cannot be null");
+        }
+        if (dataType == KeyRequestResource.SYMMETRIC_KEY_TYPE) {
+            if (keyAlgorithm == null || keySize < 0) {
+                throw new IllegalArgumentException(
+                        "Key algorithm and key size are required for a symmetric key type request.");
+            }
+        }
+        if (privateData == null) {
+            throw new IllegalArgumentException("No data provided to archive.");
+        }
+        // Default algorithm OID for DES_EDE3_CBC
+        String algorithmOID = "{1 2 840 113549 3 7}";
+        byte[] nonceData = CryptoOperationStore.getNonceData(8);
+        String symAlgParams = Utils.base64encode(nonceData);
+        SymmetricKey sessionKey = crypto.generateSessionKey();
+        byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
+        byte[] wrappedPrivateData = crypto.wrapUsingSessionKey(nonceData, privateData,
+                sessionKey);
+
+        return archiveWrappedData(clientKeyId, dataType, keyAlgorithm, keySize, algorithmOID, symAlgParams, wrappedPrivateData, transWrappedSessionKey);
+    }
+
+    /**
+     * Archive a secret (symmetric key or passphrase) on the DRM.
+     *
+     * The following parameters are also required:
+     * - wrappedPrivateData - which is the secret wrapped by a session
+     * key (168 bit 3DES symmetric key)
+     * - transWrappedSession_key - the above session key wrapped by the
+     * DRM transport certificate public key.
+     * - the algorithmOID string for the symmetric key wrap
+     * - the symAlgParams storing the value of Utils.base64encode(nonceData)
+     *
+     * This method is useful if the caller wants to do their own wrapping
+     * of the secret, or if the secret was generated on a separate client
+     * machine and the wrapping was done there.
+     *
+     * @param clientKeyId
+     * @param dataType
+     * @param algorithm
+     * @param strength
+     * @param algorithmOID
+     * @param symAlgParams
+     * @param wrappedPrivateData
+     * @param transWrappedSessionKey
+     * @return
+     */
+    public KeyRequestResponse archiveWrappedData(String clientKeyId, String dataType, String keyAlgorithm, int keySize,
+            String algorithmOID, String symAlgParams, byte[] wrappedPrivateData, byte[] transWrappedSessionKey) {
+
+        if (clientKeyId == null || dataType == null) {
+            throw new IllegalArgumentException("Client key id and data type cannot be null");
+        }
+        if (dataType == KeyRequestResource.SYMMETRIC_KEY_TYPE) {
+            if (keyAlgorithm == null || keySize < 0) {
+                throw new IllegalArgumentException(
+                        "Key algorithm and key size are required for a symmetric key type request.");
+            }
+        }
+        if (wrappedPrivateData == null || transWrappedSessionKey == null || algorithmOID == null
+                || symAlgParams == null) {
+            throw new IllegalArgumentException("All data and wrapping parameters must be provided.");
+        }
+        KeyArchivalRequest data = new KeyArchivalRequest();
+
+        data.setDataType(dataType);
+        data.setKeyAlgorithm(keyAlgorithm);
+        data.setKeySize(keySize);
+        data.setClientKeyId(clientKeyId);
+        data.setAlgorithmOID(algorithmOID);
+        data.setSymmetricAlgorithmParams(symAlgParams);
+        String req1 = Utils.base64encode(wrappedPrivateData);
+        data.setWrappedPrivateData(req1);
+        data.setTransWrappedSessionKey(Utils.base64encode(transWrappedSessionKey));
+
+        return createRequest(data);
+    }
+
+    /**
+     * Archive a secret (symmetric key or passphrase) on the DRM using a PKIArchiveOptions data format.
+     *
+     * @param clientKeyId
+     * @param dataType
+     * @param algorithm
+     * @param strength
+     * @param pkiArchiveOptions -- is the data to be archived wrapped in a
+     *            PKIArchiveOptions structure
+     * @return
+     * @throws Exception
+     */
+    public KeyRequestResponse archiveOptionsData(String clientKeyId, String dataType, String keyAlgorithm, int keySize,
+            byte[] pkiArchiveOptions) throws Exception {
+
+        if (clientKeyId == null || dataType == null) {
+            throw new IllegalArgumentException("Client key id and data type cannot be null");
+        }
+        if (dataType == KeyRequestResource.SYMMETRIC_KEY_TYPE) {
+            if (keyAlgorithm == null || keySize < 0) {
+                throw new IllegalArgumentException(
+                        "Key algorithm and key size are required for a symmetric key type request.");
+            }
+        }
+        if (pkiArchiveOptions == null) {
+            throw new IllegalArgumentException("No data provided to be archived.");
+        }
+        KeyArchivalRequest data = new KeyArchivalRequest();
+
+        data.setClientKeyId(clientKeyId);
+        data.setDataType(dataType);
+        data.setKeyAlgorithm(keyAlgorithm);
+        data.setKeySize(keySize);
+
+        String options = Utils.base64encode(pkiArchiveOptions);
+        data.setPKIArchiveOptions(options);
+
+        return createRequest(data);
+    }
+
+    /**
+     * Generate and archive a symmetric key on the DRM.
+     *
+     * @param clientKeyId
+     * @param keyAlgorithm
+     * @param keySize
+     * @param usages
+     * @return a KeyRequestResponse which contains a KeyRequestInfo
+     *         object that describes the URL for the request and generated key.
+     */
+    public KeyRequestResponse generateSymmetricKey(String clientKeyId, String keyAlgorithm, int keySize,
+            List<String> usages, String transWrappedSessionKey) {
+        if (clientKeyId == null) {
+            throw new IllegalArgumentException("Client Key Identifier cannot be null");
+        }
+
+        SymKeyGenerationRequest data = new SymKeyGenerationRequest();
+        data.setClientKeyId(clientKeyId);
+        data.setKeyAlgorithm(keyAlgorithm);
+        data.setKeySize(new Integer(keySize));
+        data.setUsages(usages);
+
+        return createRequest(data);
     }
 }
+
+class CryptoOperationStore {
+
+    private CryptoManager manager = null;
+    private CryptoToken token = null;
+
+    public CryptoOperationStore(PKIClient client) throws KeyDatabaseException,
+            CertDatabaseException, GeneralSecurityException, NotInitializedException, TokenException,
+            IncorrectPasswordException {
+
+        String dbDir = client.getConfig().getCertDatabase();
+        String tokenPwd = client.getConfig().getCertPassword();
+
+        // Initialize token
+        try {
+            CryptoManager.initialize(dbDir);
+        } catch (AlreadyInitializedException e) {
+            // Can be ignored since it is just for getting the token
+        } catch (KeyDatabaseException | CertDatabaseException | GeneralSecurityException e1) {
+            throw e1;
+        }
+
+        // log into token
+        try {
+            manager = CryptoManager.getInstance();
+            token = manager.getInternalKeyStorageToken();
+            Password password = new Password(tokenPwd.toCharArray());
+            try {
+                token.login(password);
+            } catch (IncorrectPasswordException | TokenException e) {
+                if (!token.isLoggedIn()) {
+                    token.initPassword(password, password);
+                }
+            }
+        } catch (AlreadyInitializedException e1) {
+            //Ignore
+        } catch (NotInitializedException | TokenException | IncorrectPasswordException e2) {
+            throw e2;
+        }
+    }
+
+    /**
+     * Generate a session key
+     *
+     * @param token
+     * @return
+     * @throws NoSuchAlgorithmException
+     * @throws IllegalStateException
+     * @throws TokenException
+     */
+    public SymmetricKey generateSessionKey() throws NoSuchAlgorithmException,
+            IllegalStateException, TokenException {
+
+        return CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+    }
+
+    public byte[] wrapSessionKeyWithTransportCert(SymmetricKey sessionKey, String transportCert)
+            throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException, TokenException {
+
+        return CryptoUtil.wrapSymmetricKey(manager, token, transportCert, sessionKey);
+    }
+
+    public String unwrapUsingSessionKey(String wrappedPrivateData, SymmetricKey key, String nonceData)
+            throws InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, TokenException,
+            BadPaddingException, IllegalBlockSizeException {
+
+        return new String(Utils.base64decode(CryptoUtil.unwrapUsingSymmetricKey(token, new IVParameterSpec(Utils.base64decode(nonceData)),
+                Utils.base64decode(wrappedPrivateData), key, EncryptionAlgorithm.DES3_CBC_PAD)));
+    }
+
+    public byte[] wrapUsingSessionKey(byte[] nonceData, String passphrase, SymmetricKey key)
+            throws InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, TokenException,
+            IllegalBlockSizeException, BadPaddingException, IOException {
+
+        return CryptoUtil.wrapPassphrase(token, passphrase, new IVParameterSpec(nonceData), key,
+                EncryptionAlgorithm.DES3_CBC_PAD);
+    }
+
+    /**
+     * Generates a nonve_iv for padding.
+     * @return
+     */
+    public static byte[] getNonceData(int size) {
+        byte[] iv = new byte[size];
+        Random rnd = new Random();
+        rnd.nextBytes(iv);
+
+        return iv;
+    }
+}
\ No newline at end of file
diff --git a/base/common/src/com/netscape/certsrv/key/KeyData.java b/base/common/src/com/netscape/certsrv/key/KeyData.java
index 4fcb6b4209c1a977b8b7e1d559728beb2046dc61..6da4d38ec940afdc794b09a5c72b9419bebb9e7c 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyData.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyData.java
@@ -31,7 +31,7 @@ import javax.xml.bind.annotation.XmlRootElement;
  *
  */
 @XmlRootElement(name="KeyData")
-@XmlAccessorType(XmlAccessType.FIELD)
+@XmlAccessorType(XmlAccessType.NONE)
 public class KeyData {
     @XmlElement
     String wrappedPrivateData;
@@ -48,6 +48,8 @@ public class KeyData {
     @XmlElement
     Integer size;
 
+    String privateData;
+
     public KeyData() {
         // required for JAXB (defaults)
     }
@@ -123,4 +125,12 @@ public class KeyData {
     public void setSize(Integer size) {
         this.size = size;
     }
+
+    public String getPrivateData() {
+        return privateData;
+    }
+
+    public void setPrivateData(String privateData) {
+        this.privateData = privateData;
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/key/KeyRequestResponse.java b/base/common/src/com/netscape/certsrv/key/KeyRequestResponse.java
index 1d21b4cec090a6cf07dce67ee273733ec1730660..cbb211026ca5784a1df635a0300f10933c14392d 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyRequestResponse.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyRequestResponse.java
@@ -21,6 +21,9 @@ package com.netscape.certsrv.key;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import com.netscape.certsrv.dbs.keydb.KeyId;
+import com.netscape.certsrv.request.RequestId;
+
 @XmlRootElement(name = "KeyRequestResponse")
 public class KeyRequestResponse {
     KeyRequestInfo requestInfo;
@@ -43,4 +46,12 @@ public class KeyRequestResponse {
     public void setKeyData(KeyData keyData) {
         this.keyData = keyData;
     }
+
+    public KeyId getKeyId(){
+        return this.requestInfo.getKeyId();
+    }
+
+    public RequestId getRequestId(){
+        return this.requestInfo.getRequestId();
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/kra/KRAClient.java b/base/common/src/com/netscape/certsrv/kra/KRAClient.java
index 1cdb879e64d7bfce60e74448cb30d312744cca43..f4332a8d7dc7cc3842cfcbb4fd6f53b08d3b7cd5 100644
--- a/base/common/src/com/netscape/certsrv/kra/KRAClient.java
+++ b/base/common/src/com/netscape/certsrv/kra/KRAClient.java
@@ -1,6 +1,13 @@
 package com.netscape.certsrv.kra;
 
 import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+
+import org.mozilla.jss.CertDatabaseException;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
+import org.mozilla.jss.KeyDatabaseException;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.util.IncorrectPasswordException;
 
 import com.netscape.certsrv.client.PKIClient;
 import com.netscape.certsrv.client.SubsystemClient;
@@ -13,12 +20,14 @@ import com.netscape.certsrv.user.UserClient;
 
 public class KRAClient extends SubsystemClient {
 
-    public KRAClient(PKIClient client) throws URISyntaxException {
+    public KRAClient(PKIClient client) throws URISyntaxException, KeyDatabaseException, CertDatabaseException,
+            GeneralSecurityException, NotInitializedException, IncorrectPasswordException, TokenException {
         super(client, "kra");
         init();
     }
 
-    public void init() throws URISyntaxException {
+    public void init() throws URISyntaxException, KeyDatabaseException, CertDatabaseException,
+            GeneralSecurityException, NotInitializedException, IncorrectPasswordException, TokenException {
 
         addClient(new AuditClient(client, name));
         addClient(new GroupClient(client, name));
diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java
index ce095a22ed23da7f88fc984048e2c85adca1a291..53e9bccc9e76ea90182abb28a877aabc382553ff 100644
--- a/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java
@@ -97,7 +97,7 @@ public class KeyFindCLI extends CLI {
         s = cmd.getOptionValue("size");
         Integer size = s == null ? null : Integer.valueOf(s);
 
-        KeyInfoCollection keys = keyCLI.keyClient.findKeys(clientKeyID, status, maxResults, maxTime, start, size);
+        KeyInfoCollection keys = keyCLI.keyClient.listKeys(clientKeyID, status, maxResults, maxTime, start, size);
 
         Collection<KeyInfo> entries = keys.getEntries();
 
diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java
index d1385b0a5dff0e3e253878618868a6920eb31c76..bc4efb411c1411a2baf963b07596b2fe815a1bda 100644
--- a/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java
@@ -103,7 +103,7 @@ public class KeyRequestFindCLI extends CLI {
         s = cmd.getOptionValue("maxTime");
         Integer maxTime = s == null ? null : Integer.valueOf(s);
 
-        KeyRequestInfoCollection keys = keyCLI.keyClient.findRequests(
+        KeyRequestInfoCollection keys = keyCLI.keyClient.listRequests(
                 status, type, clientKeyID, start, pageSize, maxResults, maxTime);
 
         MainCLI.printMessage(keys.getTotal() + " entries matched");
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
index 621d95d0b53117d6598ee4a7735a152ea28ec5c9..2c6ad6bc6b8c63cc7706d99771f38e096a4c0b07 100644
--- a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
@@ -204,7 +204,6 @@ public class DRMTest {
 
         // Set base URI and get client
 
-
         KRAClient client;
         SystemCertClient systemCertClient;
         KeyClient keyClient;
@@ -212,10 +211,12 @@ public class DRMTest {
             ClientConfig config = new ClientConfig();
             config.setServerURI(protocol + "://" + host + ":" + port + "/kra");
             config.setCertNickname(clientCertNickname);
+            config.setCertDatabase(db_dir);
+            config.setCertPassword(token_pwd);
 
             client = new KRAClient(new PKIClient(config));
-            systemCertClient = (SystemCertClient)client.getClient("systemcert");
-            keyClient = (KeyClient)client.getClient("key");
+            systemCertClient = (SystemCertClient) client.getClient("systemcert");
+            keyClient = (KeyClient) client.getClient("key");
 
         } catch (Exception e) {
             e.printStackTrace();
@@ -225,13 +226,14 @@ public class DRMTest {
         // Test 1: Get transport certificate from DRM
         transportCert = systemCertClient.getTransportCert().getEncoded();
         transportCert = transportCert.substring(PKIService.HEADER.length(),
-                                                transportCert.indexOf(PKIService.TRAILER));
+                transportCert.indexOf(PKIService.TRAILER));
+        keyClient.setTransportCert(transportCert);
 
         log("Transport Cert retrieved from DRM: " + transportCert);
 
         // Test 2: Get list of completed key archival requests
         log("\n\nList of completed archival requests");
-        KeyRequestInfoCollection list = keyClient.findRequests("complete", "securityDataEnrollment");
+        KeyRequestInfoCollection list = keyClient.listRequests("complete", "securityDataEnrollment");
         if (list.getTotal() == 0) {
             log("No requests found");
         } else {
@@ -244,7 +246,7 @@ public class DRMTest {
 
         // Test 3: Get list of key recovery requests
         log("\n\nList of completed recovery requests");
-        KeyRequestInfoCollection list2 = keyClient.findRequests("complete", "securityDataRecovery");
+        KeyRequestInfoCollection list2 = keyClient.listRequests("complete", "securityDataRecovery");
         if (list2.getTotal() == 0) {
             log("No requests found");
         } else {
@@ -257,13 +259,13 @@ public class DRMTest {
 
         // Test 4: Generate and archive a symmetric key
         log("Archiving symmetric key");
-        clientKeyId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime();
+        clientKeyId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime().toString();
         try {
             vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
             byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
                     KeyGenAlgorithm.DES3, ivps);
 
-            KeyRequestResponse info = keyClient.archiveSecurityData(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE,
+            KeyRequestResponse info = keyClient.archiveOptionsData(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE,
                     KeyRequestResource.DES3_ALGORITHM, 0, encoded);
             log("Archival Results:");
             printRequestInfo(info.getRequestInfo());
@@ -296,28 +298,18 @@ public class DRMTest {
         try {
             recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
             wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            KeyRequestResponse info = keyClient.requestRecovery(keyId, null, wrappedRecoveryKey,
-                    ivps.getIV());
-            recoveryRequestId = info.getRequestInfo().getRequestId();
+            keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey);
         } catch (Exception e) {
             log("Exception in recovering symmetric key using session key: " + e.getMessage());
         }
 
-        // Test 7: Approve recovery
-        log("Approving recovery request: " + recoveryRequestId);
-        keyClient.approveRequest(recoveryRequestId);
-
-        // Test 8: Get key
-        log("Getting key: " + keyId);
-
-        keyData = keyClient.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
 
         ivps_server = new IVParameterSpec(Utils.base64decode(keyData.getNonceData()));
         try {
-            recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
+            recoveredKey = new String(Utils.base64decode(CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
                     Utils.base64decode(wrappedRecoveredKey),
-                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
+                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD)));
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
             e.printStackTrace();
@@ -329,7 +321,7 @@ public class DRMTest {
             log("Success: recoverd and archived keys match!");
         }
 
-        // Test 9: Submit a recovery request for the symmetric key using a passphrase
+        // Test 7: Submit a recovery request for the symmetric key using a passphrase
         log("Submitting a recovery request for the  symmetric key using a passphrase");
         recoveryPassphrase = "Gimme me keys please";
 
@@ -339,20 +331,13 @@ public class DRMTest {
                     EncryptionAlgorithm.DES3_CBC_PAD);
             wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
 
-            requestResponse = keyClient.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
-            recoveryRequestId = requestResponse.getRequestInfo().getRequestId();
+            keyData = keyClient.retrieveKeyByPassphrase(keyId, null, wrappedRecoveryKey, wrappedRecoveryPassphrase,
+                    ivps.getIV());
         } catch (Exception e) {
             log("Exception in recovering symmetric key using passphrase" + e.toString());
             e.printStackTrace();
         }
 
-        //Test 10: Approve recovery
-        log("Approving recovery request: " + recoveryRequestId);
-        keyClient.approveRequest(recoveryRequestId);
-
-        // Test 11: Get key
-        log("Getting key: " + keyId);
-        keyData = keyClient.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
 
         try {
@@ -368,15 +353,13 @@ public class DRMTest {
             log("Success: recovered and archived keys do match!");
         }
 
-
         passphrase = "secret12345";
-        // Test 12: Generate and archive a passphrase
-        clientKeyId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime();
+        // Test 8: Generate and archive a passphrase
+        clientKeyId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime().toString();
         try {
-            byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, null, passphrase,
-                    KeyGenAlgorithm.DES3, ivps);
-            requestResponse = keyClient.archiveSecurityData(clientKeyId, KeyRequestResource.PASS_PHRASE_TYPE,
-                    null, 0, encoded);
+            requestResponse = keyClient.archiveKey(clientKeyId, KeyRequestResource.PASS_PHRASE_TYPE, passphrase, null,
+                    0);
+
             log("Archival Results:");
             printRequestInfo(requestResponse.getRequestInfo());
             keyId = requestResponse.getRequestInfo().getKeyId();
@@ -385,7 +368,7 @@ public class DRMTest {
             e.printStackTrace();
         }
 
-        //Test 13: Get keyId for active passphrase with client ID
+        //Test 9: Get keyId for active passphrase with client ID
         log("Getting key ID for passphrase");
         keyInfo = keyClient.getActiveKeyInfo(clientKeyId);
         printKeyInfo(keyInfo);
@@ -402,36 +385,23 @@ public class DRMTest {
             log("Success: key ids from search and archival do match!");
         }
 
-        // Test 14: Submit a recovery request for the passphrase using a session key
+        // Test 10: Submit a recovery request for the passphrase using a session key
         log("Submitting a recovery request for the passphrase using session key");
         recoveryKey = null;
-        recoveryRequestId = null;
         wrappedRecoveryKey = null;
         try {
             recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
             wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
             wrappedRecoveryPassphrase = CryptoUtil.wrapPassphrase(token, recoveryPassphrase, ivps, recoveryKey,
                     EncryptionAlgorithm.DES3_CBC_PAD);
-            requestResponse = keyClient.requestRecovery(keyId, null, wrappedRecoveryKey, ivps.getIV());
-            recoveryRequestId = requestResponse.getRequestInfo().getRequestId();
+            keyData = keyClient.retrieveKeyByPassphrase(keyId, recoveryPassphrase, null, null, null);
         } catch (Exception e) {
             log("Exception in recovering passphrase using session key: " + e.getMessage());
         }
-
-        // Test 15: Approve recovery
-        log("Approving recovery request: " + recoveryRequestId);
-        keyClient.approveRequest(recoveryRequestId);
-
-        // Test 16: Get key
-        log("Getting passphrase: " + keyId);
-
-        keyData = keyClient.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
-        ivps_server = new IVParameterSpec( Utils.base64decode(keyData.getNonceData()));
+        ivps_server = new IVParameterSpec(Utils.base64decode(keyData.getNonceData()));
         try {
-            recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
-                    Utils.base64decode(wrappedRecoveredKey),
-                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
+            recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
             recoveredKey = new String(Utils.base64decode(recoveredKey), "UTF-8");
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
@@ -444,18 +414,16 @@ public class DRMTest {
             log("Success: recovered and archived passphrases do match!");
         }
 
-        // Test 17: Submit a recovery request for the passphrase using a passphrase
-        log("Submitting a recovery request for the passphrase using a passphrase");
-        requestResponse = keyClient.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
-        recoveryRequestId = requestResponse.getRequestInfo().getRequestId();
-
-        //Test 18: Approve recovery
-        log("Approving recovery request: " + recoveryRequestId);
-        keyClient.approveRequest(recoveryRequestId);
-
-        // Test 19: Get key
-        log("Getting passphrase: " + keyId);
-        keyData = keyClient.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+        // Test 11: Submit a recovery request for the passphrase using a passphrase
+        try {
+            keyData = keyClient.retrieveKeyByPassphrase(keyId, null, wrappedRecoveryKey, wrappedRecoveryPassphrase,
+                    ivps.getIV());
+        } catch (Exception e1) {
+            // TODO Auto-generated catch block
+            e1.printStackTrace();
+            System.out.println("Test 17: " + e1.getMessage());
+            System.exit(-1);
+        }
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
         try {
             recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
@@ -471,20 +439,18 @@ public class DRMTest {
             log("Success: recovered and archived passphrases do match!");
         }
 
-        // Test 20: Submit a recovery request for the passphrase using a passphrase
-        //Wait until retrieving key before sending input data.
-
-        log("Submitting a recovery request for the passphrase using a passphrase, wait till end to provide recovery data.");
-        requestResponse = keyClient.requestRecovery(keyId, null, null, null);
-        recoveryRequestId = requestResponse.getRequestInfo().getRequestId();
-
-        //Test 21: Approve recovery
-        log("Approving recovery request: " + recoveryRequestId);
-        keyClient.approveRequest(recoveryRequestId);
-
-        // Test 22: Get key
+        // Test 12: Get key
         log("Getting passphrase: " + keyId);
-        keyData = keyClient.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, ivps.getIV());
+        try {
+            keyData = keyClient.retrieveKeyByPassphrase(keyId, null, wrappedRecoveryKey, wrappedRecoveryPassphrase,
+                    ivps.getIV());
+        } catch (Exception e1) {
+            // TODO Auto-generated catch block
+            e1.printStackTrace();
+            e1.printStackTrace();
+            System.out.println("Test 22: " + e1.getMessage());
+            System.exit(-1);
+        }
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
         try {
             recoveredKey = CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
@@ -500,47 +466,48 @@ public class DRMTest {
             log("Success: recovered and archived passphrases do match!");
         }
 
-        // Test 23: Get non-existent request
+        // Test 13: Get non-existent request
         RequestId requestId = new RequestId("0xabcdef");
         log("Getting non-existent request: " + requestId.toHexString());
         try {
             keyClient.getRequestInfo(requestId);
             log("Error: getting non-existent request does not throw an exception");
         } catch (RequestNotFoundException e) {
-            log("Success: getting non-existent request throws an exception: "+e.getMessage()+" ("+e.getRequestId().toHexString()+")");
+            log("Success: getting non-existent request throws an exception: " + e.getMessage() + " ("
+                    + e.getRequestId().toHexString() + ")");
         }
 
-        // Test 24: Request x509 key recovery
+        // Test 14: Request x509 key recovery
         // This test requires to retrieve keyId and matching certificate
         // from installed instances of CA and DRM
         String keyID = "1";
-        String b64Certificate = "MIIC+TCCAeGgAwIBAgIBDDANBgkqhkiG9w0BAQsFADBOMSswKQYDVQQKDCJ1c2Vy"+
-                                "c3lzLnJlZGhhdC5jb20gU2VjdXJpdHkgRG9tYWluMR8wHQYDVQQDDBZDQSBTaWdu"+
-                                "aW5nIENlcnRpZmljYXRlMB4XDTEzMTAyNTE5MzQwM1oXDTE0MDQyMzE5MzQwM1ow"+
-                                "EzERMA8GCgmSJomT8ixkAQEMAXgwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB"+
-                                "ALhLfGmKvxFsKXPh49q1QsluXU3WlyS1XnpDLgOAhgTNgO4sG6CpPdv6hZYIvQBb"+
-                                "ZQ5bhuML+NXK+Q+EIiNk1cUTxgL3a30sPzy6QaFWxwM8i4uXm4nCBYv7T+n4V6/O"+
-                                "xHIM2Ch/dviAb3vz+M9trErv9t+d2H8jNXT3sHuDb/kvAgMBAAGjgaAwgZ0wHwYD"+
-                                "VR0jBBgwFoAUh1cxWFRY+nMsx4odQQI1GqyFxP8wSwYIKwYBBQUHAQEEPzA9MDsG"+
-                                "CCsGAQUFBzABhi9odHRwOi8vZG9ndGFnMjAudXNlcnN5cy5yZWRoYXQuY29tOjgw"+
-                                "ODAvY2Evb2NzcDAOBgNVHQ8BAf8EBAMCBSAwHQYDVR0lBBYwFAYIKwYBBQUHAwIG"+
-                                "CCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQCvmbUzQOouE2LgQQcKfmgwwJMJ"+
-                                "9tMrPwDUtyFdaIFoPL4uZaujSscaN4IWK2r5vIMJ65jwYCI7sI9En2ZfO28J9dQj"+
-                                "lpqu6TaJ+xtaMk7OvXpVB7lJk73HAttMGjETlkoq/6EjxcugmJsDqVD0b2tO7Vd0"+
-                                "hroBe2uPDHM2ASewZF415lUcRh0URtmxSazTInbyxpmy1wgSJQ0C6fMCeT+hUFlA"+
-                                "0P4k1TIprapGVq7FpKcqlhK2gTBfTSnoO7gmXG/9MxJiYpb/Aph8ptXq6quHz1Mj"+
-                                "greWr3xTsy6gF2yphUEkGHh4v22XvK+FLx9Jb6zloMWA2GG9gpUpvMnl1fH4";
+        String b64Certificate = "MIIC+TCCAeGgAwIBAgIBDDANBgkqhkiG9w0BAQsFADBOMSswKQYDVQQKDCJ1c2Vy" +
+                "c3lzLnJlZGhhdC5jb20gU2VjdXJpdHkgRG9tYWluMR8wHQYDVQQDDBZDQSBTaWdu" +
+                "aW5nIENlcnRpZmljYXRlMB4XDTEzMTAyNTE5MzQwM1oXDTE0MDQyMzE5MzQwM1ow" +
+                "EzERMA8GCgmSJomT8ixkAQEMAXgwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB" +
+                "ALhLfGmKvxFsKXPh49q1QsluXU3WlyS1XnpDLgOAhgTNgO4sG6CpPdv6hZYIvQBb" +
+                "ZQ5bhuML+NXK+Q+EIiNk1cUTxgL3a30sPzy6QaFWxwM8i4uXm4nCBYv7T+n4V6/O" +
+                "xHIM2Ch/dviAb3vz+M9trErv9t+d2H8jNXT3sHuDb/kvAgMBAAGjgaAwgZ0wHwYD" +
+                "VR0jBBgwFoAUh1cxWFRY+nMsx4odQQI1GqyFxP8wSwYIKwYBBQUHAQEEPzA9MDsG" +
+                "CCsGAQUFBzABhi9odHRwOi8vZG9ndGFnMjAudXNlcnN5cy5yZWRoYXQuY29tOjgw" +
+                "ODAvY2Evb2NzcDAOBgNVHQ8BAf8EBAMCBSAwHQYDVR0lBBYwFAYIKwYBBQUHAwIG" +
+                "CCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQCvmbUzQOouE2LgQQcKfmgwwJMJ" +
+                "9tMrPwDUtyFdaIFoPL4uZaujSscaN4IWK2r5vIMJ65jwYCI7sI9En2ZfO28J9dQj" +
+                "lpqu6TaJ+xtaMk7OvXpVB7lJk73HAttMGjETlkoq/6EjxcugmJsDqVD0b2tO7Vd0" +
+                "hroBe2uPDHM2ASewZF415lUcRh0URtmxSazTInbyxpmy1wgSJQ0C6fMCeT+hUFlA" +
+                "0P4k1TIprapGVq7FpKcqlhK2gTBfTSnoO7gmXG/9MxJiYpb/Aph8ptXq6quHz1Mj" +
+                "greWr3xTsy6gF2yphUEkGHh4v22XvK+FLx9Jb6zloMWA2GG9gpUpvMnl1fH4";
 
         log("Requesting X509 key recovery.");
-        recoveryRequestId = keyClient.requestKeyRecovery(keyID,
-                b64Certificate).getRequestInfo().getRequestId();
+        recoveryRequestId = keyClient.recoverKey(new KeyId(keyID), null, null, null, b64Certificate).getRequestInfo()
+                .getRequestId();
         log("Requesting X509 key recovery request: " + recoveryRequestId);
 
-        // Test 25: Approve x509 key recovery
+        // Test 55: Approve x509 key recovery
         log("Approving X509 key recovery request: " + recoveryRequestId);
         keyClient.approveRequest(recoveryRequestId);
 
-        // Test 26: Recover x509 key
+        // Test 16: Recover x509 key
         log("Recovering X509 key based on request: " + recoveryRequestId);
         try {
             // KeyData recoveredX509Key = client.recoverKey(recoveryRequestId, "netscape");
@@ -549,17 +516,16 @@ public class DRMTest {
             log("Error: recovering X509Key");
         }
 
-
         // Test 1: Get transport certificate from DRM
         transportCert = systemCertClient.getTransportCert().getEncoded();
         transportCert = transportCert.substring(PKIService.HEADER.length(),
-                                                transportCert.indexOf(PKIService.TRAILER));
+                transportCert.indexOf(PKIService.TRAILER));
 
         log("Transport Cert retrieved from DRM: " + transportCert);
 
-        // Test 27: Get list of completed key archival requests
+        // Test 17: Get list of completed key archival requests
         log("\n\nList of completed archival requests");
-        list = keyClient.findRequests("complete", IRequest.SYMKEY_GENERATION_REQUEST);
+        list = keyClient.listRequests("complete", IRequest.SYMKEY_GENERATION_REQUEST);
         if (list.getTotal() == 0) {
             log("No requests found");
         } else {
@@ -570,18 +536,18 @@ public class DRMTest {
             }
         }
 
-        // test 28: Generate symmetric key
-        clientKeyId = "Symmetric Key #1234f " + Calendar.getInstance().getTime();
+        // test 18: Generate symmetric key
+        clientKeyId = "Symmetric Key #1234f " + Calendar.getInstance().getTime().toString();
         List<String> usages = new ArrayList<String>();
         usages.add(SymKeyGenerationRequest.DECRYPT_USAGE);
         usages.add(SymKeyGenerationRequest.ENCRYPT_USAGE);
-        KeyRequestResponse genKeyResponse = keyClient.generateKey(clientKeyId,
+        KeyRequestResponse genKeyResponse = keyClient.generateSymmetricKey(clientKeyId,
                 KeyRequestResource.AES_ALGORITHM,
-                128, usages);
+                128, usages, null);
         printRequestInfo(genKeyResponse.getRequestInfo());
         keyId = genKeyResponse.getRequestInfo().getKeyId();
 
-        // test 29: Get keyId for active key with client ID
+        // test 19: Get keyId for active key with client ID
         log("Getting key ID for symmetric key");
         keyInfo = keyClient.getActiveKeyInfo(clientKeyId);
         printKeyInfo(keyInfo);
@@ -598,61 +564,52 @@ public class DRMTest {
             log("Success: keyids from search and archival match.");
         }
 
-        // Test 30: Submit a recovery request for the symmetric key using a session key
+        // Test 20: Submit a recovery request for the symmetric key using a session key
         log("Submitting a recovery request for the  symmetric key using session key");
         try {
             recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
             wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            KeyRequestResponse response = keyClient.requestRecovery(keyId, null, wrappedRecoveryKey, ivps.getIV());
-            recoveryRequestId = response.getRequestInfo().getRequestId();
+            keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey);
         } catch (Exception e) {
             log("Exception in recovering symmetric key using session key: " + e.getMessage());
         }
 
-        // Test 31: Approve recovery
-        log("Approving recovery request: " + recoveryRequestId);
-        keyClient.approveRequest(recoveryRequestId);
-
-        // Test 32: Get key
-        log("Getting key: " + keyId);
-
-        keyData = keyClient.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
 
         ivps_server = new IVParameterSpec(Utils.base64decode(keyData.getNonceData()));
         try {
-            recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
+            recoveredKey = new String(Utils.base64decode(CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
                     Utils.base64decode(wrappedRecoveredKey),
-                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
+                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD)));
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
             e.printStackTrace();
         }
 
-        // test 33: Generate symmetric key - invalid algorithm
+        // test 21: Generate symmetric key - invalid algorithm
         try {
-            genKeyResponse = keyClient.generateKey("Symmetric Key #1235", "AFS", 128, usages);
+            genKeyResponse = keyClient.generateSymmetricKey("Symmetric Key #1235", "AFS", 128, usages, null);
         } catch (Exception e) {
             log("Exception: " + e);
         }
 
-        // test 34: Generate symmetric key - invalid key size
+        // test 22: Generate symmetric key - invalid key size
         try {
-            genKeyResponse = keyClient.generateKey("Symmetric Key #1236", "AES", 135, usages);
+            genKeyResponse = keyClient.generateSymmetricKey("Symmetric Key #1236", "AES", 0, usages, null);
         } catch (Exception e) {
             log("Exception: " + e);
         }
 
-        // test 35: Generate symmetric key - usages not defined
+        // test 23: Generate symmetric key - usages not defined
         try {
-            genKeyResponse = keyClient.generateKey("Symmetric Key #1236", "DES", 56, usages);
+            genKeyResponse = keyClient.generateSymmetricKey("Symmetric Key #1236", "DES", 56, null, null);
         } catch (Exception e) {
             log("Exception: " + e);
         }
 
-        // Test 36: Generate and archive a symmetric key of type AES
+        // Test 24: Generate and archive a symmetric key of type AES
         log("Archiving symmetric key");
-        clientKeyId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime();
+        clientKeyId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime().toString();
         try {
             KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.AES);
             kg.initialize(128);
@@ -661,8 +618,8 @@ public class DRMTest {
             byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
                     KeyGenAlgorithm.DES3, ivps);
 
-            KeyRequestResponse response = keyClient.archiveSecurityData(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE,
-                    KeyRequestResource.AES_ALGORITHM, 128, encoded);
+            KeyRequestResponse response = keyClient.archiveOptionsData(clientKeyId,
+                    KeyRequestResource.SYMMETRIC_KEY_TYPE, KeyRequestResource.AES_ALGORITHM, 128, encoded);
             log("Archival Results:");
             printRequestInfo(response.getRequestInfo());
             keyId = response.getRequestInfo().getKeyId();
@@ -671,7 +628,7 @@ public class DRMTest {
             e.printStackTrace();
         }
 
-        //Test 37: Get keyId for active key with client ID
+        //Test 25: Get keyId for active key with client ID
         log("Getting key ID for symmetric key");
         keyInfo = keyClient.getActiveKeyInfo(clientKeyId);
         printKeyInfo(keyInfo);
@@ -688,32 +645,23 @@ public class DRMTest {
             log("Success: keyids from search and archival match.");
         }
 
-        // Test 38: Submit a recovery request for the symmetric key using a session key
+        // Test 26: Submit a recovery request for the symmetric key using a session key
         log("Submitting a recovery request for the  symmetric key using session key");
         try {
             recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
             wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            KeyRequestResponse response = keyClient.requestRecovery(keyId, null, wrappedRecoveryKey, ivps.getIV());
-            recoveryRequestId = response.getRequestInfo().getRequestId();
+            keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey);
         } catch (Exception e) {
             log("Exception in recovering symmetric key using session key: " + e.getMessage());
         }
 
-        // Test 39: Approve recovery
-        log("Approving recovery request: " + recoveryRequestId);
-        keyClient.approveRequest(recoveryRequestId);
-
-        // Test 40: Get key
-        log("Getting key: " + keyId);
-
-        keyData = keyClient.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, ivps.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
 
         ivps_server = new IVParameterSpec(Utils.base64decode(keyData.getNonceData()));
         try {
-            recoveredKey = CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
+            recoveredKey = new String(Utils.base64decode(CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
                     Utils.base64decode(wrappedRecoveredKey),
-                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD);
+                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD)));
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
             e.printStackTrace();
@@ -725,17 +673,17 @@ public class DRMTest {
             log("Success: recoverd and archived keys match!");
         }
 
-        // Test 41: Get key info
+        // Test 27: Get key info
         log("getting key info for existing key");
         printKeyInfo(keyClient.getKeyInfo(keyId));
 
-        //Test 42: Modify status
+        //Test 28: Modify status
         log("modify the key status");
         keyClient.modifyKeyStatus(keyId, "inactive");
         keyInfo = keyClient.getKeyInfo(keyId);
         printKeyInfo(keyInfo);
 
-        //Test 43:  Confirm no more active keys with this ID
+        //Test 29:  Confirm no more active keys with this ID
         log("look for active keys with this id");
         clientKeyId = keyInfo.getClientKeyID();
         try {
@@ -776,4 +724,4 @@ public class DRMTest {
 
         return new IVParameterSpec(iv);
     }
-}
+}
\ No newline at end of file
-- 
1.8.5.3

