>From 3685c95fad72260f825f109733bb8280400b1f8d Mon Sep 17 00:00:00 2001
From: Abhishek Koneru <akoneru@redhat.com>
Date: Tue, 18 Mar 2014 11:13:30 -0400
Subject: [PATCH] Address comments for Patch 86-2

---
 base/common/python/pki/cryptoutil.py               |   2 +-
 .../src/com/netscape/certsrv/cert/CertData.java    |   4 +
 .../src/com/netscape/certsrv/key/KeyClient.java    | 178 ++++++++++++---------
 .../netscape/certsrv/key/KeyRequestResource.java   |   3 -
 .../src/com/netscape/certsrv/key/KeyResource.java  |   3 +
 .../com/netscape/certsrv/util/CryptoProvider.java  |   4 +-
 .../netscape/certsrv/util/NSSCryptoProvider.java   | 124 ++++++++------
 .../src/com/netscape/cms/servlet/test/DRMTest.java |  67 ++++----
 .../servlet/test/GeneratePKIArchiveOptions.java    |   6 +-
 .../com/netscape/cms/servlet/base/PKIService.java  |   5 +-
 .../com/netscape/cmsutil/crypto/CryptoUtil.java    |  12 +-
 11 files changed, 223 insertions(+), 185 deletions(-)

diff --git a/base/common/python/pki/cryptoutil.py b/base/common/python/pki/cryptoutil.py
index e9174bc3bfec6f20278b73c99854c043bd920745..f9c87155b6388b5119f5c514055a6822a022905a 100644
--- a/base/common/python/pki/cryptoutil.py
+++ b/base/common/python/pki/cryptoutil.py
@@ -192,7 +192,7 @@ class NSSCryptoUtil(CryptoUtil):
 
         Note that for fixed length keys, this length should be 0.  If no length
         is provided, then the function will either use 0 (for fixed length keys)
