>From 0ed7fc64eb64d16b893b6731e1af449b1c2a72a0 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/cms/servlet/test/CATest.java  |   2 +-
 .../cms/servlet/test/ConfigurationTest.java        |   2 +-
 .../src/com/netscape/certsrv/client/PKIClient.java |  14 +-
 .../src/com/netscape/certsrv/key/KeyClient.java    | 650 +++++++++++++++++----
 .../src/com/netscape/certsrv/key/KeyData.java      |  12 +-
 .../netscape/certsrv/key/KeyRequestResource.java   |   3 +
 .../netscape/certsrv/key/KeyRequestResponse.java   |  14 +
 .../src/com/netscape/certsrv/kra/KRAClient.java    |   6 +-
 .../com/netscape/certsrv/util/CryptoProvider.java  |  25 +
 .../netscape/certsrv/util/NSSCryptoProvider.java   | 178 ++++++
 .../src/com/netscape/cmstools/cli/MainCLI.java     |   2 +-
 .../src/com/netscape/cmstools/key/KeyFindCLI.java  |   2 +-
 .../netscape/cmstools/key/KeyRequestFindCLI.java   |   2 +-
 .../src/com/netscape/cms/servlet/test/DRMTest.java | 280 ++++-----
 .../cms/servlet/csadmin/ConfigurationUtils.java    |   6 +-
 .../com/netscape/cmsutil/crypto/CryptoUtil.java    |  14 +
 .../src/com/netscape/beakertests/CATestJunit.java  |   2 +-
 17 files changed, 924 insertions(+), 290 deletions(-)
 create mode 100644 base/common/src/com/netscape/certsrv/util/CryptoProvider.java
 create mode 100644 base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java