-        or the maximaum available length for that algorithm and the token.
+        or the maximum available length for that algorithm and the token.
         '''
         slot = nss.get_best_slot(mechanism)
         if size == 0:
diff --git a/base/common/src/com/netscape/certsrv/cert/CertData.java b/base/common/src/com/netscape/certsrv/cert/CertData.java
index 1c75d8f7c5ed21ad783c18c1c73f16c880f91c83..6451e4c0b3bc538c93eef7fa3f4326703f29013f 100644
--- a/base/common/src/com/netscape/certsrv/cert/CertData.java
+++ b/base/common/src/com/netscape/certsrv/cert/CertData.java
@@ -54,6 +54,10 @@ public class CertData {
         }
     }
 
+    /* HEADER and FOOTER used to create an encoded cert string*/
+    public static final String HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----";
+    public static final String FOOTER = "-----END NEW CERTIFICATE REQUEST-----";
+
     CertId serialNumber;
     String issuerDN;
     String subjectDN;
diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java
index ca196fffd0711baedd18baba5e8da01beb5d5c2e..1005097f0a9bf2e538be447ab7a2827cef263018 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyClient.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import javax.ws.rs.core.Response;
 
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
 import org.mozilla.jss.crypto.SymmetricKey;
 
 import com.netscape.certsrv.base.ResourceMessage;
@@ -56,10 +57,6 @@ public class KeyClient extends Client {
         keyRequestClient = createProxy(KeyRequestResource.class);
     }
 
-    public void setTransportCert(String transportCert) {
-        this.transportCert = transportCert;
-    }
-
     public CryptoProvider getCrypto() {
         return crypto;
     }
@@ -69,6 +66,17 @@ public class KeyClient extends Client {
     }
 
     /**
+     * Set the value of the transport cert.
+     * The HEADER and FOOTER should be removed from the string.
+     * HEADER - CertData.HEADER
+     * FOOTER - CertData.FOOTER
+     * @param transportCert
+     */
+    public void setTransportCert(String transportCert) {
+        this.transportCert = transportCert;
+    }
+
+    /**
      * List/Search archived secrets in the DRM.
      *
      * @param clientKeyID -- Client Key Identifier
@@ -186,6 +194,9 @@ public class KeyClient extends Client {
         if (id == null || status == null) {
             throw new IllegalArgumentException("Key Id and status must be specified.");
         }
+        if ((status != KeyResource.KEY_STATUS_ACTIVE) && (status != KeyResource.KEY_STATUS_INACTIVE)) {
+            throw new IllegalArgumentException("Invalid status value.");
+        }
         Response response = keyClient.modifyKeyStatus(id, status);
         client.getEntity(response, Void.class);
     }
@@ -305,33 +316,51 @@ public class KeyClient extends Client {
     /**
      * 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.
+     * key of the DRM transport certificate before being sent to the DRM.
      *
-     * 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
+     * This method will call CryptoUtil methods to generate the session key and wrap it
+     * with the DRM transport cert. 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.
+     * @param keyId -- key id for secret
+     * @return A KeyData object containing the unwrapped secret.
+     * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
+     *                     CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException
+     */
+    public KeyData retrieveKey(KeyId keyId) throws Exception {
+        if (keyId == null) {
+            throw new IllegalArgumentException("KeyId has to be specified.");
+        }
+        SymmetricKey sessionKey = crypto.generateSessionKey();
+        byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, transportCert);
+
+        KeyData data = retrieveKey(keyId, transWrappedSessionKey);
+
+        data.setPrivateData(crypto.unwrapUsingSessionKey(
+                Utils.base64decode(data.getWrappedPrivateData()), sessionKey,
+                KeyRequestResource.DES3_ALGORITHM, Utils.base64decode(data.getNonceData())));
+
+        return data;
+    }
+
+    /**
+     * Retrieve a secret (passphrase or symmetric key) from the DRM.
      *
-     * In this case, the function will simply pass the data to the DRM, and will return the secret
+     * This function generates a key recovery request, approves it, and retrieves
+     * the secret referred to by keyId.
+     * This assumes that only one approval is required to authorize the recovery.
+     *
+     * The parameter transWrappedSessionKey refers to the session key wrapped with the transport cert.
+     *
+     * The method 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.
+     * @return A KeyData object containing the wrapped secret.
      * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
      *                     CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException
      */
@@ -340,13 +369,8 @@ public class KeyClient extends Client {
         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);
+        if (transWrappedSessionKey == null){
+            throw new IllegalArgumentException("A transport cert wrapped session key cannot be null.");
         }
 
         KeyRequestResponse keyData = recoverKey(keyId, null, null, null, null);
@@ -357,59 +381,61 @@ public class KeyClient extends Client {
         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;
+        return retrieveKeyData(recoveryRequest);
     }
 
     /**
-     * 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
+     * The secret is secured in transit by wrapping the secret with the 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
-     *
+     * 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 passphrase wrapped by a 168 bit 3DES symmetric key (the session key).
+     * - the session key wrapped with the public key in the DRM transport certificate.
+     * - an ivps vector to be used as nonceData.
      *
-     * - the session key wrapped with the public key in the DRM transport certificate. This
-     * is referred to as the transWrappedSessionKey above.
+     * @param keyId -- key id of secret.
+     * @param passphrase -- passphrase used to wrap the secret in the response.
+     * @return KeyData object with the secret wrapped with the passphrase.
+     * @throws Exception - Exceptions of type NoSuchAlgorithmException, IllegalStateException, TokenException,
+     *                     CertificateEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException
+     */
+    public KeyData retrieveKeyByPassphrase(KeyId keyId, String passphrase) throws Exception{
+        if (keyId == null) {
+            throw new IllegalArgumentException("KeyId has to be specified.");
+        }
+        if (passphrase == null) {
+            throw new IllegalArgumentException("No passphrase provided.");
+        }
+        SymmetricKey sessionKey = crypto.generateSessionKey();
+        byte[] transWrappedSessionKey = crypto.wrapSessionKeyWithTransportCert(sessionKey, this.transportCert);
+        byte[] nonceData = CryptoUtil.getNonceData(8);
+        byte[] sessionWrappedPassphrase = crypto.wrapUsingSessionKey(passphrase, nonceData, sessionKey,
+                KeyRequestResource.DES3_ALGORITHM);
+
+        return retrieveKeyUsingWrappedPassphrase(keyId, transWrappedSessionKey, sessionWrappedPassphrase, nonceData);
+    }
+
+    /**
      *
-     * - ivps nonce data, referred to as nonceData
+     * This method generates a key recovery request, approves it, and retrieves
+     * the secret referred to by keyId. This assumes that only one approval is required
+     * to authorize the recovery.
      *
-     * 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.
+     * The method 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
+     * @param transWrappedSessionKey -- Session key wrapped with the transport cert
+     * @param sessionWrappedPassphrase -- Passphrase wrapped with the session key
+     * @param nonceData -- nonce data used for encryption.
      * @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,
+    public KeyData retrieveKeyUsingWrappedPassphrase(KeyId keyId, byte[] transWrappedSessionKey,
             byte[] sessionWrappedPassphrase, byte[] nonceData) throws Exception {
 
         if (keyId == null) {
@@ -417,20 +443,12 @@ public class KeyClient extends Client {
         }
 
         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.");
-            }
+            throw new IllegalArgumentException("Session Key wrapped passphrase cannot be null.");
+
+        }
+        if (transWrappedSessionKey == null || nonceData == null) {
+            throw new IllegalArgumentException(
+                    "No way to extract passphrase. Both transWrappedSessionKey and nonceData are required.");
         }
 
         // Need to pass the sessionWrappedPassphrase and transWrappedSessionKey when the
@@ -455,7 +473,6 @@ public class KeyClient extends Client {
         // 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);
-
     }
 
     /**
@@ -525,14 +542,15 @@ public class KeyClient extends Client {
             throw new IllegalArgumentException("No data provided to archive.");
         }
         // Default algorithm OID for DES_EDE3_CBC
+        String algorithmOID = EncryptionAlgorithm.DES3_CBC.toOID().toString();
         byte[] nonceData = CryptoUtil.getNonceData(8);
         String symAlgParams = Utils.base64encode(nonceData);
-        SymmetricKey sessionKey = crypto.generateSessionKey(KeyRequestResource.DES3_ALGORITHM);
+        SymmetricKey sessionKey = crypto.generateSessionKey();
         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,
+        return archiveWrappedData(clientKeyId, dataType, keyAlgorithm, keySize, algorithmOID,
                 symAlgParams, wrappedPrivateData, transWrappedSessionKey);
     }
 
diff --git a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
index e9097f43ba2f817978a8786971b55f613ba67f79..fb82afe19bbe7bf774f45f96da7c1c8b0dc3cc89 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
@@ -35,9 +35,6 @@ 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/KeyResource.java b/base/common/src/com/netscape/certsrv/key/KeyResource.java
index 4ec577dbf23b1c8f8e1d6212fe22d70adfd25c99..77c9a587e3c23dfb95c6c52ca23458e9e4a9f751 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyResource.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyResource.java
@@ -22,6 +22,9 @@ import com.netscape.certsrv.dbs.keydb.KeyId;
 @AuthMethodMapping("keys")
 public interface KeyResource {
 
+    public static final String KEY_STATUS_ACTIVE = "active";
+    public static final String KEY_STATUS_INACTIVE = "inactive";
+
     @GET
     @ClientResponseType(entityType=KeyInfoCollection.class)
     public Response listKeys(@QueryParam("clientKeyID") String clientKeyID,
diff --git a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
index 0766285a911de062001994a1ec51adc0547dcf4e..f5e5603aa8f8a35fe92701d10560e802e290bebb 100644
--- a/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
+++ b/base/common/src/com/netscape/certsrv/util/CryptoProvider.java
@@ -6,9 +6,9 @@ public abstract class CryptoProvider {
 
     public abstract void initialize() throws Exception;
 
-    public abstract SymmetricKey generateSymmetricKey(String keyAlgorithm) throws Exception;
+    public abstract SymmetricKey generateSymmetricKey(String keyAlgorithm, int keySize) throws Exception;
 
-    public abstract SymmetricKey generateSessionKey(String keyAlgorithm) throws Exception;
+    public abstract SymmetricKey generateSessionKey() throws Exception;
 
     public abstract byte[] wrapSessionKeyWithTransportCert(SymmetricKey sessionKey, String transportCert)
             throws Exception;
diff --git a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
index 050bbf691133a7cb5211df4291b350e2789b36b1..76c849c7a229d0cc5cf6cd09e1137e77031ee027 100644
--- a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
+++ b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java
@@ -1,23 +1,17 @@
 package com.netscape.certsrv.util;
 
-import java.io.IOException;
+import java.io.File;
 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;
@@ -33,18 +27,51 @@ public class NSSCryptoProvider extends CryptoProvider {
     CryptoManager manager;
     CryptoToken token;
     ClientConfig config;
+    File certDBDir;
+    String certDBPassword;
 
     public NSSCryptoProvider(ClientConfig config)
             throws Exception {
         this.config = config;
-        initialize();
+        if(config !=null){
+            if((config.getCertDatabase() != null) && (config.getCertPassword() != null)){
+                setDatabaseDetails(config.getCertDatabase(), config.getCertPassword());
+                initialize();
+            }
+        }
     }
 
+    /**
+     * To create and initialize an NSS database.
+     * @param certDBDir -- Location of the database
+     * @param certDBPwd -- Password for the database
+     * @throws Exception
+     */
+    public void setDatabaseDetails(String certDBDir, String certDBPwd) throws Exception{
+        if((certDBDir == null) || (certDBPwd == null)){
+            throw new IllegalArgumentException(" Both the db directory path and the password are required.");
+        }
+        this.certDBDir = new File(certDBDir);
+        if (this.certDBDir.exists()) {
+            if (!this.certDBDir.isDirectory())
+                this.certDBDir.mkdir();
+        } else {
+            this.certDBDir.mkdir();
+        }
+        this.certDBPassword = certDBPwd;
+    }
+
+    /**
+     * Initializes the NSS DB.
+     *
+     */
     @Override
     public void initialize() throws Exception {
-        // TODO Auto-generated method stub
+        if((certDBDir == null) || (certDBPassword == null)){
+            throw new Exception("NSS db location and password need to be specified.");
+        }
         try {
-            CryptoManager.initialize(config.getCertDatabase());
+            CryptoManager.initialize(certDBDir.getAbsolutePath());
         } catch (AlreadyInitializedException e) {
             // Can be ignored since it is just for getting the token
         } catch (KeyDatabaseException | CertDatabaseException | GeneralSecurityException e1) {
@@ -53,7 +80,7 @@ public class NSSCryptoProvider extends CryptoProvider {
         try {
             manager = CryptoManager.getInstance();
             token = manager.getInternalKeyStorageToken();
-            Password password = new Password(config.getCertPassword().toCharArray());
+            Password password = new Password(certDBPassword.toCharArray());
             try {
                 token.login(password);
             } catch (IncorrectPasswordException | TokenException e) {
@@ -69,64 +96,56 @@ public class NSSCryptoProvider extends CryptoProvider {
     }
 
     @Override
-    public SymmetricKey generateSymmetricKey(String keyAlgorithm) throws Exception {
-        try {
-            return CryptoUtil.generateKey(token, getKeyGenAlgorithm(keyAlgorithm));
-        } catch (NoSuchAlgorithmException | IllegalStateException | TokenException e) {
-            throw e;
+    public SymmetricKey generateSymmetricKey(String keyAlgorithm, int keySize) throws Exception {
+        if(token == null){
+            throw new NotInitializedException();
         }
+        return CryptoUtil.generateKey(token, getKeyGenAlgorithm(keyAlgorithm), keySize);
     }
 
     @Override
-    public SymmetricKey generateSessionKey(String keyAlgorithm) throws Exception{
-        return generateSymmetricKey(keyAlgorithm);
+    public SymmetricKey generateSessionKey() throws Exception {
+        return generateSymmetricKey(KeyRequestResource.DES3_ALGORITHM, 168);
     }
 
     @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;
+    public byte[] wrapSessionKeyWithTransportCert(SymmetricKey sessionKey, String transportCert) throws Exception {
+        if((manager == null) || (token == null)){
+            throw new NotInitializedException();
         }
+        return CryptoUtil.wrapSymmetricKey(manager, token, transportCert, sessionKey);
     }
 
     @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;
+    public byte[] wrapUsingSessionKey(String passphrase, byte[] iv, SymmetricKey key, String encryptionAlgorithm)
+            throws Exception {
+        if(token == null){
+            throw new NotInitializedException();
         }
+        return CryptoUtil.wrapPassphrase(token, passphrase, new IVParameterSpec(iv), key,
+                getEncryptionAlgorithm(encryptionAlgorithm));
     }
 
     @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;
+            String encryptionAlgorithm, byte[] nonceData) throws Exception {
+        if(token == null){
+            throw new NotInitializedException();
         }
+        return CryptoUtil.unwrapUsingSymmetricKey(token, new IVParameterSpec(nonceData), wrappedRecoveredKey,
+                recoveryKey,
+                getEncryptionAlgorithm(encryptionAlgorithm));
     }
 
     @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 String unWrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase) throws Exception {
+        return CryptoUtil.unwrapUsingPassphrase(wrappedRecoveredKey, recoveryPassphrase);
     }
 
-    public KeyGenAlgorithm getKeyGenAlgorithm(String keyAlgorithm) {
+    public KeyGenAlgorithm getKeyGenAlgorithm(String keyAlgorithm) throws NoSuchAlgorithmException {
+        if (keyAlgorithm == null) {
+            return KeyGenAlgorithm.DES3;
+        }
         KeyGenAlgorithm alg = null;
         switch (keyAlgorithm) {
         case KeyRequestResource.AES_ALGORITHM:
@@ -145,14 +164,18 @@ public class NSSCryptoProvider extends CryptoProvider {
             alg = KeyGenAlgorithm.RC4;
             break;
         case KeyRequestResource.DES3_ALGORITHM:
-        default:
             alg = KeyGenAlgorithm.DES3;
             break;
+        default:
+            throw new NoSuchAlgorithmException("No Algorithm named: " + keyAlgorithm);
         }
         return alg;
     }
 
-    public EncryptionAlgorithm getEncryptionAlgorithm(String encryptionAlgorithm) {
+    public EncryptionAlgorithm getEncryptionAlgorithm(String encryptionAlgorithm) throws NoSuchAlgorithmException {
+        if (encryptionAlgorithm == null) {
+            return EncryptionAlgorithm.DES3_CBC_PAD;
+        }
         EncryptionAlgorithm alg = null;
         switch (encryptionAlgorithm) {
         case KeyRequestResource.AES_ALGORITHM:
@@ -168,9 +191,10 @@ public class NSSCryptoProvider extends CryptoProvider {
             alg = EncryptionAlgorithm.RC4;
             break;
         case KeyRequestResource.DES3_ALGORITHM:
-        default:
             alg = EncryptionAlgorithm.DES3_CBC_PAD;
             break;
+        default:
+            throw new NoSuchAlgorithmException("No Algorithm named: " + encryptionAlgorithm);
         }
         return alg;
     }
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 f75dcf990006888f766c0aabb804c2646c69f05c..96a771660957233bf4ef088ca29f5839e63e9c06 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
@@ -40,6 +40,7 @@ import org.mozilla.jss.crypto.SymmetricKey;
 import org.mozilla.jss.util.Password;
 
 import com.netscape.certsrv.base.ResourceNotFoundException;
+import com.netscape.certsrv.cert.CertData;
 import com.netscape.certsrv.client.ClientConfig;
 import com.netscape.certsrv.client.PKIClient;
 import com.netscape.certsrv.dbs.keydb.KeyId;
@@ -50,6 +51,7 @@ import com.netscape.certsrv.key.KeyRequestInfo;
 import com.netscape.certsrv.key.KeyRequestInfoCollection;
 import com.netscape.certsrv.key.KeyRequestResource;
 import com.netscape.certsrv.key.KeyRequestResponse;
+import com.netscape.certsrv.key.KeyResource;
 import com.netscape.certsrv.key.SymKeyGenerationRequest;
 import com.netscape.certsrv.kra.KRAClient;
 import com.netscape.certsrv.request.IRequest;
@@ -57,7 +59,6 @@ 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;
 
@@ -227,8 +228,8 @@ 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 = transportCert.substring(CertData.HEADER.length(),
+                transportCert.indexOf(CertData.FOOTER));
         keyClient.setTransportCert(transportCert);
 
         log("Transport Cert retrieved from DRM: " + transportCert);
@@ -263,9 +264,9 @@ public class DRMTest {
         log("Archiving symmetric key");
         clientKeyId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime().toString();
         try {
-            vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+            vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0);
             byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
-                    KeyGenAlgorithm.DES3, ivps);
+                    KeyGenAlgorithm.DES3, 0, ivps);
 
             KeyRequestResponse info = keyClient.archiveOptionsData(clientKeyId, KeyRequestResource.SYMMETRIC_KEY_TYPE,
                     KeyRequestResource.DES3_ALGORITHM, 0, encoded);
@@ -298,7 +299,7 @@ public class DRMTest {
         // Test 6: 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);
+            recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0);
             wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
             keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey);
         } catch (Exception e) {
@@ -328,12 +329,12 @@ public class DRMTest {
         recoveryPassphrase = "Gimme me keys please";
 
         try {
-            recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+            recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0);
             wrappedRecoveryPassphrase = CryptoUtil.wrapPassphrase(token, recoveryPassphrase, ivps, recoveryKey,
                     EncryptionAlgorithm.DES3_CBC_PAD);
             wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
 
-            keyData = keyClient.retrieveKeyByPassphrase(keyId, null, wrappedRecoveryKey, wrappedRecoveryPassphrase,
+            keyData = keyClient.retrieveKeyUsingWrappedPassphrase(keyId, wrappedRecoveryKey, wrappedRecoveryPassphrase,
                     ivps.getIV());
         } catch (Exception e) {
             log("Exception in recovering symmetric key using passphrase" + e.toString());
@@ -392,11 +393,7 @@ public class DRMTest {
         recoveryKey = 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);
-            keyData = keyClient.retrieveKeyByPassphrase(keyId, recoveryPassphrase, null, null, null);
+            keyData = keyClient.retrieveKeyByPassphrase(keyId, recoveryPassphrase);
         } catch (Exception e) {
             log("Exception in recovering passphrase using session key: " + e.getMessage());
         }
@@ -418,10 +415,13 @@ public class DRMTest {
 
         // Test 11: Submit a recovery request for the passphrase using a passphrase
         try {
-            keyData = keyClient.retrieveKeyByPassphrase(keyId, null, wrappedRecoveryKey, wrappedRecoveryPassphrase,
+            recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0);
+            wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+            wrappedRecoveryPassphrase = CryptoUtil.wrapPassphrase(token, recoveryPassphrase, ivps, recoveryKey,
+                    EncryptionAlgorithm.DES3_CBC_PAD);
+            keyData = keyClient.retrieveKeyUsingWrappedPassphrase(keyId, wrappedRecoveryKey, wrappedRecoveryPassphrase,
                     ivps.getIV());
         } catch (Exception e1) {
-            // TODO Auto-generated catch block
             e1.printStackTrace();
             System.out.println("Test 17: " + e1.getMessage());
             System.exit(-1);
@@ -444,8 +444,7 @@ public class DRMTest {
         // Test 12: Get key
         log("Getting passphrase: " + keyId);
         try {
-            keyData = keyClient.retrieveKeyByPassphrase(keyId, null, wrappedRecoveryKey, wrappedRecoveryPassphrase,
-                    ivps.getIV());
+            keyData = keyClient.retrieveKeyByPassphrase(keyId, recoveryPassphrase);
         } catch (Exception e1) {
             // TODO Auto-generated catch block
             e1.printStackTrace();
@@ -520,8 +519,8 @@ 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 = transportCert.substring(CertData.HEADER.length(),
+                transportCert.indexOf(CertData.FOOTER));
 
         log("Transport Cert retrieved from DRM: " + transportCert);
 
@@ -569,7 +568,7 @@ public class DRMTest {
         // 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);
+            recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0);
             wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
             keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey);
         } catch (Exception e) {
@@ -618,7 +617,7 @@ public class DRMTest {
             vek = kg.generate();
 
             byte[] encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
-                    KeyGenAlgorithm.DES3, ivps);
+                    KeyGenAlgorithm.DES3, 0, ivps);
 
             KeyRequestResponse response = keyClient.archiveOptionsData(clientKeyId,
                     KeyRequestResource.SYMMETRIC_KEY_TYPE, KeyRequestResource.AES_ALGORITHM, 128, encoded);
@@ -647,27 +646,19 @@ public class DRMTest {
             log("Success: keyids from search and archival match.");
         }
 
-        // 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");
+        // Test 26: Submit a recovery request for the symmetric key
+        log("Submitting a recovery request for the  symmetric key without using session key");
         try {
-            recoveryKey = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
-            wrappedRecoveryKey = CryptoUtil.wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            keyData = keyClient.retrieveKey(keyId, wrappedRecoveryKey);
+            keyData = keyClient.retrieveKey(keyId);
         } catch (Exception e) {
             log("Exception in recovering symmetric key using session key: " + e.getMessage());
         }
 
-        wrappedRecoveredKey = keyData.getWrappedPrivateData();
-
-        ivps_server = new IVParameterSpec(Utils.base64decode(keyData.getNonceData()));
-        try {
-            recoveredKey = new String(Utils.base64decode(CryptoUtil.unwrapUsingSymmetricKey(token, ivps_server,
-                    Utils.base64decode(wrappedRecoveredKey),
-                    recoveryKey, EncryptionAlgorithm.DES3_CBC_PAD)));
-        } catch (Exception e) {
-            log("Exception in unwrapping key: " + e.toString());
-            e.printStackTrace();
-        }
+        // Since no session key is provided externally, the retrieveKey method
+        // generates a session key, wraps it with transport cert and completes the request.
+        // The encrypted data is then unwrapped using the temporary session key and set to
+        // the attribute privateData.
+        recoveredKey = keyData.getPrivateData();
 
         if (!recoveredKey.equals(Utils.base64encode(vek.getEncoded()))) {
             log("Error: recovered and archived keys do not match!");
@@ -681,7 +672,7 @@ public class DRMTest {
 
         //Test 28: Modify status
         log("modify the key status");
-        keyClient.modifyKeyStatus(keyId, "inactive");
+        keyClient.modifyKeyStatus(keyId, KeyResource.KEY_STATUS_INACTIVE);
         keyInfo = keyClient.getKeyInfo(keyId);
         printKeyInfo(keyInfo);
 
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java b/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java
index e1d5124fa3d0a52d3c334388542d466f57a71ebb..03a0729e756bcd2e96f19b1e27a24f580fd06448 100644
--- a/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java
@@ -199,7 +199,7 @@ public class GeneratePKIArchiveOptions {
         // Data to be archived
         SymmetricKey vek = null;
         if (!passphraseMode) {
-            vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3);
+            vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0);
             // store vek in file
             write_file(Utils.base64encode(vek.getKeyData()), key_file);
         }
@@ -208,10 +208,10 @@ public class GeneratePKIArchiveOptions {
 
         if (passphraseMode) {
             encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, null, passphrase,
-                    KeyGenAlgorithm.DES3, ivps);
+                    KeyGenAlgorithm.DES3, 0, ivps);
         } else {
             encoded = CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, vek, null,
-                    KeyGenAlgorithm.DES3, ivps);
+                    KeyGenAlgorithm.DES3, 0, ivps);
         }
 
         // write encoded to file
diff --git a/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java b/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java
index 27dea60db208e0677bec22b2f1b7e20f30a23d17..2b8a4ada3e73bd2b3cae37f0b4ca942a13978c80 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/base/PKIService.java
@@ -50,9 +50,6 @@ import com.netscape.certsrv.logging.ILogger;
  */
 public class PKIService {
 
-    public static final String HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----";
-    public static final String TRAILER = "-----END NEW CERTIFICATE REQUEST-----";
-
     // caching parameters
     public static final int DEFAULT_LONG_CACHE_LIFETIME = 1000;
 
@@ -141,7 +138,7 @@ public class PKIService {
     public CertData createCertificateData(org.mozilla.jss.crypto.X509Certificate cert)
             throws CertificateEncodingException {
         CertData data = new CertData();
-        String b64 = HEADER + CMS.BtoA(cert.getEncoded()) + TRAILER;
+        String b64 = CertData.HEADER + CMS.BtoA(cert.getEncoded()) + CertData.FOOTER;
         data.setEncoded(b64);
         return data;
     }
diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
index 6056452e3b471fd0c7b152e4795f1497f51d1d2a..d3eafd7f5e1eadba0a2cefd56c120e7495567e4d 100644
--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -1303,11 +1303,15 @@ public class CryptoUtil {
      * Generates a symmetric key.
      */
     public static SymmetricKey generateKey(CryptoToken token,
-            KeyGenAlgorithm alg)
+            KeyGenAlgorithm alg, int keySize)
             throws TokenException, NoSuchAlgorithmException,
-                IllegalStateException {
+                IllegalStateException, InvalidAlgorithmParameterException {
         try {
             KeyGenerator kg = token.getKeyGenerator(alg);
+            if (alg == KeyGenAlgorithm.AES || alg == KeyGenAlgorithm.RC4
+                    || alg == KeyGenAlgorithm.RC2) {
+                kg.initialize(keySize);
+            }
 
             return kg.generate();
         } catch (CharConversionException e) {
@@ -1619,7 +1623,7 @@ public class CryptoUtil {
     }
 
     public static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert,
-            SymmetricKey vek, String passphrase, KeyGenAlgorithm keyGenAlg, IVParameterSpec IV) throws TokenException,
+            SymmetricKey vek, String passphrase, KeyGenAlgorithm keyGenAlg, int symKeySize, IVParameterSpec IV) throws TokenException,
             CharConversionException,
             NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
             CertificateEncodingException, IOException, IllegalStateException, IllegalBlockSizeException,
@@ -1627,7 +1631,7 @@ public class CryptoUtil {
         byte[] key_data = null;
 
         //generate session key
-        SymmetricKey sk = CryptoUtil.generateKey(token, keyGenAlg);
+        SymmetricKey sk = CryptoUtil.generateKey(token, keyGenAlg, symKeySize);
 
         if (passphrase != null) {
             key_data = wrapPassphrase(token, passphrase, IV, sk, EncryptionAlgorithm.DES3_CBC_PAD);
-- 
1.8.5.3