diff --git a/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java b/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java
index 548b1f98b0179d06855c68ba274c665c16ce38e8..15023cad939abb11927abc64fe5916e04cb65661 100644
--- a/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java
+++ b/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java
@@ -161,7 +161,7 @@ public class CATest {
             config.setServerURI(protocol + "://" + host + ":" + port);
             config.setCertNickname(clientCertNickname);
 
-            client = new CAClient(new PKIClient(config));
+            client = new CAClient(new PKIClient(config, null));
             certClient = (CertClient)client.getClient("cert");
             profileClient = (ProfileClient)client.getClient("profile");
 
diff --git a/base/common/functional/src/com/netscape/cms/servlet/test/ConfigurationTest.java b/base/common/functional/src/com/netscape/cms/servlet/test/ConfigurationTest.java
index 145575697fe7182d173eed978b529b018d10bb2d..3b21b652e6ef1a3470a07d8e818295057d1d544a 100644
--- a/base/common/functional/src/com/netscape/cms/servlet/test/ConfigurationTest.java
+++ b/base/common/functional/src/com/netscape/cms/servlet/test/ConfigurationTest.java
@@ -190,7 +190,7 @@ public class ConfigurationTest {
             ClientConfig config = new ClientConfig();
             config.setServerURI(protocol + "://" + host + ":" + port);
 
-            client = new SystemConfigClient(new PKIClient(config), cstype);
+            client = new SystemConfigClient(new PKIClient(config, null), cstype);
         } catch (URISyntaxException e1) {
             e1.printStackTrace();
             System.exit(1);
diff --git a/base/common/src/com/netscape/certsrv/client/PKIClient.java b/base/common/src/com/netscape/certsrv/client/PKIClient.java
index 4f5a98d25b12246936ee9a0d3451ef2b55197cba..c23e8b600b125d0a2da14dcec1880fb05598f42a 100644
--- a/base/common/src/com/netscape/certsrv/client/PKIClient.java
+++ b/base/common/src/com/netscape/certsrv/client/PKIClient.java
@@ -28,6 +28,7 @@ import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
 import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.util.CryptoProvider;
 import com.netscape.cmsutil.util.Utils;
 
 
@@ -37,12 +38,13 @@ public class PKIClient {
 
     public ClientConfig config;
     public PKIConnection connection;
+    public CryptoProvider crypto;
 
     public boolean verbose;
 
-    public PKIClient(ClientConfig config) {
+    public PKIClient(ClientConfig config, CryptoProvider crypto) {
         this.config = config;
-
+        this.crypto = crypto;
         connection = new PKIConnection(this);
     }
 
@@ -82,6 +84,14 @@ public class PKIClient {
         return config;
     }
 
+    public CryptoProvider getCrypto() {
+        return crypto;
+    }
+
+    public void setCrypto(CryptoProvider crypto) {
+        this.crypto = crypto;
+    }
+
     public PKIConnection getConnection() {
         return connection;
     }
diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java
index 0fa1f264e8c3723b5eec02794b5d0b66408a090f..ca196fffd0711baedd18baba5e8da01beb5d5c2e 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyClient.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java
@@ -22,24 +22,33 @@ import java.util.List;
 
 import javax.ws.rs.core.Response;
 
+import org.mozilla.jss.crypto.SymmetricKey;
+
 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.certsrv.util.CryptoProvider;
+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 CryptoProvider crypto;
+    private String transportCert;
+
+    public KeyClient(PKIClient client, String subsystem) throws Exception {
         super(client, subsystem, "key");
         init();
+        this.crypto=client.getCrypto();
     }
 
     public void init() throws URISyntaxException {
@@ -47,54 +56,66 @@ 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;
+    }
+
+    public CryptoProvider getCrypto() {
+        return crypto;
+    }
+
+    public void setCrypto(CryptoProvider crypto) {
+        this.crypto = crypto;
+    }
+
+    /**
+     * 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 a 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 -- State of the requests to be queried.
+     * @param requestType -- Type of the requests to be queried.
+     * @param clientKeyID -- Client Key Identifier
+     * @param start -- Start index of list
+     * @param pageSize -- Size of the list to be returned.
+     * @param maxResults -- Maximum number of requests to be fetched
+     * @param maxTime -- Maximum time for the operation to take
+     * @return a KeyRequestInfoCollection object.
+     */
+    public KeyRequestInfoCollection listRequests(
             String requestState,
             String requestType,
             String clientKeyID,
@@ -113,105 +134,520 @@ 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 the KeyRequestInfo object for a specific request.
+     */
     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 -- key id for secret
+     * @return the KeyInfo object for a specific request.
+     */
+    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 -- key id for secret
+     * @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 -- Id of the request
+     */
     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 -- Id of the request
+     */
     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 -- Id of the request
+     */
     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 -- key id for secret
+     * @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 A KeyRequestResponse object containing information about the key request and the key.
+     */
+    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 method:
+     *
+     * 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 -- key id for secret
+     * @param transWrappedSessionKey -- session key wrapped by the transport cert.
+     * @return A KeyData object - containing the wrapped secret if a transWrappedSessionKey is not null.
+     *         If transWrappedSessionKey is null, then a KeyData object with the secret stored as privateData attribute.
+     * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
+     *                     CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException
+     */
+    public KeyData retrieveKey(KeyId keyId, byte[] transWrappedSessionKey) throws Exception{
+
+        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(KeyRequestResource.DES3_ALGORITHM);
+            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(Utils.base64decode(data.getWrappedPrivateData()), sessionKey,
+                            KeyRequestResource.DES3_ALGORITHM, Utils.base64decode(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 -- key id for secret
+     * @param passphrase
+     * @param transWrappedSessionKey
+     * @param sessionWrappedPassphrase
+     * @param nonceData
+     * @return A KeyData object with the secret wrapped by the passphrase provided.
+     * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
+     *                     CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException
+     */
+    public KeyData retrieveKeyByPassphrase(KeyId keyId, String passphrase, byte[] transWrappedSessionKey,
+            byte[] sessionWrappedPassphrase, byte[] nonceData) throws Exception {
+
+        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(KeyRequestResource.DES3_ALGORITHM);
+                transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
+                nonceData = CryptoUtil.getNonceData(8);
+                sessionWrappedPassphrase = crypto.wrapUsingSessionKey(passphrase, nonceData, sessionKey,
+                        KeyRequestResource.DES3_ALGORITHM);
+            }
+        } 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 -- key id for secret
+     * @param certificate -- the certificate associated with the private key
+     * @param passphrase -- A passphrase for the pkcs12 file.
+     * @return A KeyData object with the wrapped secret
+     */
+    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
+     *
+     * @param clientKeyId -- Client Key Identfier
+     * @param dataType -- Type of the secret being archived.
+     * @param privateData -- the raw secret to be archived.
+     * @param keyAlgorithm
+     * @param keySize
+     *        keyAlgorithm and keySize are applicable to symmetric keys only.
+     *        If a symmetric key is being archived, these parameters are required.
+     * @return A KeyRequestResponse object with information about the request.
+     * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
+     *         IOException, CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException,
+     *         BadPaddingException, IllegalBlockSizeException
+     */
+    public KeyRequestResponse archiveKey(String clientKeyId, String dataType, String privateData, String keyAlgorithm,
+            int keySize) 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 (privateData == null) {
+            throw new IllegalArgumentException("No data provided to archive.");
+        }
+        // Default algorithm OID for DES_EDE3_CBC
+        byte[] nonceData = CryptoUtil.getNonceData(8);
+        String symAlgParams = Utils.base64encode(nonceData);
+        SymmetricKey sessionKey = crypto.generateSessionKey(KeyRequestResource.DES3_ALGORITHM);
+        byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
+        byte[] wrappedPrivateData = crypto.wrapUsingSessionKey(privateData, nonceData,
+                sessionKey, KeyRequestResource.DES3_ALGORITHM);
+
+        return archiveWrappedData(clientKeyId, dataType, keyAlgorithm, keySize, KeyRequestResource.DES_EDE3_CBC_AOID,
+                symAlgParams, wrappedPrivateData, transWrappedSessionKey);
+    }
+
+    /**
+     * Archive a secret (symmetric key or passphrase) on the DRM.
+     *
+     * 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 -- Client Key Identifier
+     * @param dataType -- Type of secret being archived
+     * @param keyAlgorithm -- Algorithm used - if the secret is a symmetric key
+     * @param keySize -- Strength of the symmetric key (secret)
+     * @param algorithmOID -- string for the symmetric key wrap
+     * @param symAlgParams -- storing the value of Utils.base64encode(nonceData)
+     * @param wrappedPrivateData -- which is the secret wrapped by a session
+     *                              key (168 bit 3DES symmetric key)
+     * @param transWrappedSessionKey -- session key wrapped by the transport cert.
+     * @return A KeyRequestResponse object with information about the request.
+     */
+    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 -- Client Key Identifier
+     * @param dataType -- Type of secret bring archived
+     * @param keyAlgorithm -- Algorithm used if the secret is a symmetric key
+     * @param keySize -- Strength of the symmetric key
+     * @param pkiArchiveOptions -- is the data to be archived wrapped in a
+     *            PKIArchiveOptions structure
+     * @return A KeyRequestResponse object with information about the request.
+     * @throws Exception
+     */
+    public KeyRequestResponse archiveOptionsData(String clientKeyId, String dataType, String keyAlgorithm, int keySize,
+            byte[] pkiArchiveOptions) {
+
+        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 -- Client Key Identifier
+     * @param keyAlgorithm -- Algorithm to be used to generate the key
+     * @param keySize -- Strength of the algorithm
+     * @param usages -- Usages of the generated key.
+     * @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);
+        data.setTransWrappedSessionKey(transWrappedSessionKey);
+
+        return createRequest(data);
     }
 }
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/KeyRequestResource.java b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
index fb82afe19bbe7bf774f45f96da7c1c8b0dc3cc89..e9097f43ba2f817978a8786971b55f613ba67f79 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
@@ -35,6 +35,9 @@ public interface KeyRequestResource {
     public static final String RC4_ALGORITHM = "RC4";
     public static final String AES_ALGORITHM = "AES";
 
+    /* Algorithm OID */
+    public static final String DES_EDE3_CBC_AOID = "{1 2 840 113549 3 7}";
+
     /**
      * Used to generate list of key requests based on the search parameters
      */
diff --git a/base/common/src/com/netscape/certsrv/key/KeyRequestResponse.java b/base/common/src/com/netscape/certsrv/key/KeyRequestResponse.java
index 1d21b4cec090a6cf07dce67ee273733ec1730660..aadfa354004355990eb631399b94f027c37d42db 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyRequestResponse.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyRequestResponse.java
@@ -18,10 +18,16 @@
 
 package com.netscape.certsrv.key;
 
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
 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")
+@XmlAccessorType(XmlAccessType.NONE)
 public class KeyRequestResponse {
     KeyRequestInfo requestInfo;
     KeyData keyData;
@@ -43,4 +49,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..a218501534f6ca72d88fc693798d784c026cee57 100644
--- a/base/common/src/com/netscape/certsrv/kra/KRAClient.java
+++ b/base/common/src/com/netscape/certsrv/kra/KRAClient.java
@@ -1,7 +1,5 @@
 package com.netscape.certsrv.kra;
 
-import java.net.URISyntaxException;
-
 import com.netscape.certsrv.client.PKIClient;
 import com.netscape.certsrv.client.SubsystemClient;
 import com.netscape.certsrv.group.GroupClient;
@@ -13,12 +11,12 @@ import com.netscape.certsrv.user.UserClient;
 
 public class KRAClient extends SubsystemClient {
 
-    public KRAClient(PKIClient client) throws URISyntaxException {
+    public KRAClient(PKIClient client) throws Exception {
         super(client, "kra");
         init();
     }
 
-    public void init() throws URISyntaxException {
+    public void init() throws Exception {
 
         addClient(new AuditClient(client, name));
         addClient(new GroupClient(client, name));
diff --git a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..0766285a911de062001994a1ec51adc0547dcf4e
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
@@ -0,0 +1,25 @@
+package com.netscape.certsrv.util;
+
+import org.mozilla.jss.crypto.SymmetricKey;
+
+public abstract class CryptoProvider {
+
+    public abstract void initialize() throws Exception;
+
+    public abstract SymmetricKey generateSymmetricKey(String keyAlgorithm) throws Exception;
+
+    public abstract SymmetricKey generateSessionKey(String keyAlgorithm) throws Exception;
+
+    public abstract byte[] wrapSessionKeyWithTransportCert(SymmetricKey sessionKey, String transportCert)
+            throws Exception;
+
+    public abstract byte[] wrapUsingSessionKey(String passphrase, byte[] iv, SymmetricKey key, String keyAlgorithm)
+            throws Exception;
+
+    public abstract String unwrapUsingSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+            String keyAlgorithm, byte[] nonceData) throws Exception;
+
+    public abstract String unWrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase)
+            throws Exception;
+
+}
diff --git a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..050bbf691133a7cb5211df4291b350e2789b36b1
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
@@ -0,0 +1,178 @@
+package com.netscape.certsrv.util;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+
+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.asn1.InvalidBERException;
+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.client.ClientConfig;
+import com.netscape.certsrv.key.KeyRequestResource;
+import com.netscape.cmsutil.crypto.CryptoUtil;
+
+public class NSSCryptoProvider extends CryptoProvider {
+
+    CryptoManager manager;
+    CryptoToken token;
+    ClientConfig config;
+
+    public NSSCryptoProvider(ClientConfig config)
+            throws Exception {
+        this.config = config;
+        initialize();
+    }
+
+    @Override
+    public void initialize() throws Exception {
+        // TODO Auto-generated method stub
+        try {
+            CryptoManager.initialize(config.getCertDatabase());
+        } catch (AlreadyInitializedException e) {
+            // Can be ignored since it is just for getting the token
+        } catch (KeyDatabaseException | CertDatabaseException | GeneralSecurityException e1) {
+            throw e1;
+        }
+        try {
+            manager = CryptoManager.getInstance();
+            token = manager.getInternalKeyStorageToken();
+            Password password = new Password(config.getCertPassword().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;
+        }
+    }
+
+    @Override
+    public SymmetricKey generateSymmetricKey(String keyAlgorithm) throws Exception {
+        try {
+            return CryptoUtil.generateKey(token, getKeyGenAlgorithm(keyAlgorithm));
+        } catch (NoSuchAlgorithmException | IllegalStateException | TokenException e) {
+            throw e;
+        }
+    }
+
+    @Override
+    public SymmetricKey generateSessionKey(String keyAlgorithm) throws Exception{
+        return generateSymmetricKey(keyAlgorithm);
+    }
+
+    @Override
+    public byte[] wrapSessionKeyWithTransportCert(SymmetricKey sessionKey, String transportCert) throws Exception{
+        try {
+            return CryptoUtil.wrapSymmetricKey(manager, token, transportCert, sessionKey);
+        } catch (CertificateEncodingException | InvalidKeyException | NoSuchAlgorithmException
+                | InvalidAlgorithmParameterException | TokenException e) {
+            throw e;
+        }
+    }
+
+    @Override
+    public byte[] wrapUsingSessionKey(String passphrase, byte[] iv, SymmetricKey key, String encryptionAlgorithm) throws Exception{
+        try {
+            return CryptoUtil.wrapPassphrase(token, passphrase, new IVParameterSpec(iv), key,
+                    getEncryptionAlgorithm(encryptionAlgorithm));
+        } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | TokenException
+                | IllegalBlockSizeException | BadPaddingException | IOException e) {
+            throw e;
+        }
+    }
+
+    @Override
+    public String unwrapUsingSessionKey(byte[] wrappedRecoveredKey, SymmetricKey recoveryKey,
+            String encryptionAlgorithm, byte[] nonceData) throws Exception{
+        try {
+            return CryptoUtil.unwrapUsingSymmetricKey(token, new IVParameterSpec(nonceData), wrappedRecoveredKey, recoveryKey,
+                    getEncryptionAlgorithm(encryptionAlgorithm));
+        } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | TokenException
+                | BadPaddingException | IllegalBlockSizeException e) {
+            throw e;
+        }
+    }
+
+    @Override
+    public String unWrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase) throws Exception{
+        try {
+            return CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
+        } catch (InvalidKeyException | IllegalStateException | NoSuchAlgorithmException
+                | InvalidAlgorithmParameterException | IOException | InvalidBERException | NotInitializedException
+                | TokenException | IllegalBlockSizeException | BadPaddingException e) {
+            throw e;
+        }
+    }
+
+    public KeyGenAlgorithm getKeyGenAlgorithm(String keyAlgorithm) {
+        KeyGenAlgorithm alg = null;
+        switch (keyAlgorithm) {
+        case KeyRequestResource.AES_ALGORITHM:
+            alg = KeyGenAlgorithm.AES;
+            break;
+        case KeyRequestResource.DES_ALGORITHM:
+            alg = KeyGenAlgorithm.DES;
+            break;
+        case KeyRequestResource.DESEDE_ALGORITHM:
+            alg = KeyGenAlgorithm.DESede;
+            break;
+        case KeyRequestResource.RC2_ALGORITHM:
+            alg = KeyGenAlgorithm.RC2;
+            break;
+        case KeyRequestResource.RC4_ALGORITHM:
+            alg = KeyGenAlgorithm.RC4;
+            break;
+        case KeyRequestResource.DES3_ALGORITHM:
+        default:
+            alg = KeyGenAlgorithm.DES3;
+            break;
+        }
+        return alg;
+    }
+
+    public EncryptionAlgorithm getEncryptionAlgorithm(String encryptionAlgorithm) {
+        EncryptionAlgorithm alg = null;
+        switch (encryptionAlgorithm) {
+        case KeyRequestResource.AES_ALGORITHM:
+            alg = EncryptionAlgorithm.AES_CBC_PAD;
+            break;
+        case KeyRequestResource.DES_ALGORITHM:
+            alg = EncryptionAlgorithm.DES_CBC_PAD;
+            break;
+        case KeyRequestResource.RC2_ALGORITHM:
+            alg = EncryptionAlgorithm.RC2_CBC_PAD;
+            break;
+        case KeyRequestResource.RC4_ALGORITHM:
+            alg = EncryptionAlgorithm.RC4;
+            break;
+        case KeyRequestResource.DES3_ALGORITHM:
+        default:
+            alg = EncryptionAlgorithm.DES3_CBC_PAD;
+            break;
+        }
+        return alg;
+    }
+
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
index 3527238d203964c414f0b04e6bfd8fce922852ba..b40a3295074e390a741b8624d0a27f6bfeb04389 100644
--- a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
@@ -305,7 +305,7 @@ public class MainCLI extends CLI {
 
         }
 
-        client = new PKIClient(config);
+        client = new PKIClient(config, null);
         client.setVerbose(verbose);
 
         PKIConnection connection = client.getConnection();
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..f8bc9ae144867c4c852060487c7519ca7fee25c0 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
@@ -23,12 +23,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
 
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.HelpFormatter;
 import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-import org.apache.commons.cli.PosixParser;
 import org.mozilla.jss.CryptoManager;
 import org.mozilla.jss.crypto.AlreadyInitializedException;
 import org.mozilla.jss.crypto.CryptoToken;
@@ -56,6 +52,7 @@ import com.netscape.certsrv.request.IRequest;
 import com.netscape.certsrv.request.RequestId;
 import com.netscape.certsrv.request.RequestNotFoundException;
 import com.netscape.certsrv.system.SystemCertClient;
+import com.netscape.certsrv.util.NSSCryptoProvider;
 import com.netscape.cms.servlet.base.PKIService;
 import com.netscape.cmsutil.crypto.CryptoUtil;
 import com.netscape.cmsutil.util.Utils;
@@ -69,14 +66,14 @@ public class DRMTest {
     }
 
     public static void main(String args[]) {
-        String host = null;
-        String port = null;
-        String token_pwd = null;
-        String db_dir = "./";
-        String protocol = "http";
-        String clientCertNickname = "KRA Administrator of Instance pki-kra's SjcRedhat Domain ID";
+        String host = "localhost";
+        String port = "8443";
+        String token_pwd = "Secret123";
+        String db_dir = "/tmp/nssdb";
+        String protocol = "https";
+        String clientCertNickname = "PKI Administrator for redhat.com";
 
-        // parse command line arguments
+        /*// parse command line arguments
         Options options = new Options();
         options.addOption("h", true, "Hostname of the DRM");
         options.addOption("p", true, "Port of the DRM");
@@ -131,7 +128,7 @@ public class DRMTest {
         } catch (ParseException e) {
             System.err.println("Error in parsing command line options: " + e.getMessage());
             usage(options);
-        }
+        }*/
 
         // used for crypto operations
         byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
@@ -204,7 +201,6 @@ public class DRMTest {
 
         // Set base URI and get client
 
-
         KRAClient client;
         SystemCertClient systemCertClient;
         KeyClient keyClient;
@@ -212,10 +208,13 @@ public class DRMTest {
             ClientConfig config = new ClientConfig();
             config.setServerURI(protocol + "://" + host + ":" + port + "/kra");
             config.setCertNickname(clientCertNickname);
+            config.setCertDatabase(db_dir);
+            config.setCertPassword(token_pwd);
+            NSSCryptoProvider nss = new NSSCryptoProvider(config);
 
-            client = new KRAClient(new PKIClient(config));
-            systemCertClient = (SystemCertClient)client.getClient("systemcert");
-            keyClient = (KeyClient)client.getClient("key");
+            client = new KRAClient(new PKIClient(config, nss));
+            systemCertClient = (SystemCertClient) client.getClient("systemcert");
+            keyClient = (KeyClient) client.getClient("key");
 
         } catch (Exception e) {
             e.printStackTrace();
@@ -225,13 +224,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 +244,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 +257,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 +296,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 +319,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 +329,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 +351,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 +366,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 +383,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 +412,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 +437,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 +464,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 +514,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 +534,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 +562,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 +616,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 +626,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 +643,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 +671,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 +722,4 @@ public class DRMTest {
 
         return new IVParameterSpec(iv);
     }
-}
+}
\ No newline at end of file
diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index 2ef7090f6ad1d005b27dd43a876403f9cf3d5929..3019716db842dfcb6d2716b48f5fe0f7342e2c15 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -224,7 +224,7 @@ public class ConfigurationUtils {
         config.setServerURI(protocol + "://" + hostname + ":" + port + path);
         config.setCertNickname(clientnickname);
 
-        PKIClient client = new PKIClient(config);
+        PKIClient client = new PKIClient(config, null);
         PKIConnection connection = client.getConnection();
         return connection.post(map);
     }
@@ -338,7 +338,7 @@ public class ConfigurationUtils {
         config.setUsername(user);
         config.setPassword(passwd);
 
-        PKIClient client = new PKIClient(config);
+        PKIClient client = new PKIClient(config, null);
         PKIConnection connection = client.getConnection();
 
         // Ignore the "UNTRUSTED_ISSUER" validity status
@@ -3595,7 +3595,7 @@ public class ConfigurationUtils {
         config.setCertNickname(dbNick);
         config.setCertPassword(dbPass);
 
-        PKIClient client = new PKIClient(config);
+        PKIClient client = new PKIClient(config, null);
         PKIConnection connection = client.getConnection();
 
         // Ignore the "UNTRUSTED_ISSUER" and "CA_CERT_INVALID" validity status
diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
index 5e8e323f4484018bf4775417db879d6e4aa99ae7..6056452e3b471fd0c7b152e4795f1497f51d1d2a 100644
--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -39,6 +39,7 @@ import java.security.interfaces.RSAPublicKey;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.Random;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
@@ -1533,6 +1534,19 @@ public class CryptoUtil {
         return certs;
     }
 
+    /**
+     * 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;
+    }
+
     public static String unwrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase)
             throws IOException, InvalidBERException, InvalidKeyException, IllegalStateException,
             NoSuchAlgorithmException, InvalidAlgorithmParameterException, NotInitializedException, TokenException,
diff --git a/tests/dogtag/dev_java_tests/src/com/netscape/beakertests/CATestJunit.java b/tests/dogtag/dev_java_tests/src/com/netscape/beakertests/CATestJunit.java
index e8d26246544c378f98a9724f4358c66b2f651a6c..15aca05c301dbe9b6adb993d3875d636ebf022a9 100644
--- a/tests/dogtag/dev_java_tests/src/com/netscape/beakertests/CATestJunit.java
+++ b/tests/dogtag/dev_java_tests/src/com/netscape/beakertests/CATestJunit.java
@@ -73,7 +73,7 @@ public class CATestJunit extends PKIJUnitTest {
             config.setServerURI(protocol + "://" + host + ":" + port + "/ca");
             config.setCertNickname(clientCertNickname);
             log("URI::: " + config.getServerURI().toString());
-            client = new CAClient(new PKIClient(config));
+            client = new CAClient(new PKIClient(config, null));
             certClient = (CertClient)client.getClient("cert");
         } catch (Exception e) {
             e.printStackTrace();
-- 
1.8.5.3

