From fda43f0534e2de25f4ff48092a640c69ee9abf2e Mon Sep 17 00:00:00 2001
From: Jack Magne <jmagne@redhat.com>
Date: Sat, 21 Jan 2012 17:39:26 -0800
Subject: [PATCH] KRA changes for archiving and recovering symmetric keys  and
 passphrases.

Ticket #66 and #68.

Add ability to archive and recover symmetric keys and passphrases using rest interface.
Enhanced test client to test out new functionality.
Provided support to return recovered data either wrapped by symmetric key or wrapped in PBE password based encryption blob.
---
 pki/base/ca/shared/conf/schema.ldif                |   17 +-
 .../com/netscape/certsrv/dbs/keydb/IKeyRecord.java |   12 +
 .../src/com/netscape/certsrv/request/IRequest.java |   14 +-
 .../netscape/certsrv/security/IEncryptionUnit.java |   21 +
 .../certsrv/security/ITransportKeyUnit.java        |    2 +
 .../cms/servlet/key/KeyResourceService.java        |    4 +-
 .../cms/servlet/key/KeysResourceService.java       |    3 +-
 .../com/netscape/cms/servlet/key/model/KeyDAO.java |  101 +++++-
 .../netscape/cms/servlet/key/model/KeyData.java    |   19 +
 .../cms/servlet/request/KeyRequestResource.java    |    3 +
 .../servlet/request/KeyRequestResourceService.java |   16 +
 .../cms/servlet/request/model/KeyRequestDAO.java   |   73 ++++-
 .../servlet/request/model/RecoveryRequestData.java |   21 +
 .../src/com/netscape/cmscore/dbs/KeyDBSchema.java  |    3 +
 .../src/com/netscape/cmscore/dbs/KeyRecord.java    |   26 ++
 .../com/netscape/cmscore/dbs/KeyRepository.java    |   15 +-
 .../netscape/cms/servlet/test/DRMRestClient.java   |   16 +-
 .../src/com/netscape/cms/servlet/test/DRMTest.java |  219 ++++++++---
 pki/base/kra/shared/conf/schema.ldif               |   17 +-
 .../kra/src/com/netscape/kra/ArchiveOptions.java   |  154 ++++++++
 .../kra/src/com/netscape/kra/EncryptionUnit.java   |  355 ++++++++++++------
 .../src/com/netscape/kra/EnrollmentService.java    |  117 +------
 pki/base/kra/src/com/netscape/kra/KRAService.java  |    7 +-
 .../netscape/kra/SecurityDataRecoveryService.java  |  395 ++++++++++++++++++++
 .../src/com/netscape/kra/SecurityDataService.java  |  163 ++++++++
 pki/base/ocsp/shared/conf/schema.ldif              |   17 +-
 pki/base/tks/shared/conf/schema.ldif               |   17 +-
 27 files changed, 1527 insertions(+), 300 deletions(-)
 create mode 100644 pki/base/kra/src/com/netscape/kra/ArchiveOptions.java
 create mode 100644 pki/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
 create mode 100644 pki/base/kra/src/com/netscape/kra/SecurityDataService.java

diff --git a/pki/base/ca/shared/conf/schema.ldif b/pki/base/ca/shared/conf/schema.ldif
index caf71e9..70578e2 100644
--- a/pki/base/ca/shared/conf/schema.ldif
+++ b/pki/base/ca/shared/conf/schema.ldif
@@ -161,6 +161,21 @@ attributeTypes: ( keySize-oid NAME 'keySize' DESC 'CMS defined attribute' SYNTAX
 dn: cn=schema
 changetype: modify
 add: attributeTypes
+attributeTypes: ( clientId-oid NAME 'clientId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dataType-oid NAME 'dataType' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( status-oid NAME 'status' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
 attributeTypes: ( keyState-oid NAME 'keyState' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
 
 dn: cn=schema
@@ -446,7 +461,7 @@ objectClasses: ( userDetails-oid NAME 'userDetails' DESC 'CMS defined class' SUP
 dn: cn=schema
 changetype: modify
 add: objectClasses
-objectClasses: ( keyRecord-oid NAME 'keyRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ keyState $ privateKeyData $ ownerName $ keySize $ metaInfo $ dateOfArchival $ dateOfRecovery $ algorithm $ publicKeyFormat $ publicKeyData $ archivedBy ) X-ORIGIN 'user defined' )
+objectClasses: ( keyRecord-oid NAME 'keyRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ keyState $ privateKeyData $ ownerName $ keySize $ metaInfo $ dateOfArchival $ dateOfRecovery $ algorithm $ publicKeyFormat $ publicKeyData $ archivedBy $ clientId $ dataType $ status ) X-ORIGIN 'user defined' )
 
 dn: cn=schema
 changetype: modify
diff --git a/pki/base/common/src/com/netscape/certsrv/dbs/keydb/IKeyRecord.java b/pki/base/common/src/com/netscape/certsrv/dbs/keydb/IKeyRecord.java
index 010661d..4007f3c 100644
--- a/pki/base/common/src/com/netscape/certsrv/dbs/keydb/IKeyRecord.java
+++ b/pki/base/common/src/com/netscape/certsrv/dbs/keydb/IKeyRecord.java
@@ -40,6 +40,10 @@ public interface IKeyRecord {
     public static final String ATTR_MODIFY_TIME = "keyModifyTime";
     public static final String ATTR_META_INFO = "keyMetaInfo";
     public static final String ATTR_ARCHIVED_BY = "keyArchivedBy";
+    public static final String ATTR_CLIENT_ID = "clientId";
+    public static final String ATTR_DATA_TYPE = "dataType";
+    public static final String ATTR_STATUS = "status";
+    
 
     // key state
     public static final String STATUS_ANY = "ANY";
@@ -86,6 +90,14 @@ public interface IKeyRecord {
     public Integer getKeySize() throws EBaseException;
 
     /**
+     * Retrieves client ID.
+     * 
+     * @return client id
+     * @exception EBaseException failed to retrieve client id
+     */
+    public String getClientId() throws EBaseException;
+
+    /**
      * Retrieves archiver identifier.
      * 
      * @return archiver uid
diff --git a/pki/base/common/src/com/netscape/certsrv/request/IRequest.java b/pki/base/common/src/com/netscape/certsrv/request/IRequest.java
index 19b8308..6443d64 100644
--- a/pki/base/common/src/com/netscape/certsrv/request/IRequest.java
+++ b/pki/base/common/src/com/netscape/certsrv/request/IRequest.java
@@ -69,8 +69,6 @@ public interface IRequest {
     public static final String CLA_UNCERT4CRL_REQUEST = "uncert4crl";
     public static final String NETKEY_KEYGEN_REQUEST = "netkeyKeygen";
     public static final String NETKEY_KEYRECOVERY_REQUEST = "netkeyKeyRecovery";
-    public static final String SECURITY_DATA_ENROLLMENT_REQUEST = "securityDataEnrollment";
-    public static final String SECURITY_DATA_RECOVERY_REQUEST = "securityDataRecovery";
 
     public static final String REQUESTOR_NAME = "csrRequestorName";
     public static final String REQUESTOR_PHONE = "csrRequestorPhone";
@@ -152,6 +150,18 @@ public interface IRequest {
     public final static String NETKEY_ATTR_USER_CERT = "cert";
     public final static String NETKEY_ATTR_KEY_SIZE = "keysize";
 
+    //Security Data request attributes
+    public static final String SECURITY_DATA_ENROLLMENT_REQUEST = "securityDataEnrollment";
+    public static final String SECURITY_DATA_RECOVERY_REQUEST = "securityDataRecovery";
+    public static final String SECURITY_DATA_CLIENT_ID = "clientID";
+    public static final String SECURITY_DATA_TYPE = "dataType";
+    public static final String SECURITY_DATA_STATUS = "status";
+    public static final String SECURITY_DATA_TRANS_SESS_KEY = "transWrappedSessKey";
+    public static final String SECURITY_DATA_SESS_PASS_PHRASE = "sessWrappedPassPhrase";
+    public static final String SECURITY_DATA_IV_STRING_IN = "iv_in";
+    public static final String SECURITY_DATA_IV_STRING_OUT = "iv_out";
+    
+    
     // requestor type values.
     public static final String REQUESTOR_EE = "EE";
     public static final String REQUESTOR_RA = "RA";
diff --git a/pki/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java b/pki/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java
index e318188..de67a9e 100644
--- a/pki/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java
+++ b/pki/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java
@@ -20,6 +20,7 @@ package com.netscape.certsrv.security;
 import java.security.PublicKey;
 
 import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.crypto.SymmetricKey;
 
 import com.netscape.certsrv.base.EBaseException;
 
@@ -46,6 +47,16 @@ public interface IEncryptionUnit extends IToken {
      * @exception EBaseException failed to wrap
      */
     public byte[] wrap(PrivateKey priKey) throws EBaseException;
+    
+    /**
+     * Wraps data. The given key will be wrapped by the
+     * private key in this unit.
+     * 
+     * @param symKey symmetric key to be wrapped
+     * @return wrapped data
+     * @exception EBaseException failed to wrap
+     */
+    public byte[] wrap(SymmetricKey symKey) throws EBaseException;
 
     /**
      * Verifies the given key pair.
@@ -72,6 +83,16 @@ public interface IEncryptionUnit extends IToken {
             byte symmAlgParams[], byte privateKey[],
             PublicKey pubKey)
             throws EBaseException;
+    
+    public SymmetricKey unwrap(byte wrappedKeyData[])
+            throws EBaseException;
+    
+    public SymmetricKey unwrap_symmetric(byte sessionKey[], String symmAlgOID,
+            byte symmAlgParams[], byte symmetricKey[])
+            throws EBaseException;
+    
+    public SymmetricKey unwrap_sym(byte encSymmKey[],
+            SymmetricKey.Usage usage);
 
     /**
      * Unwraps data. This method rebuilds the private key by
diff --git a/pki/base/common/src/com/netscape/certsrv/security/ITransportKeyUnit.java b/pki/base/common/src/com/netscape/certsrv/security/ITransportKeyUnit.java
index 0a012e8..a3bea72 100644
--- a/pki/base/common/src/com/netscape/certsrv/security/ITransportKeyUnit.java
+++ b/pki/base/common/src/com/netscape/certsrv/security/ITransportKeyUnit.java
@@ -41,6 +41,8 @@ public interface ITransportKeyUnit extends IEncryptionUnit {
      */
     public org.mozilla.jss.crypto.X509Certificate getCertificate();
 
+    public SymmetricKey unwrap_sym(byte encSymmKey[], SymmetricKey.Usage usage);
+    
     public SymmetricKey unwrap_sym(byte encSymmKey[]);
 
     public SymmetricKey unwrap_encrypt_sym(byte encSymmKey[]);
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java b/pki/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java
index 887820c..6c4375a 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java
@@ -111,13 +111,13 @@ public class KeyResourceService extends CMSResourceService implements KeyResourc
         
         // confirm request is in approved state
         String status = reqInfo.getRequestStatus();
-        if (!status.equals(RequestStatus.APPROVED.toString())) {
+        if (!status.equals(RequestStatus.APPROVED.toString()) && !status.equals(RequestStatus.COMPLETE.toString())) {
             // log error
             throw new WebApplicationException(Response.Status.UNAUTHORIZED);
         }
         
         String keyURL = reqInfo.getKeyURL();
-        return keyURL.substring(keyURL.lastIndexOf("/")); 
+        return keyURL.substring(keyURL.lastIndexOf("/") + 1); 
     }
 
 }
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java b/pki/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java
index 471abc1..513d5c2 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java
@@ -76,7 +76,8 @@ public class KeysResourceService extends CMSResourceService implements KeysResou
         }
         
         if (clientID != null) {
-            filter += "(clientID=\'" + clientID + "\')";
+           // filter += "(clientID=\'" + clientID + "\')";
+            filter += "(clientID=" + clientID + ")";
             matches ++;
         }
         
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDAO.java b/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDAO.java
index 5fd17a3..c2853ea 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDAO.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDAO.java
@@ -20,6 +20,7 @@ package com.netscape.cms.servlet.key.model;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.Hashtable;
 import java.util.List;
 
 import javax.ws.rs.core.UriBuilder;
@@ -29,7 +30,13 @@ import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.dbs.keydb.IKeyRecord;
 import com.netscape.certsrv.dbs.keydb.IKeyRepository;
 import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.IRequestQueue;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.certsrv.request.RequestStatus;
 import com.netscape.cms.servlet.request.model.RecoveryRequestData;
+import com.netscape.kra.RecoveryService;
+import com.netscape.kra.SecurityDataRecoveryService;
 
 /**
  * @author alee
@@ -38,11 +45,13 @@ import com.netscape.cms.servlet.request.model.RecoveryRequestData;
 public class KeyDAO {
 
     private IKeyRepository repo;
+    private IKeyRecoveryAuthority kra;
+    private IRequestQueue queue;
     
     public KeyDAO() {
-        IKeyRecoveryAuthority kra = null;
         kra = ( IKeyRecoveryAuthority ) CMS.getSubsystem( "kra" );
         repo = kra.getKeyRepository();
+        queue = kra.getRequestQueue();
     }
     /**
      * Returns list of keys meeting specified search filter.
@@ -82,15 +91,95 @@ public class KeyDAO {
         KeyData keyData = null;
         BigInteger serial = new BigInteger(keyId);
         
-        // get wrapped key
+        String rId = data.getRequestId();
+        
+        String transWrappedSessionKey = null;
+        String sessionWrappedPassphrase = null;
+        
+        IRequest  request = queue.findRequest(new RequestId(rId));
+        
+        if (request == null) {
+            return null;
+        }
+        
+     // get wrapped key
         IKeyRecord rec = repo.readKeyRecord(serial);
         if (rec == null) {
-            // key does not exist
-            // log the error
             return null;  
         }
-        // TODO unwrap the key and wrap with the credential in RecoveryRequestData
-        // need to figure out how to do this with jmagne 
+        
+        Hashtable<String, Object> params = kra.getVolatileRequest(
+                request.getRequestId());
+        
+        
+        String sessWrappedKeyData = null;
+        String passWrappedKeyData = null;
+        String nonceData = null;
+        
+        if ( params != null) {
+           sessWrappedKeyData = (String) params.get( SecurityDataRecoveryService.ATTR_SESS_WRAPPED_DATA);
+           passWrappedKeyData = (String) params.get( SecurityDataRecoveryService.ATTR_PASS_WRAPPED_DATA);
+           nonceData = (String) params.get( IRequest.SECURITY_DATA_IV_STRING_OUT);
+        } else {
+            throw new EBaseException("Can't obtain Volatile params in KeyDAO.getKey!");
+        }
+        
+        if ( sessWrappedKeyData != null || passWrappedKeyData != null) {
+            keyData = new KeyData();
+            
+        } else {
+            // The data has not yet been set, let's see if the RecoveryRequestData contains
+            // the info. If so, process the request at this point.
+            
+            transWrappedSessionKey   = data.getTransWrappedSessionKey();
+            sessionWrappedPassphrase = data.getSessionWrappedPassphrase();
+            nonceData = data.getNonceData();
+            
+            if (sessionWrappedPassphrase != null) {
+                params.put(RecoveryService.ATTR_TRANSPORT_PWD, sessionWrappedPassphrase);
+            }
+                
+            if ( transWrappedSessionKey != null) {
+                params.put(IRequest.SECURITY_DATA_TRANS_SESS_KEY, transWrappedSessionKey);
+            }
+            
+            if ( nonceData != null) {
+                params.put(IRequest.SECURITY_DATA_IV_STRING_IN, nonceData);
+            }
+                
+            try {
+                // Has to be in this state or it won't go anywhere.
+                request.setRequestStatus(RequestStatus.BEGIN);
+                queue.processRequest(request);
+            } catch ( EBaseException e) {
+                kra.destroyVolatileRequest(request.getRequestId());
+            }
+
+            nonceData = null;
+            keyData = new KeyData();
+            if ( keyData != null) {
+                sessWrappedKeyData = (String) params.get( SecurityDataRecoveryService.ATTR_SESS_WRAPPED_DATA);
+                passWrappedKeyData = (String) params.get( SecurityDataRecoveryService.ATTR_PASS_WRAPPED_DATA);
+                nonceData = (String) params.get( IRequest.SECURITY_DATA_IV_STRING_OUT);
+                    
+            }
+        }
+        
+        if ( keyData != null) {
+            if ( sessWrappedKeyData != null) {
+                keyData.setWrappedPrivateData(sessWrappedKeyData);
+            }
+            if ( passWrappedKeyData != null) {
+                keyData.setWrappedPrivateData(passWrappedKeyData);
+            }
+            if ( nonceData != null) {
+                keyData.setNonceData(nonceData);
+            }
+            
+            kra.destroyVolatileRequest(request.getRequestId());
+        }
+        
+        queue.markAsServiced(request);
         
         return keyData;
     }
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyData.java b/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyData.java
index 0e6e80d..42a6bbf 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyData.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/model/KeyData.java
@@ -36,6 +36,9 @@ public class KeyData {
     @XmlElement
     String wrappedPrivateData;
     
+    @XmlElement
+    String nonceData;
+    
     public KeyData() {
         // required for JAXB (defaults)
     }
@@ -54,4 +57,20 @@ public class KeyData {
         this.wrappedPrivateData = wrappedPrivateData;
     }
     
+    /**
+     * @return the nonceData
+     */
+    
+    public String getNonceData() {
+        return nonceData;
+    }
+    
+    /**
+     * @param nonceData the nonceData to set
+     */
+    
+    public void setNonceData(String nonceData) {
+        this.nonceData = nonceData;
+    }
+    
 }
diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResource.java b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResource.java
index 146b03d..656768f 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResource.java
@@ -14,6 +14,9 @@ import com.netscape.cms.servlet.request.model.RecoveryRequestData;
 
 @Path("/keyrequest")
 public interface KeyRequestResource {
+    public final String SYMMETRIC_KEY_TYPE = "symmetricKey";
+    public final String PASS_PHRASE_TYPE = "passPhrase";
+    public final String ASYMMETRIC_KEY_TYPE = "asymmetricKey";
 
     /**
      * Used to retrieve key request info for a specific request
diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java
index da08c4d..2a2d5c8 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java
@@ -69,6 +69,10 @@ public class KeyRequestResourceService extends CMSResourceService implements Key
 
     public KeyRequestInfo archiveKey(ArchivalRequestData data) {
         // auth and authz
+        if ( data == null ) {
+            throw new WebApplicationException(Response.Status.NOT_FOUND);
+        }
+        
         KeyRequestDAO dao = new KeyRequestDAO();
         KeyRequestInfo info;
         try {
@@ -89,6 +93,9 @@ public class KeyRequestResourceService extends CMSResourceService implements Key
 
     public KeyRequestInfo recoverKey(RecoveryRequestData data) {
         // auth and authz
+        if ( data == null ) {
+            throw new WebApplicationException(Response.Status.NOT_FOUND);
+        }
         KeyRequestDAO dao = new KeyRequestDAO();
         KeyRequestInfo info;
         try {
@@ -102,6 +109,9 @@ public class KeyRequestResourceService extends CMSResourceService implements Key
     }
     
     public void approveRequest(@PathParam("id") String id) {
+        if ( id == null) {
+            throw new WebApplicationException(Response.Status.NOT_FOUND);
+        }
         // auth and authz
         KeyRequestDAO dao = new KeyRequestDAO();
         try {
@@ -114,6 +124,9 @@ public class KeyRequestResourceService extends CMSResourceService implements Key
     }
     
     public void rejectRequest(@PathParam("id") String id) {
+        if ( id == null) {
+            throw new WebApplicationException(Response.Status.NOT_FOUND);
+        }
         // auth and authz
         KeyRequestDAO dao = new KeyRequestDAO();
         try {
@@ -126,6 +139,9 @@ public class KeyRequestResourceService extends CMSResourceService implements Key
     }
          
     public void cancelRequest(@PathParam("id") String id) {
+        if ( id == null) {
+            throw new WebApplicationException(Response.Status.NOT_FOUND);
+        }
         // auth and authz
         KeyRequestDAO dao = new KeyRequestDAO();
         try {
diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestDAO.java b/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestDAO.java
index 16da23d..e7cbd68 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestDAO.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestDAO.java
@@ -19,6 +19,7 @@ package com.netscape.cms.servlet.request.model;
 
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.Hashtable;
 import java.util.List;
 
 import javax.ws.rs.core.MultivaluedMap;
@@ -35,6 +36,8 @@ import com.netscape.certsrv.request.IRequestVirtualList;
 import com.netscape.certsrv.request.RequestId;
 import com.netscape.certsrv.request.RequestStatus;
 import com.netscape.cms.servlet.base.model.Link;
+import com.netscape.certsrv.profile.IEnrollProfile;
+import com.netscape.kra.RecoveryService;
 
 /**
  * @author alee
@@ -42,6 +45,9 @@ import com.netscape.cms.servlet.base.model.Link;
  */
 public class KeyRequestDAO {
     private IRequestQueue queue;
+    private IKeyRecoveryAuthority kra;
+    
+    private static String REQUEST_ARCHIVE_OPTIONS = IEnrollProfile.REQUEST_ARCHIVE_OPTIONS;
     
     private String[] vlvFilters = {
             "(requeststate=*)", "(requesttype=enrollment)",
@@ -56,8 +62,9 @@ public class KeyRequestDAO {
             "(&(requeststate=complete)(requesttype=recovery))"
     };
     
+    public static final String ATTR_SERIALNO = "serialNumber";
+    
     public KeyRequestDAO() {
-        IKeyRecoveryAuthority kra = null;
         kra = ( IKeyRecoveryAuthority ) CMS.getSubsystem( "kra" );
         queue = kra.getRequestQueue();
     }
@@ -104,6 +111,10 @@ public class KeyRequestDAO {
             // We should think about whether they should be, or if we need to
             // limit the number of results returned.
             IRequestList requests = queue.listRequestsByFilter(filter, maxResults, maxTime);
+            
+            if ( requests == null) {
+                return null;
+            }
             while (requests.hasMoreElements()) {
                 RequestId rid = (RequestId) requests.nextElement();
                 IRequest request = queue.findRequest(rid);
@@ -168,10 +179,34 @@ public class KeyRequestDAO {
      * @throws EBaseException 
      */
     public KeyRequestInfo submitRequest(ArchivalRequestData data, UriInfo uriInfo) throws EBaseException {
+        String clientId = data.getClientId();
+        String wrappedSecurityData = data.getWrappedPrivateData();
+        String dataType = data.getDataType();
+        
+        KeyRequestInfos alreadyWithClientID =  null;
+        
+        if (clientId != null) {
+            alreadyWithClientID = listRequests("(extdata" + "-" + IRequest.SECURITY_DATA_CLIENT_ID+"=" + clientId + ")" , 0, 1, 1,10, 
+                 uriInfo);
+        }
+        
+        if ( alreadyWithClientID != null ) {
+            throw new EBaseException("Client ID already exists! ID: " + clientId);
+        }
+                
         IRequest request = queue.newRequest(IRequest.SECURITY_DATA_ENROLLMENT_REQUEST);
+        
+        request.setExtData(REQUEST_ARCHIVE_OPTIONS, wrappedSecurityData);
+        request.setExtData(IRequest.SECURITY_DATA_CLIENT_ID, clientId);
+        request.setExtData(IRequest.SECURITY_DATA_TYPE, dataType);
+        
+        //request.setExtData
         //TODO : 
         //set data using request.setExtData(field, data)
         queue.processRequest(request);
+        
+        queue.markAsServiced(request);
+        
         return createKeyRequestInfo(request, uriInfo);
     }
     /**
@@ -181,15 +216,49 @@ public class KeyRequestDAO {
      * @throws EBaseException 
      */
     public KeyRequestInfo submitRequest(RecoveryRequestData data, UriInfo uriInfo) throws EBaseException { 
-        IRequest request = queue.newRequest(IRequest.SECURITY_DATA_RECOVERY_REQUEST);
+        
         // set data using request.setExtData(field, data)
+        
+        String wrappedSessionKeyStr = data.getTransWrappedSessionKey();
+        String wrappedPassPhraseStr = data.getSessionWrappedPassphrase();
+        String nonceDataStr = data.getNonceData();
+        
+        IRequest request = queue.newRequest(IRequest.SECURITY_DATA_RECOVERY_REQUEST);
+        
+        String keyId = data.getKeyId();
+        
+        Hashtable<String, Object> params = null;
+        params = kra.createVolatileRequest(request.getRequestId());
+        
+        CMS.debug("Create volatile  params for recovery request. " + params);
+        
+        if (params != null) {
+            if (wrappedPassPhraseStr != null) {
+                params.put(RecoveryService.ATTR_TRANSPORT_PWD, wrappedPassPhraseStr);
+            }
+            
+            if ( wrappedSessionKeyStr != null) {
+                params.put(IRequest.SECURITY_DATA_TRANS_SESS_KEY, wrappedSessionKeyStr);
+            }
+            
+            if ( nonceDataStr != null) {
+                params.put(IRequest.SECURITY_DATA_IV_STRING_IN, nonceDataStr);
+            }
+        } else {
+            throw new EBaseException("Can not create Volatile params in submitRequest!");
+        }
+        
+        request.setExtData(ATTR_SERIALNO,keyId);
+        
         queue.processRequest(request);
+        
         return createKeyRequestInfo(request, uriInfo);
     }
 
     public void approveRequest(String id) throws EBaseException {
         IRequest request = queue.findRequest(new RequestId(id));
         request.setRequestStatus(RequestStatus.APPROVED);
+        queue.updateRequest(request);
     }
     
     public void rejectRequest(String id) throws EBaseException {
diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/model/RecoveryRequestData.java b/pki/base/common/src/com/netscape/cms/servlet/request/model/RecoveryRequestData.java
index c84d8f4..64a93ef 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/request/model/RecoveryRequestData.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/request/model/RecoveryRequestData.java
@@ -39,6 +39,7 @@ public class RecoveryRequestData {
     private static final String REQUEST_ID = "requestId";
     private static final String TRANS_WRAPPED_SESSION_KEY = "transWrappedSessionKey";
     private static final String SESSION_WRAPPED_PASSPHRASE = "sessionWrappedPassphrase";
+    private static final String NONCE_DATA = "nonceData";
 
     @XmlElement
     protected String keyId;
@@ -52,6 +53,9 @@ public class RecoveryRequestData {
     @XmlElement
     protected String sessionWrappedPassphrase;
     
+    @XmlElement
+    protected String nonceData;
+    
     public RecoveryRequestData() {
         // required for JAXB (defaults)
     }
@@ -61,6 +65,7 @@ public class RecoveryRequestData {
         requestId = form.getFirst(REQUEST_ID);
         transWrappedSessionKey = form.getFirst(TRANS_WRAPPED_SESSION_KEY);
         sessionWrappedPassphrase = form.getFirst(SESSION_WRAPPED_PASSPHRASE);
+        nonceData = form.getFirst(NONCE_DATA);
     }
 
     /**
@@ -118,5 +123,21 @@ public class RecoveryRequestData {
     public void setSessionWrappedPassphrase(String sessionWrappedPassphrase) {
         this.sessionWrappedPassphrase = sessionWrappedPassphrase;
     }
+    
+    /**
+     * @return nonceData
+     */
+    
+    public String getNonceData() {
+        return nonceData;
+    }
+    
+    /**
+     * @param nonceData the nonceData to set
+     */
+    
+    public void setNonceData(String nonceData) {
+        this.nonceData = nonceData;
+    }
 
 }
diff --git a/pki/base/common/src/com/netscape/cmscore/dbs/KeyDBSchema.java b/pki/base/common/src/com/netscape/cmscore/dbs/KeyDBSchema.java
index ca9db77..50b3bad 100644
--- a/pki/base/common/src/com/netscape/cmscore/dbs/KeyDBSchema.java
+++ b/pki/base/common/src/com/netscape/cmscore/dbs/KeyDBSchema.java
@@ -45,4 +45,7 @@ public class KeyDBSchema {
     public static final String LDAP_ATTR_PUBLIC_KEY_FORMAT =
             "publicKeyFormat";
     public static final String LDAP_ATTR_ARCHIVED_BY = "archivedBy";
+    public static final String LDAP_ATTR_CLIENT_ID = "clientId";
+    public static final String LDAP_ATTR_STATUS = "status";
+    public static final String LDAP_ATTR_DATA_TYPE = "dataType";
 }
diff --git a/pki/base/common/src/com/netscape/cmscore/dbs/KeyRecord.java b/pki/base/common/src/com/netscape/cmscore/dbs/KeyRecord.java
index 8f28887..7883c8f 100644
--- a/pki/base/common/src/com/netscape/cmscore/dbs/KeyRecord.java
+++ b/pki/base/common/src/com/netscape/cmscore/dbs/KeyRecord.java
@@ -56,6 +56,10 @@ public class KeyRecord implements IDBObj, IKeyRecord {
     private Date mCreateTime = null;
     private Date mModifyTime = null;
     private String mArchivedBy = null;
+    private String mClientId = null;
+    private String mStatus = null;
+    private String mDataType = null;
+    
 
     protected static Vector<String> mNames = new Vector<String>();
     static {
@@ -71,6 +75,9 @@ public class KeyRecord implements IDBObj, IKeyRecord {
         mNames.addElement(ATTR_CREATE_TIME);
         mNames.addElement(ATTR_MODIFY_TIME);
         mNames.addElement(ATTR_ARCHIVED_BY);
+        mNames.addElement(ATTR_CLIENT_ID);
+        mNames.addElement(ATTR_STATUS);
+        mNames.addElement(ATTR_DATA_TYPE);
     }
 
     /**
@@ -128,6 +135,12 @@ public class KeyRecord implements IDBObj, IKeyRecord {
             mModifyTime = (Date) object;
         } else if (name.equalsIgnoreCase(ATTR_ARCHIVED_BY)) {
             mArchivedBy = (String) object;
+        } else if (name.equalsIgnoreCase(ATTR_CLIENT_ID)) {
+            mClientId = (String) object;
+        } else if (name.equalsIgnoreCase(ATTR_DATA_TYPE)) {
+            mDataType = (String) object;
+        } else if (name.equalsIgnoreCase(ATTR_STATUS)) {
+            mStatus = (String) object;
         } else {
             throw new EBaseException(com.netscape.certsrv.apps.CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name));
         }
@@ -162,6 +175,12 @@ public class KeyRecord implements IDBObj, IKeyRecord {
             return mMetaInfo;
         } else if (name.equalsIgnoreCase(ATTR_ARCHIVED_BY)) {
             return mArchivedBy;
+        } else if (name.equalsIgnoreCase(ATTR_CLIENT_ID)) {
+            return mClientId;
+        } else if (name.equalsIgnoreCase(ATTR_DATA_TYPE)) {
+            return mDataType;
+        } else if (name.equalsIgnoreCase(ATTR_STATUS)) {
+            return mStatus;
         } else {
             throw new EBaseException(com.netscape.certsrv.apps.CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name));
         }
@@ -342,4 +361,11 @@ public class KeyRecord implements IDBObj, IKeyRecord {
     public Date getModifyTime() {
         return mModifyTime;
     }
+
+    /**
+     * Retrieves the client ID of this record.
+     */
+    public String getClientId() throws EBaseException {
+        return mClientId ;
+    }
 }
diff --git a/pki/base/common/src/com/netscape/cmscore/dbs/KeyRepository.java b/pki/base/common/src/com/netscape/cmscore/dbs/KeyRepository.java
index 269a94c..b1c7eca 100644
--- a/pki/base/common/src/com/netscape/cmscore/dbs/KeyRepository.java
+++ b/pki/base/common/src/com/netscape/cmscore/dbs/KeyRepository.java
@@ -129,6 +129,19 @@ public class KeyRepository extends Repository implements IKeyRepository {
             reg.registerAttribute(KeyRecord.ATTR_ARCHIVED_BY, new
                     StringMapper(KeyDBSchema.LDAP_ATTR_ARCHIVED_BY));
         }
+        if (!reg.isAttributeRegistered(KeyRecord.ATTR_CLIENT_ID)) {
+            reg.registerAttribute(KeyRecord.ATTR_CLIENT_ID, new
+                    StringMapper(KeyDBSchema.LDAP_ATTR_CLIENT_ID));
+        }
+        if (!reg.isAttributeRegistered(KeyRecord.ATTR_STATUS)) {
+            reg.registerAttribute(KeyRecord.ATTR_STATUS, new
+                    StringMapper(KeyDBSchema.LDAP_ATTR_STATUS));
+        }
+        if (!reg.isAttributeRegistered(KeyRecord.ATTR_DATA_TYPE)) {
+            reg.registerAttribute(KeyRecord.ATTR_DATA_TYPE, new
+                    StringMapper(KeyDBSchema.LDAP_ATTR_DATA_TYPE));
+        }
+
     }
 
     public void setKeyStatusUpdateInterval(IRepository requestRepo, int interval) {
@@ -230,7 +243,7 @@ public class KeyRepository extends Repository implements IKeyRepository {
     }
 
     /**
-     * Recovers an archived key by owner name.
+     * Recovers an archived key by owner name.readKeyRecord
      * <P>
      * 
      * @param ownerName owner name
diff --git a/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
index 06d5d96..b3cdc15 100644
--- a/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
+++ b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
@@ -49,12 +49,13 @@ public class DRMRestClient {
         return list;
     }
     
-    public KeyRequestInfo archiveSecurityData(byte[] encoded, String clientId) {
+    public KeyRequestInfo archiveSecurityData(byte[] encoded, String clientId, String dataType) {
         // create archival request
         ArchivalRequestData data = new ArchivalRequestData();
         String req1 = com.netscape.osutil.OSUtil.BtoA(encoded);
         data.setWrappedPrivateData(req1);
         data.setClientId(clientId);
+        data.setDataType(dataType);
 
         KeyRequestInfo info = keyRequestClient.archiveKey(data);
         return info;
@@ -75,7 +76,7 @@ public class DRMRestClient {
         return null;
     }
     
-    public KeyRequestInfo requestRecovery(String keyId, byte[] rpwd, byte[] rkey) {
+    public KeyRequestInfo requestRecovery(String keyId, byte[] rpwd, byte[] rkey, byte[] nonceData) {
         // create recovery request
         RecoveryRequestData data = new RecoveryRequestData();
         data.setKeyId(keyId);
@@ -85,6 +86,10 @@ public class DRMRestClient {
         if (rkey != null) {
             data.setTransWrappedSessionKey(com.netscape.osutil.OSUtil.BtoA(rkey));
         }
+        
+        if (nonceData != null) {
+            data.setNonceData(com.netscape.osutil.OSUtil.BtoA(nonceData));
+        }
 
         KeyRequestInfo info = keyRequestClient.recoverKey(data);
         return info;
@@ -94,7 +99,7 @@ public class DRMRestClient {
         keyRequestClient.approveRequest(recoveryId);
     }
     
-    public KeyData retrieveKey(String keyId, String requestId, byte[] rpwd, byte[] rkey) { 
+    public KeyData retrieveKey(String keyId, String requestId, byte[] rpwd, byte[] rkey, byte[] nonceData) { 
         // create recovery request
         RecoveryRequestData data = new RecoveryRequestData();
         data.setKeyId(keyId);
@@ -105,6 +110,11 @@ public class DRMRestClient {
         if (rpwd != null) {
             data.setSessionWrappedPassphrase(com.netscape.osutil.OSUtil.BtoA(rpwd));
         }
+        
+        if (nonceData != null) {
+            data.setNonceData(com.netscape.osutil.OSUtil.BtoA(nonceData));
+        }
+        
         KeyData key = keyClient.retrieveKey(data);
         return key;
     }
diff --git a/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
index a8560dc..341561a 100644
--- a/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
+++ b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
@@ -17,6 +17,7 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.servlet.test;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.CharConversionException;
 import java.io.IOException;
@@ -27,11 +28,13 @@ import java.security.cert.CertificateEncodingException;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.Random;
+
 import org.mozilla.jss.CryptoManager;
 import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.InvalidBERException;
 import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
 import org.mozilla.jss.asn1.OCTET_STRING;
-import org.mozilla.jss.asn1.SEQUENCE;
 import org.mozilla.jss.crypto.AlreadyInitializedException;
 import org.mozilla.jss.crypto.BadPaddingException;
 import org.mozilla.jss.crypto.Cipher;
@@ -43,13 +46,16 @@ import org.mozilla.jss.crypto.KeyGenAlgorithm;
 import org.mozilla.jss.crypto.KeyGenerator;
 import org.mozilla.jss.crypto.KeyWrapAlgorithm;
 import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.PBEAlgorithm;
 import org.mozilla.jss.crypto.SymmetricKey;
 import org.mozilla.jss.crypto.TokenException;
 import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkcs11.PK11SecureRandom;
+import org.mozilla.jss.pkcs12.PasswordConverter;
+import org.mozilla.jss.pkcs7.EncryptedContentInfo;
 import org.mozilla.jss.pkix.crmf.EncryptedKey;
 import org.mozilla.jss.pkix.crmf.EncryptedValue;
 import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
-import org.mozilla.jss.pkix.primitive.AVA;
 import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
 import org.mozilla.jss.util.Password;
 
@@ -63,6 +69,7 @@ import org.apache.commons.cli.PosixParser;
 import com.netscape.cms.servlet.base.CMSResourceService;
 import com.netscape.cms.servlet.key.model.KeyData;
 import com.netscape.cms.servlet.key.model.KeyDataInfo;
+import com.netscape.cms.servlet.request.KeyRequestResource;
 import com.netscape.cms.servlet.request.model.KeyRequestInfo;
 
 @SuppressWarnings("deprecation")
@@ -124,7 +131,15 @@ public class DRMTest {
         // used for crypto operations
         byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
         IVParameterSpec IV = null;
-        IV = new IVParameterSpec(iv);
+        IVParameterSpec IV_server = null;
+        
+        try {
+            IV = genIV(8);
+        } catch (Exception e) {
+            log("Can't generate initialization vector use default: " + e.toString());
+            IV = new IVParameterSpec(iv);
+        }
+        
         CryptoManager manager = null;
         CryptoToken token = null;
         KeyGenerator kg1 = null;
@@ -196,7 +211,7 @@ public class DRMTest {
 
         // Test 2: Get list of completed key archival requests
         log("\n\nList of completed archival requests");
-        Collection<KeyRequestInfo> list = client.listRequests("complete", "enrollment");
+        Collection<KeyRequestInfo> list = client.listRequests("complete", "securityDataEnrollment");
         if (list == null) {
             log("No requests found");
         } else {
@@ -209,7 +224,7 @@ public class DRMTest {
 
         // Test 3: Get list of key recovery requests
         log("\n\nList of completed recovery requests");
-        Collection<KeyRequestInfo> list2 = client.listRequests("complete", "recovery");
+        Collection<KeyRequestInfo> list2 = client.listRequests("complete", "securityDataRecovery");
         if (list2 == null) {
             log("No requests found");
         } else {
@@ -226,9 +241,10 @@ public class DRMTest {
         try {
             kg1 = token.getKeyGenerator(KeyGenAlgorithm.DES3);
             vek = kg1.generate();
-            byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, vek, null, kg1);
+            
+            byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, vek, null, kg1, IV);
 
-            KeyRequestInfo info = client.archiveSecurityData(encoded, clientId);
+            KeyRequestInfo info = client.archiveSecurityData(encoded, clientId, KeyRequestResource.SYMMETRIC_KEY_TYPE);
             log("Archival Results:");
             printRequestInfo(info);
             keyId = getId(info.getKeyURL());
@@ -238,6 +254,7 @@ public class DRMTest {
         }
 
         //Test 5: Get keyId for active key with client ID
+        
         log("Getting key ID for symmetric key");
         keyInfo = client.getKeyData(clientId, "active");
         String keyId2 = getId(keyInfo.getKeyURL());
@@ -249,6 +266,8 @@ public class DRMTest {
 
         if (!keyId.equals(keyId2)) {
             log("Error: key ids from search and archival do not match");
+        } else {
+            log("Success: keyids from search and archival match.");
         }
 
         // Test 6: Submit a recovery request for the symmetric key using a session key
@@ -256,7 +275,7 @@ public class DRMTest {
         try {
             recoveryKey = kg1.generate();
             wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            KeyRequestInfo info = client.requestRecovery(keyId, null, wrappedRecoveryKey);
+            KeyRequestInfo info = client.requestRecovery(keyId, null, wrappedRecoveryKey, IV.getIV());
             recoveryRequestId = getId(info.getRequestURL());
         } catch (Exception e) {
             log("Exception in recovering symmetric key using session key: " + e.getMessage());
@@ -269,10 +288,12 @@ public class DRMTest {
         // Test 8: Get key
         log("Getting key: " + keyId);
 
-        keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey);
+        keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, IV.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        
+        IV_server = new IVParameterSpec( com.netscape.osutil.OSUtil.AtoB(keyData.getNonceData()));
         try {
-            recoveredKey = unwrap(token, IV, wrappedRecoveredKey.getBytes("ISO-8859-1"), recoveryKey);
+            recoveredKey = unwrap(token, IV_server,com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey), recoveryKey);
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
             e.printStackTrace();
@@ -280,6 +301,8 @@ public class DRMTest {
 
         if (!recoveredKey.equals(com.netscape.osutil.OSUtil.BtoA(vek.getEncoded()))) {
             log("Error: recovered and archived keys do not match!");
+        } else {
+            log("Success: recoverd and archived keys match!");
         }
 
         // Test 9: Submit a recovery request for the symmetric key using a passphrase
@@ -290,7 +313,8 @@ public class DRMTest {
             recoveryKey = kg1.generate();
             wrappedRecoveryPassphrase = wrapPassphrase(token, recoveryPassphrase, IV, recoveryKey);
             wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey);
+            
+            requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
             recoveryRequestId = getId(requestInfo.getRequestURL());
         } catch (Exception e) {
             log("Exception in recovering symmetric key using passphrase" + e.toString());
@@ -303,19 +327,25 @@ public class DRMTest {
 
         // Test 11: Get key
         log("Getting key: " + keyId);
-        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey);
+        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        
         recoveredKey = unwrap(wrappedRecoveredKey, recoveryPassphrase);
 
-        if (!recoveredKey.equals(com.netscape.osutil.OSUtil.BtoA(vek.getEncoded()))) {
+        
+        if (recoveredKey == null || !recoveredKey.equals(com.netscape.osutil.OSUtil.BtoA(vek.getEncoded()))) {
             log("Error: recovered and archived keys do not match!");
+        } else {
+            log("Success: recovered and archived keys do match!");
         }
+        
 
+        passphrase = "secret12345";
         // Test 12: Generate and archive a passphrase
         clientId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime().toString();
         try {
-            byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, null, passphrase, kg1);
-            requestInfo = client.archiveSecurityData(encoded, clientId);
+            byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, null, passphrase, kg1, IV);
+            requestInfo = client.archiveSecurityData(encoded, clientId, KeyRequestResource.PASS_PHRASE_TYPE);
             log("Archival Results:");
             printRequestInfo(requestInfo);
             keyId = getId(requestInfo.getKeyURL());
@@ -336,6 +366,8 @@ public class DRMTest {
 
         if (!keyId.equals(keyId2)) {
             log("Error: key ids from search and archival do not match");
+        } else {
+            log("Success: key ids from search and archival do match!");
         }
 
         // Test 14: Submit a recovery request for the passphrase using a session key
@@ -346,7 +378,8 @@ public class DRMTest {
         try {
             recoveryKey = kg1.generate();
             wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
-            requestInfo = client.requestRecovery(keyId, null, wrappedRecoveryKey);
+            wrappedRecoveryPassphrase = wrapPassphrase(token, recoveryPassphrase, IV, recoveryKey);
+            requestInfo = client.requestRecovery(keyId, null, wrappedRecoveryKey, IV.getIV());
             recoveryRequestId = getId(requestInfo.getRequestURL());
         } catch (Exception e) {
             log("Exception in recovering passphrase using session key: " + e.getMessage());
@@ -359,22 +392,26 @@ public class DRMTest {
         // Test 16: Get key
         log("Getting passphrase: " + keyId);
 
-        keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey);
+        keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey, IV.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        IV_server = new IVParameterSpec( com.netscape.osutil.OSUtil.AtoB(keyData.getNonceData()));
         try {
-            recoveredKey = unwrap(token, IV, wrappedRecoveredKey.getBytes("ISO-8859-1"), recoveryKey);
+            recoveredKey = unwrap(token, IV_server, com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey), recoveryKey);
+            recoveredKey = new String(com.netscape.osutil.OSUtil.AtoB(recoveredKey), "UTF-8");
         } catch (Exception e) {
             log("Exception in unwrapping key: " + e.toString());
             e.printStackTrace();
         }
-
-        if (!recoveredKey.equals(passphrase)) {
+        
+        if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
             log("Error: recovered and archived passphrases do not match!");
+        } else {
+            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");
-        requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey);
+        requestInfo = client.requestRecovery(keyId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
         recoveryRequestId = getId(requestInfo.getRequestURL());
 
         //Test 18: Approve recovery
@@ -383,19 +420,80 @@ public class DRMTest {
 
         // Test 19: Get key
         log("Getting passphrase: " + keyId);
-        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey);
+        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
         wrappedRecoveredKey = keyData.getWrappedPrivateData();
         recoveredKey = unwrap(wrappedRecoveredKey, recoveryPassphrase);
+        try {
+            recoveredKey = new String(com.netscape.osutil.OSUtil.AtoB(recoveredKey), "UTF-8");
+        } catch (Exception e) {
+            log("Error: Can't convert recovered passphrase from binary to ascii!");
+        }
 
-        if (!recoveredKey.equals(passphrase)) {
+        if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
             log("Error: recovered and archived passphrases do not match!");
+        } else {
+            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.");
+        requestInfo = client.requestRecovery(keyId, null, null, null);
+        recoveryRequestId = getId(requestInfo.getRequestURL());
+
+        //Test 21: Approve recovery
+        log("Approving recovery request: " + recoveryRequestId);
+        client.approveRecovery(recoveryRequestId);
+
+        // Test 22: Get key
+        log("Getting passphrase: " + keyId);
+        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, wrappedRecoveryKey, IV.getIV());
+        wrappedRecoveredKey = keyData.getWrappedPrivateData();
+        recoveredKey = unwrap(wrappedRecoveredKey, recoveryPassphrase);
+        try {
+            recoveredKey = new String(com.netscape.osutil.OSUtil.AtoB(recoveredKey), "UTF-8");
+        } catch (Exception e) {
+            log("Error: Can't convert recovered passphrase from binary to ascii!");
         }
 
+        if (recoveredKey == null || !recoveredKey.equals(passphrase)) {
+            log("Error: recovered and archived passphrases do not match!");
+        } else {
+            log("Success: recovered and archived passphrases do match!");
+        }
     }
 
     private static String unwrap(String wrappedRecoveredKey, String recoveryPassphrase) {
-        // TODO Auto-generated method stub
-        return null;
+
+        EncryptedContentInfo cInfo = null;
+        String unwrappedData = null;
+        
+        //We have to do this to get the decoding to work.
+        PBEAlgorithm pbeAlg = PBEAlgorithm.PBE_SHA1_DES3_CBC;
+        
+        log("pbeAlg: " + pbeAlg);
+        try {
+            Password pass = new Password(recoveryPassphrase.toCharArray());
+            PasswordConverter passConverter = new
+                    PasswordConverter();
+
+            byte[] encoded = com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey);
+
+            ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+            cInfo = (EncryptedContentInfo)
+                      new EncryptedContentInfo.Template().decode(inStream);
+
+            byte[] decodedData = cInfo.decrypt(pass, passConverter);
+
+            unwrappedData = com.netscape.osutil.OSUtil.BtoA(decodedData);
+
+        } catch (Exception e) {
+            log("Problem unwraping PBE wrapped datat! " + e.toString());
+
+        }
+
+        return unwrappedData;
     }
 
     private static void log(String string) {
@@ -407,31 +505,24 @@ public class DRMTest {
             SymmetricKey recoveryKey) throws NoSuchAlgorithmException, TokenException, BadPaddingException,
             IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException {
 
-        if (wrappedRecoveredKey == null || recoveryKey == null || token == null) {
-            return null;
-        }
-
         Cipher decryptor = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
         decryptor.initDecrypt(recoveryKey, IV);
         byte[] unwrappedData = decryptor.doFinal(wrappedRecoveredKey);
-        String unwrappedS = new String(unwrappedData);
+        String unwrappedS = com.netscape.osutil.OSUtil.BtoA( unwrappedData);
 
         return unwrappedS;
     }
 
     private static String getId(String link) {
-        return link.substring(link.lastIndexOf("/"));
+        return link.substring(link.lastIndexOf("/") + 1);
     }
 
     private static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert,
-            SymmetricKey vek, String passphrase, KeyGenerator kg1) throws TokenException, CharConversionException,
+            SymmetricKey vek, String passphrase, KeyGenerator kg1, IVParameterSpec IV) throws TokenException, CharConversionException,
             NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
             CertificateEncodingException, IOException, IllegalStateException, IllegalBlockSizeException,
             BadPaddingException {
         byte[] key_data = null;
-        byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
-        IVParameterSpec IV = null;
-        IV = new IVParameterSpec(iv);
 
         //generate session key
         SymmetricKey sk = kg1.generate();
@@ -450,17 +541,35 @@ public class DRMTest {
 
         // create PKIArchiveOptions structure
         AlgorithmIdentifier algS = new AlgorithmIdentifier(new OBJECT_IDENTIFIER("1.2.840.113549.3.7"),
-                new OCTET_STRING(iv));
+                new OCTET_STRING(IV.getIV()));
         EncryptedValue encValue = new EncryptedValue(null, algS, new BIT_STRING(session_data, 0), null, null,
                 new BIT_STRING(key_data, 0));
         EncryptedKey key = new EncryptedKey(encValue);
         PKIArchiveOptions opt = new PKIArchiveOptions(key);
-        SEQUENCE seq = new SEQUENCE();
-        seq.addElement(new AVA(new OBJECT_IDENTIFIER("1.3.6.1.5.5.7.5.1.4"), opt));
-
-        ByteArrayOutputStream bo = new ByteArrayOutputStream();
-        seq.encode(bo);
-        byte[] encoded = bo.toByteArray();
+        
+        byte[] encoded = null;
+        
+        try {
+          
+            //Let's make sure we can decode the encoded PKIArchiveOptions..
+          ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+          
+          opt.encode(oStream);
+          
+          encoded = oStream.toByteArray();
+          ByteArrayInputStream inStream = new ByteArrayInputStream( encoded);
+          PKIArchiveOptions  options = (PKIArchiveOptions)
+                    (new PKIArchiveOptions.Template()).decode(inStream);
+          log("Decoded PKIArchiveOptions: " + options);
+        } catch (IOException e) {
+            log("Problem with PKIArchiveOptions: " + e.toString());
+            return null;
+            
+        } catch (InvalidBERException e) {
+            log("Problem with PKIArchiveOptions: " + e.toString());
+            return null;
+        }
+        
         return encoded;
     }
 
@@ -470,28 +579,16 @@ public class DRMTest {
         byte[] wrappedPassphrase = null;
         Cipher encryptor = null;
 
-        if (passphrase == null || sk == null || token == null || IV == null) {
-            return null;
-        }
-
         encryptor = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
         log("cipher " + encryptor);
 
         if (encryptor != null) {
             encryptor.initEncrypt(sk, IV);
-            wrappedPassphrase = encryptor.doFinal(passphrase.getBytes());
-            log("Pass phrase mode key_data: " + wrappedPassphrase);
-
-            // Try to decrypt
-            String wrappedS = new String(wrappedPassphrase, "ISO-8859-1");
-            byte[] pPhrase = wrappedS.getBytes("ISO-8859-1");
-            encryptor.initDecrypt(sk, IV);
-            byte[] decrypted = encryptor.doFinal(pPhrase);
-            String s = new String(decrypted, "ISO-8859-1");
-            log("Re decrypted pass phrase " + s + " decrypted.size " + decrypted.length);
+            wrappedPassphrase = encryptor.doFinal(passphrase.getBytes("UTF-8"));
         } else {
             throw new IOException("Failed to create cipher");
         }
+        
         return wrappedPassphrase;
     }
 
@@ -512,5 +609,15 @@ public class DRMTest {
         log("Status:        " + info.getRequestStatus());
         log("Type:          " + info.getRequestType());
     }
+    
+    //Use this when we actually create random initialization vectors
+    private static IVParameterSpec genIV(int blockSize) throws Exception {
+        // generate an IV
+        byte[] iv = new byte[blockSize];
+
+        Random rnd = new Random();
+        rnd.nextBytes(iv);
 
+        return new IVParameterSpec(iv);
+    }
 }
diff --git a/pki/base/kra/shared/conf/schema.ldif b/pki/base/kra/shared/conf/schema.ldif
index caf71e9..70578e2 100644
--- a/pki/base/kra/shared/conf/schema.ldif
+++ b/pki/base/kra/shared/conf/schema.ldif
@@ -161,6 +161,21 @@ attributeTypes: ( keySize-oid NAME 'keySize' DESC 'CMS defined attribute' SYNTAX
 dn: cn=schema
 changetype: modify
 add: attributeTypes
+attributeTypes: ( clientId-oid NAME 'clientId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dataType-oid NAME 'dataType' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( status-oid NAME 'status' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
 attributeTypes: ( keyState-oid NAME 'keyState' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
 
 dn: cn=schema
@@ -446,7 +461,7 @@ objectClasses: ( userDetails-oid NAME 'userDetails' DESC 'CMS defined class' SUP
 dn: cn=schema
 changetype: modify
 add: objectClasses
-objectClasses: ( keyRecord-oid NAME 'keyRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ keyState $ privateKeyData $ ownerName $ keySize $ metaInfo $ dateOfArchival $ dateOfRecovery $ algorithm $ publicKeyFormat $ publicKeyData $ archivedBy ) X-ORIGIN 'user defined' )
+objectClasses: ( keyRecord-oid NAME 'keyRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ keyState $ privateKeyData $ ownerName $ keySize $ metaInfo $ dateOfArchival $ dateOfRecovery $ algorithm $ publicKeyFormat $ publicKeyData $ archivedBy $ clientId $ dataType $ status ) X-ORIGIN 'user defined' )
 
 dn: cn=schema
 changetype: modify
diff --git a/pki/base/kra/src/com/netscape/kra/ArchiveOptions.java b/pki/base/kra/src/com/netscape/kra/ArchiveOptions.java
new file mode 100644
index 0000000..7130fb9
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/ArchiveOptions.java
@@ -0,0 +1,154 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.pkix.cms.EncryptedContentInfo;
+import org.mozilla.jss.pkix.cms.EnvelopedData;
+import org.mozilla.jss.pkix.cms.RecipientInfo;
+import org.mozilla.jss.pkix.crmf.EncryptedKey;
+import org.mozilla.jss.pkix.crmf.EncryptedValue;
+import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+
+class ArchiveOptions {
+    private String mSymmAlgOID = null;
+    private byte mSymmAlgParams[] = null;
+    private byte mEncSymmKey[] = null;
+    private byte mEncValue[] = null;
+
+    public ArchiveOptions(PKIArchiveOptions opts) throws EBaseException {
+        try {
+            EncryptedKey key = opts.getEncryptedKey();
+            ANY enveloped_val = null;
+            EncryptedValue val = null;
+            AlgorithmIdentifier symmAlg = null;
+
+            if (key.getType() == org.mozilla.jss.pkix.crmf.EncryptedKey.ENVELOPED_DATA) {
+                CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENVELOPED_DATA");
+                // this is the new RFC4211 EncryptedKey that should
+                // have EnvelopedData to replace the deprecated EncryptedValue
+                enveloped_val = key.getEnvelopedData();
+                byte[] env_b = enveloped_val.getEncoded();
+                EnvelopedData.Template env_template = new EnvelopedData.Template();
+                EnvelopedData env_data =
+                        (EnvelopedData) env_template.decode(new ByteArrayInputStream(env_b));
+                EncryptedContentInfo eCI = env_data.getEncryptedContentInfo();
+                symmAlg = eCI.getContentEncryptionAlgorithm();
+                mSymmAlgOID = symmAlg.getOID().toString();
+                mSymmAlgParams =
+                        ((OCTET_STRING) ((ANY) symmAlg.getParameters()).decodeWith(OCTET_STRING.getTemplate()))
+                                .toByteArray();
+
+                SET recipients = env_data.getRecipientInfos();
+                if (recipients.size() <= 0) {
+                    CMS.debug("EnrollService: ArchiveOptions() - missing recipient information ");
+                    throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
+                            "[PKIArchiveOptions] missing recipient information "));
+                }
+                //check recpient - later
+                //we only handle one recipient here anyways.  so, either the key
+                //can be decrypted or it can't. No risk here.
+                RecipientInfo ri = (RecipientInfo) recipients.elementAt(0);
+                OCTET_STRING key_o = ri.getEncryptedKey();
+                mEncSymmKey = key_o.toByteArray();
+
+                OCTET_STRING oString = eCI.getEncryptedContent();
+                BIT_STRING encVal = new BIT_STRING(oString.toByteArray(), 0);
+                mEncValue = encVal.getBits();
+                CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENVELOPED_DATA done");
+            } else if (key.getType() == org.mozilla.jss.pkix.crmf.EncryptedKey.ENCRYPTED_VALUE) {
+                CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENCRYPTED_VALUE");
+                // this is deprecated: EncryptedValue
+                val = key.getEncryptedValue();
+                symmAlg = val.getSymmAlg();
+                mSymmAlgOID = symmAlg.getOID().toString();
+                mSymmAlgParams =
+                        ((OCTET_STRING) ((ANY) symmAlg.getParameters()).decodeWith(OCTET_STRING.getTemplate()))
+                                .toByteArray();
+                BIT_STRING encSymmKey = val.getEncSymmKey();
+
+                mEncSymmKey = encSymmKey.getBits();
+                BIT_STRING encVal = val.getEncValue();
+
+                mEncValue = encVal.getBits();
+                CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENCRYPTED_VALUE done");
+            } else {
+                CMS.debug("EnrollService: ArchiveOptions() invalid EncryptedKey type");
+                throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[PKIArchiveOptions] type "
+                        + key.getType()));
+            }
+
+        } catch (InvalidBERException e) {
+            CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
+            throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
+                    "[PKIArchiveOptions]" + e.toString()));
+        } catch (IOException e) {
+            CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
+            throw new EBaseException("ArchiveOptions() exception caught: " +
+                    e.toString());
+        } catch (Exception e) {
+            CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
+            throw new EBaseException("ArchiveOptions() exception caught: " +
+                    e.toString());
+        }
+
+    }
+    
+    static public ArchiveOptions toArchiveOptions(byte options[]) throws
+                                      EBaseException {
+        ByteArrayInputStream bis = new ByteArrayInputStream(options);
+        PKIArchiveOptions archOpts = null;
+
+        try {
+            archOpts = (PKIArchiveOptions)
+                    (new PKIArchiveOptions.Template()).decode(bis);
+        } catch (Exception e) {
+            throw new EBaseException("Failed to decode input PKIArchiveOptions.");
+        }
+
+        return new ArchiveOptions(archOpts);
+
+    }
+
+    public String getSymmAlgOID() {
+        return mSymmAlgOID;
+    }
+
+    public byte[] getSymmAlgParams() {
+        return mSymmAlgParams;
+    }
+
+    public byte[] getEncSymmKey() {
+        return mEncSymmKey;
+    }
+
+    public byte[] getEncValue() {
+        return mEncValue;
+    }
+}
diff --git a/pki/base/kra/src/com/netscape/kra/EncryptionUnit.java b/pki/base/kra/src/com/netscape/kra/EncryptionUnit.java
index d90afd7..8a5984c 100644
--- a/pki/base/kra/src/com/netscape/kra/EncryptionUnit.java
+++ b/pki/base/kra/src/com/netscape/kra/EncryptionUnit.java
@@ -54,6 +54,7 @@ import com.netscape.cmscore.util.Debug;
  * @author thomask
  * @version $Revision$, $Date$
  */
+@SuppressWarnings("deprecation")
 public abstract class EncryptionUnit implements IEncryptionUnit {
 
     /* Establish one constant IV for base class, to be used for
@@ -167,97 +168,14 @@ public abstract class EncryptionUnit implements IEncryptionUnit {
             return null;
         }
     }
-
-    /**
-     * Wraps the data using transport public key.
-     */
-    public byte[] wrap(PrivateKey priKey) throws EBaseException {
-        try {
-
-            CMS.debug("EncryptionUnit.wrap");
-            CryptoToken token = getToken();
-
-            // (1) generate session key
-            org.mozilla.jss.crypto.KeyGenerator kg =
-                        token.getKeyGenerator(KeyGenAlgorithm.DES3);
-            // internalToken.getKeyGenerator(KeyGenAlgorithm.DES3);
-            SymmetricKey.Usage usages[] = new SymmetricKey.Usage[2];
-            usages[0] = SymmetricKey.Usage.WRAP;
-            usages[1] = SymmetricKey.Usage.UNWRAP;
-            kg.setKeyUsages(usages);
-            kg.temporaryKeys(true);
-            SymmetricKey sk = kg.generate();
-            CMS.debug("EncryptionUnit:wrap() session key generated on slot: " + token.getName());
-
-            // (2) wrap private key with session key
-            // KeyWrapper wrapper = internalToken.getKeyWrapper(
-            KeyWrapper wrapper = token.getKeyWrapper(
-                    KeyWrapAlgorithm.DES3_CBC_PAD);
-
-            wrapper.initWrap(sk, IV);
-            byte pri[] = wrapper.wrap(priKey);
-            CMS.debug("EncryptionUnit:wrap() privKey wrapped");
-
-            // (3) wrap session with transport public
-            KeyWrapper rsaWrap = token.getKeyWrapper(
-                    KeyWrapAlgorithm.RSA);
-
-            rsaWrap.initWrap(getPublicKey(), null);
-            byte session[] = rsaWrap.wrap(sk);
-            CMS.debug("EncryptionUnit:wrap() sessin key wrapped");
-
-            // use MY own structure for now:
-            // SEQUENCE {
-            //     encryptedSession OCTET STRING,
-            //     encryptedPrivate OCTET STRING
-            // }
-
-            DerOutputStream tmp = new DerOutputStream();
-            DerOutputStream out = new DerOutputStream();
-
-            tmp.putOctetString(session);
-            tmp.putOctetString(pri);
-            out.write(DerValue.tag_Sequence, tmp);
-
-            return out.toByteArray();
-        } catch (TokenException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
-            Debug.trace("EncryptionUnit::wrap " + e.toString());
-            return null;
-        } catch (NoSuchAlgorithmException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
-            Debug.trace("EncryptionUnit::wrap " + e.toString());
-            return null;
-        } catch (CharConversionException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
-            Debug.trace("EncryptionUnit::wrap " + e.toString());
-            return null;
-        } catch (InvalidAlgorithmParameterException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
-            Debug.trace("EncryptionUnit::wrap " + e.toString());
-            return null;
-        } catch (InvalidKeyException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
-            Debug.trace("EncryptionUnit::wrap " + e.toString());
-            return null;
-        } catch (IOException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
-            Debug.trace("EncryptionUnit::wrap " + e.toString());
-            return null;
-        } catch (Exception e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
-            Debug.trace("EncryptionUnit::wrap " + e.toString());
-            return null;
-        }
+    
+    public byte[] wrap(PrivateKey privKey) throws EBaseException {
+        return _wrap(privKey,null);
+    }
+    
+    public byte[] wrap(SymmetricKey symmKey) throws EBaseException {
+        return _wrap(null,symmKey);
     }
-
     /**
      * External unwrapping. Unwraps the data using
      * the transport private key.
@@ -365,15 +283,72 @@ public abstract class EncryptionUnit implements IEncryptionUnit {
             return null;
         }
     }
+    
+    /**
+     * External unwrapping. Unwraps the symmetric key using 
+     * the transport private key.
+     */
+    public SymmetricKey unwrap_symmetric(byte encSymmKey[],
+        String symmAlgOID, byte symmAlgParams[],
+        byte encValue[])
+        throws EBaseException {
+        try {
+            CryptoToken token = getToken();
 
+            // (1) unwrap the session
+            KeyWrapper rsaWrap = token.getKeyWrapper(
+                    KeyWrapAlgorithm.RSA);
+
+            rsaWrap.initUnwrap(getPrivateKey(), null);
+            SymmetricKey sk = rsaWrap.unwrapSymmetric(encSymmKey,
+                    SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP,
+                    0);
+
+            // (2) unwrap the sym key
+            KeyWrapper wrapper = token.getKeyWrapper(
+                    KeyWrapAlgorithm.DES3_CBC_PAD // XXX
+                    );
+
+            wrapper.initUnwrap(sk, new IVParameterSpec(
+                    symmAlgParams));
+
+            SymmetricKey symKey = wrapper.unwrapSymmetric(encValue, SymmetricKey.DES3, SymmetricKey.Usage.DECRYPT, 0);
+
+            return symKey;
+        } catch (TokenException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            Debug.trace("EncryptionUnit::unwrap " + e.toString());
+            return null;
+        } catch (NoSuchAlgorithmException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            Debug.trace("EncryptionUnit::unwrap " + e.toString());
+            return null;
+        } catch (InvalidAlgorithmParameterException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            Debug.trace("EncryptionUnit::unwrap " + e.toString());
+            return null;
+        } catch (InvalidKeyException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            Debug.trace("EncryptionUnit::unwrap " + e.toString());
+            return null;
+        } catch (Exception e) {
+            CMS.debug("EncryptionUnit.unwrap : Exception:" + e.toString());
+            return null;
+        }
+    }
+    
     /**
-     * External unwrapping. Unwraps the data using
+     * External unwrapping. Unwraps the data using 
      * the transport private key.
      */
-    public PrivateKey unwrap(byte encSymmKey[],
-            String symmAlgOID, byte symmAlgParams[],
-            byte encValue[], PublicKey pubKey)
-            throws EBaseException {
+    public PrivateKey unwrap(byte encSymmKey[], 
+        String symmAlgOID, byte symmAlgParams[],
+        byte encValue[], PublicKey pubKey)
+        throws EBaseException {
         try {
             CryptoToken token = getToken();
 
@@ -389,12 +364,12 @@ public abstract class EncryptionUnit implements IEncryptionUnit {
             // (2) unwrap the pri
             KeyWrapper wrapper = token.getKeyWrapper(
                     KeyWrapAlgorithm.DES3_CBC_PAD // XXX
-                    );
+                );
 
             wrapper.initUnwrap(sk, new IVParameterSpec(
                     symmAlgParams));
 
-            PrivateKey.Type keytype = null;
+           PrivateKey.Type keytype = null;
             String alg = pubKey.getAlgorithm();
             if (alg.equals("DSA")) {
                 keytype = PrivateKey.DSA;
@@ -404,34 +379,35 @@ public abstract class EncryptionUnit implements IEncryptionUnit {
                 keytype = PrivateKey.RSA;
             }
             PrivateKey pk = wrapper.unwrapTemporaryPrivate(encValue,
-                    keytype, pubKey);
+                    keytype , pubKey);
 
             return pk;
         } catch (TokenException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
             Debug.trace("EncryptionUnit::unwrap " + e.toString());
             return null;
         } catch (NoSuchAlgorithmException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
             Debug.trace("EncryptionUnit::unwrap " + e.toString());
             return null;
         } catch (InvalidAlgorithmParameterException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
             Debug.trace("EncryptionUnit::unwrap " + e.toString());
             return null;
         } catch (InvalidKeyException e) {
-            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
             Debug.trace("EncryptionUnit::unwrap " + e.toString());
             return null;
         } catch (Exception e) {
-            CMS.debug("EncryptionUnit.unwrap : Exception:" + e.toString());
+            CMS.debug("EncryptionUnit.unwrap : Exception:"+e.toString());
             return null;
         }
     }
+    
+    /**
+     * External unwrapping. Unwraps the data using
+     * the transport private key.
+     */
 
     public byte[] decryptInternalPrivate(byte wrappedKeyData[])
             throws EBaseException {
@@ -506,6 +482,72 @@ public abstract class EncryptionUnit implements IEncryptionUnit {
     }
 
     /**
+     * External unwrapping of stored symmetric key.
+     */
+    public SymmetricKey unwrap(byte wrappedKeyData[])
+            throws EBaseException {
+        try {
+            DerValue val = new DerValue(wrappedKeyData);
+            // val.tag == DerValue.tag_Sequence
+            DerInputStream in = val.data;
+            DerValue dSession = in.getDerValue();
+            byte session[] = dSession.getOctetString();
+            DerValue dPri = in.getDerValue();
+            byte pri[] = dPri.getOctetString();
+
+            CryptoToken token = getToken();
+            // (1) unwrap the session key
+            KeyWrapper rsaWrap = token.getKeyWrapper(
+                    KeyWrapAlgorithm.RSA);
+
+            rsaWrap.initUnwrap(getPrivateKey(), null);
+            SymmetricKey sk = rsaWrap.unwrapSymmetric(session,
+                    SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP, 0);
+            
+            // (2) unwrap the symmetric key
+            KeyWrapper wrapper = token.getKeyWrapper(
+                    KeyWrapAlgorithm.DES3_CBC_PAD);
+
+            wrapper.initUnwrap(sk, IV);
+
+            SymmetricKey sk_ret = wrapper.unwrapSymmetric(pri,
+                    SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP,
+                    0);
+            
+            return sk_ret;
+        } catch (TokenException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            Debug.trace("EncryptionUnit::unwrap " + e.toString());
+            CMS.debug(e);
+            return null;
+        } catch (NoSuchAlgorithmException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            Debug.trace("EncryptionUnit::unwrap " + e.toString());
+            return null;
+        } catch (InvalidAlgorithmParameterException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            Debug.trace("EncryptionUnit::unwrap " + e.toString());
+            return null;
+        } catch (InvalidKeyException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            Debug.printStackTrace(e);
+            return null;
+        } catch (IOException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_UNWRAP", e.toString()));
+            Debug.trace("EncryptionUnit::unwrap " + e.toString());
+            return null;
+        } catch (Exception e) {
+            Debug.printStackTrace(e);
+            return null;
+        }
+    }
+    
+    /**
      * Internal unwrapping.
      */
     public PrivateKey unwrap_temp(byte wrappedKeyData[], PublicKey pubKey)
@@ -591,6 +633,105 @@ public abstract class EncryptionUnit implements IEncryptionUnit {
             return null;
         }
     }
+    
+    /***
+     * Internal wrap, accounts for either private or symmetric key
+     */
+    private byte[] _wrap(PrivateKey priKey, SymmetricKey symmKey) throws EBaseException {
+        try {
+            if ((priKey == null && symmKey == null) || (priKey != null && symmKey != null)) {
+                return null;
+            }
+            CMS.debug("EncryptionUnit.wrap interal.");
+            CryptoToken token = getToken();
+
+            // (1) generate session key
+            org.mozilla.jss.crypto.KeyGenerator kg =
+                        token.getKeyGenerator(KeyGenAlgorithm.DES3);
+            // internalToken.getKeyGenerator(KeyGenAlgorithm.DES3);
+            SymmetricKey.Usage usages[] = new SymmetricKey.Usage[2];
+            usages[0] = SymmetricKey.Usage.WRAP;
+            usages[1] = SymmetricKey.Usage.UNWRAP;
+            kg.setKeyUsages(usages);
+            kg.temporaryKeys(true);
+            SymmetricKey sk = kg.generate();
+            CMS.debug("EncryptionUnit:wrap() session key generated on slot: " + token.getName());
+
+            // (2) wrap private key with session key
+            // KeyWrapper wrapper = internalToken.getKeyWrapper(
+            KeyWrapper wrapper = token.getKeyWrapper(
+                    KeyWrapAlgorithm.DES3_CBC_PAD);
+
+            wrapper.initWrap(sk, IV);
+            
+            byte pri[] = null;
+            
+            if ( priKey != null) {
+                pri = wrapper.wrap(priKey);
+            } else if ( symmKey != null) {
+                pri = wrapper.wrap(symmKey);
+            }
+            CMS.debug("EncryptionUnit:wrap() privKey wrapped");
+
+            // (3) wrap session with transport public
+            KeyWrapper rsaWrap = token.getKeyWrapper(
+                    KeyWrapAlgorithm.RSA);
+
+            rsaWrap.initWrap(getPublicKey(), null);
+            byte session[] = rsaWrap.wrap(sk);
+            CMS.debug("EncryptionUnit:wrap() sessin key wrapped");
+
+            // use MY own structure for now:
+            // SEQUENCE {
+            //     encryptedSession OCTET STRING,
+            //     encryptedPrivate OCTET STRING
+            // }
+
+            DerOutputStream tmp = new DerOutputStream();
+            DerOutputStream out = new DerOutputStream();
+
+            tmp.putOctetString(session);
+            tmp.putOctetString(pri);
+            out.write(DerValue.tag_Sequence, tmp);
+
+            return out.toByteArray();
+        } catch (TokenException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+            Debug.trace("EncryptionUnit::wrap " + e.toString());
+            return null;
+        } catch (NoSuchAlgorithmException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+            Debug.trace("EncryptionUnit::wrap " + e.toString());
+            return null;
+        } catch (CharConversionException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+            Debug.trace("EncryptionUnit::wrap " + e.toString());
+            return null;
+        } catch (InvalidAlgorithmParameterException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+            Debug.trace("EncryptionUnit::wrap " + e.toString());
+            return null;
+        } catch (InvalidKeyException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+            Debug.trace("EncryptionUnit::wrap " + e.toString());
+            return null;
+        } catch (IOException e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+            Debug.trace("EncryptionUnit::wrap " + e.toString());
+            return null;
+        } catch (Exception e) {
+            CMS.getLogger().log(ILogger.EV_SYSTEM, null, ILogger.S_KRA, ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_ENCRYPTION_WRAP", e.toString()));
+            Debug.trace("EncryptionUnit::wrap " + e.toString());
+            return null;
+        }
+    }
 
     /**
      * Verify the given key pair.
diff --git a/pki/base/kra/src/com/netscape/kra/EnrollmentService.java b/pki/base/kra/src/com/netscape/kra/EnrollmentService.java
index b9df360..c2705e1 100644
--- a/pki/base/kra/src/com/netscape/kra/EnrollmentService.java
+++ b/pki/base/kra/src/com/netscape/kra/EnrollmentService.java
@@ -35,25 +35,15 @@ import netscape.security.x509.CertificateX509Key;
 import netscape.security.x509.X509CertInfo;
 import netscape.security.x509.X509Key;
 
-import org.mozilla.jss.asn1.ANY;
 import org.mozilla.jss.asn1.ASN1Util;
 import org.mozilla.jss.asn1.ASN1Value;
-import org.mozilla.jss.asn1.BIT_STRING;
 import org.mozilla.jss.asn1.InvalidBERException;
 import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
-import org.mozilla.jss.asn1.OCTET_STRING;
 import org.mozilla.jss.asn1.SEQUENCE;
-import org.mozilla.jss.asn1.SET;
-import org.mozilla.jss.pkix.cms.EncryptedContentInfo;
-import org.mozilla.jss.pkix.cms.EnvelopedData;
-import org.mozilla.jss.pkix.cms.RecipientInfo;
 import org.mozilla.jss.pkix.crmf.CertReqMsg;
 import org.mozilla.jss.pkix.crmf.CertRequest;
-import org.mozilla.jss.pkix.crmf.EncryptedKey;
-import org.mozilla.jss.pkix.crmf.EncryptedValue;
 import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
 import org.mozilla.jss.pkix.primitive.AVA;
-import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.authentication.AuthToken;
@@ -73,6 +63,7 @@ import com.netscape.certsrv.security.ITransportKeyUnit;
 import com.netscape.certsrv.util.IStatsSubsystem;
 import com.netscape.cmscore.crmf.CRMFParser;
 import com.netscape.cmscore.crmf.PKIArchiveOptionsContainer;
+import com.netscape.kra.ArchiveOptions;
 import com.netscape.cmscore.dbs.KeyRecord;
 
 /**
@@ -553,7 +544,7 @@ public class EnrollmentService implements IService {
      */
     public static PKIArchiveOptionsContainer[] getPKIArchiveOptions(String crmfBlob)
             throws EBaseException {
-        Vector options = new Vector();
+        Vector<Object> options = new Vector<Object>();
 
         if (CMS.debugOn())
             CMS.debug("EnrollmentService::getPKIArchiveOptions> crmfBlob=" + crmfBlob);
@@ -876,107 +867,3 @@ public class EnrollmentService implements IService {
                 msg);
     }
 }
-
-/**
- * Parsed and Flattened structure of PKIArchiveOptions.
- */
-class ArchiveOptions {
-    private String mSymmAlgOID = null;
-    private byte mSymmAlgParams[] = null;
-    private byte mEncSymmKey[] = null;
-    private byte mEncValue[] = null;
-
-    public ArchiveOptions(PKIArchiveOptions opts) throws EBaseException {
-        try {
-            EncryptedKey key = opts.getEncryptedKey();
-            ANY enveloped_val = null;
-            EncryptedValue val = null;
-            AlgorithmIdentifier symmAlg = null;
-
-            if (key.getType() == org.mozilla.jss.pkix.crmf.EncryptedKey.ENVELOPED_DATA) {
-                CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENVELOPED_DATA");
-                // this is the new RFC4211 EncryptedKey that should
-                // have EnvelopedData to replace the deprecated EncryptedValue
-                enveloped_val = key.getEnvelopedData();
-                byte[] env_b = enveloped_val.getEncoded();
-                EnvelopedData.Template env_template = new EnvelopedData.Template();
-                EnvelopedData env_data =
-                        (EnvelopedData) env_template.decode(new ByteArrayInputStream(env_b));
-                EncryptedContentInfo eCI = env_data.getEncryptedContentInfo();
-                symmAlg = eCI.getContentEncryptionAlgorithm();
-                mSymmAlgOID = symmAlg.getOID().toString();
-                mSymmAlgParams =
-                        ((OCTET_STRING) ((ANY) symmAlg.getParameters()).decodeWith(OCTET_STRING.getTemplate()))
-                                .toByteArray();
-
-                SET recipients = env_data.getRecipientInfos();
-                if (recipients.size() <= 0) {
-                    CMS.debug("EnrollService: ArchiveOptions() - missing recipient information ");
-                    throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
-                            "[PKIArchiveOptions] missing recipient information "));
-                }
-                //check recpient - later
-                //we only handle one recipient here anyways.  so, either the key
-                //can be decrypted or it can't. No risk here.
-                RecipientInfo ri = (RecipientInfo) recipients.elementAt(0);
-                OCTET_STRING key_o = ri.getEncryptedKey();
-                mEncSymmKey = key_o.toByteArray();
-
-                OCTET_STRING oString = eCI.getEncryptedContent();
-                BIT_STRING encVal = new BIT_STRING(oString.toByteArray(), 0);
-                mEncValue = encVal.getBits();
-                CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENVELOPED_DATA done");
-            } else if (key.getType() == org.mozilla.jss.pkix.crmf.EncryptedKey.ENCRYPTED_VALUE) {
-                CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENCRYPTED_VALUE");
-                // this is deprecated: EncryptedValue
-                val = key.getEncryptedValue();
-                symmAlg = val.getSymmAlg();
-                mSymmAlgOID = symmAlg.getOID().toString();
-                mSymmAlgParams =
-                        ((OCTET_STRING) ((ANY) symmAlg.getParameters()).decodeWith(OCTET_STRING.getTemplate()))
-                                .toByteArray();
-                BIT_STRING encSymmKey = val.getEncSymmKey();
-
-                mEncSymmKey = encSymmKey.getBits();
-                BIT_STRING encVal = val.getEncValue();
-
-                mEncValue = encVal.getBits();
-                CMS.debug("EnrollService: ArchiveOptions() EncryptedKey type= ENCRYPTED_VALUE done");
-            } else {
-                CMS.debug("EnrollService: ArchiveOptions() invalid EncryptedKey type");
-                throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "[PKIArchiveOptions] type "
-                        + key.getType()));
-            }
-
-        } catch (InvalidBERException e) {
-            CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
-            throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE",
-                    "[PKIArchiveOptions]" + e.toString()));
-        } catch (IOException e) {
-            CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
-            throw new EBaseException("ArchiveOptions() exception caught: " +
-                    e.toString());
-        } catch (Exception e) {
-            CMS.debug("EnrollService: ArchiveOptions(): " + e.toString());
-            throw new EBaseException("ArchiveOptions() exception caught: " +
-                    e.toString());
-        }
-
-    }
-
-    public String getSymmAlgOID() {
-        return mSymmAlgOID;
-    }
-
-    public byte[] getSymmAlgParams() {
-        return mSymmAlgParams;
-    }
-
-    public byte[] getEncSymmKey() {
-        return mEncSymmKey;
-    }
-
-    public byte[] getEncValue() {
-        return mEncValue;
-    }
-}
diff --git a/pki/base/kra/src/com/netscape/kra/KRAService.java b/pki/base/kra/src/com/netscape/kra/KRAService.java
index 916ebe3..1a351e0 100644
--- a/pki/base/kra/src/com/netscape/kra/KRAService.java
+++ b/pki/base/kra/src/com/netscape/kra/KRAService.java
@@ -46,10 +46,13 @@ public class KRAService implements IService {
     public final static String RECOVERY = IRequest.KEYRECOVERY_REQUEST;
     public final static String NETKEY_KEYGEN = IRequest.NETKEY_KEYGEN_REQUEST;
     public final static String NETKEY_KEYRECOVERY = IRequest.NETKEY_KEYRECOVERY_REQUEST;
+    public final static String SECURITY_DATA_ENROLLMENT = IRequest.SECURITY_DATA_ENROLLMENT_REQUEST;
+    public final static String SECURITY_DATA_RECOVERY = IRequest.SECURITY_DATA_RECOVERY_REQUEST;
+
 
     // private variables
     private IKeyRecoveryAuthority mKRA = null;
-    private Hashtable mServices = new Hashtable();
+    private Hashtable<String,IService> mServices = new Hashtable<String,IService>();
 
     /**
      * Constructs KRA service.
@@ -60,6 +63,8 @@ public class KRAService implements IService {
         mServices.put(RECOVERY, new RecoveryService(kra));
         mServices.put(NETKEY_KEYGEN, new NetkeyKeygenService(kra));
         mServices.put(NETKEY_KEYRECOVERY, new TokenKeyRecoveryService(kra));
+        mServices.put(SECURITY_DATA_ENROLLMENT, new SecurityDataService(kra));
+        mServices.put(SECURITY_DATA_RECOVERY, new SecurityDataRecoveryService(kra));
     }
 
     /**
diff --git a/pki/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java b/pki/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
new file mode 100644
index 0000000..4989cdc
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
@@ -0,0 +1,395 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.io.ByteArrayOutputStream;
+import java.io.CharConversionException;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+import java.util.Random;
+
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.crypto.Cipher;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.KeyGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.PBEAlgorithm;
+import org.mozilla.jss.crypto.PBEKeyGenParams;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.pkcs12.PasswordConverter;
+import org.mozilla.jss.pkcs7.ContentInfo;
+import org.mozilla.jss.pkcs7.EncryptedContentInfo;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+import org.mozilla.jss.pkix.primitive.PBEParameter;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.certsrv.kra.EKRAException;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.certsrv.security.ITransportKeyUnit;
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.dbs.keydb.IKeyRecord;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.cms.servlet.request.KeyRequestResource;
+import com.netscape.cmscore.dbs.KeyRecord;
+
+/**
+ * This interface defines how requests are serviced.
+ * This covers certificate generation, revocation, renewals,
+ * revocation checking, and much more.
+ * <p>
+ * 
+ * @version $Revision$, $Date$
+ */
+@SuppressWarnings("deprecation")
+public class SecurityDataRecoveryService implements IService {
+
+    private IKeyRecoveryAuthority mKRA = null;
+
+    private IKeyRepository mStorage = null;
+    private IStorageKeyUnit mStorageUnit = null;
+    private ITransportKeyUnit mTransportUnit = null;
+
+    public static final String ATTR_SERIALNO = "serialNumber";
+    public static final String ATTR_SESS_WRAPPED_DATA = "sessWrappedSecData";
+    public static final String ATTR_PASS_WRAPPED_DATA = "passPhraseWrappedData";
+    public static final String ATTR_KEY_RECORD = "keyRecord";
+
+    public SecurityDataRecoveryService(IKeyRecoveryAuthority kra) {
+        mKRA = kra;
+        mStorage = mKRA.getKeyRepository();
+        mStorageUnit = mKRA.getStorageKeyUnit();
+        mTransportUnit = mKRA.getTransportKeyUnit();
+
+    }
+
+    /**
+     * Performs the service (such as certificate generation)
+     * represented by this request.
+     * <p>
+     * 
+     * @param request
+     *            The request that needs service. The service may use
+     *            attributes stored in the request, and may update the
+     *            values, or store new ones.
+     * @return
+     *         an indication of whether this request is still pending.
+     *         'false' means the request will wait for further notification.
+     * @exception EBaseException indicates major processing failure.
+     */
+    public boolean serviceRequest(IRequest request)
+            throws EBaseException {
+
+        //Pave the way for allowing generated IV vector
+        byte iv[]= null;
+        byte iv_default[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+        byte iv_in[] = null;
+        
+        Hashtable<String, Object> params = mKRA.getVolatileRequest(
+                request.getRequestId());
+
+        if (params == null) {
+            CMS.debug("Can't get volatile params.");
+            throw new EBaseException("Can't obtain volatile params!");
+        }
+        
+        BigInteger serialno = request.getExtDataInBigInteger(ATTR_SERIALNO);
+
+        request.setExtData(ATTR_KEY_RECORD, serialno);
+
+        byte[] wrappedPassPhrase = null;
+        byte[] wrappedSessKey = null;
+
+        String transWrappedSessKeyStr = (String) params.get(IRequest.SECURITY_DATA_TRANS_SESS_KEY);
+        if (transWrappedSessKeyStr != null) {
+            wrappedSessKey = com.netscape.osutil.OSUtil.AtoB(transWrappedSessKeyStr);
+        }
+
+        String transWrappedPassPhraseStr = (String) params.get(RecoveryService.ATTR_TRANSPORT_PWD);
+        if (transWrappedPassPhraseStr != null) {
+            wrappedPassPhrase = com.netscape.osutil.OSUtil.AtoB(transWrappedPassPhraseStr);
+        }
+        
+        String ivInStr = (String) params.get(IRequest.SECURITY_DATA_IV_STRING_IN);
+        if (ivInStr != null) {
+            iv_in = com.netscape.osutil.OSUtil.AtoB(ivInStr);
+        }
+        
+        if (transWrappedSessKeyStr == null && transWrappedPassPhraseStr == null) {
+            //We may be in recovery case where no params were initially submitted.
+            return false;
+        }
+
+        if (transWrappedPassPhraseStr != null && transWrappedSessKeyStr == null) {
+            throw new EBaseException("Must have trans session data if have wrapped passphrase!");
+        }
+        
+      //Create the return IV if needed.
+        iv = new byte[8];
+        Random rnd = new Random();
+        
+        try {
+            rnd.nextBytes(iv);
+        } catch (Exception e) {
+            iv = null;
+        }
+        
+        if ( iv == null) {
+            iv = iv_default.clone();
+        }
+        
+        String ivStr = com.netscape.osutil.OSUtil.BtoA(iv);
+
+        KeyRecord keyRecord = (KeyRecord) mStorage.readKeyRecord(serialno);
+
+        SymmetricKey unwrappedSess = null;
+
+        String dataType = (String) keyRecord.get(IKeyRecord.ATTR_DATA_TYPE);
+        SymmetricKey symKey = null;
+        byte[] unwrappedSecData = null;
+        if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+            symKey = recoverSymKey(keyRecord);
+        } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+            unwrappedSecData = recoverSecurityData(keyRecord);
+        }
+
+        CryptoToken ct = mTransportUnit.getToken();
+
+        byte[] key_data = null;
+        String pbeWrappedData = null;
+
+        if (transWrappedPassPhraseStr != null) { //We have a trans wrapped pass phrase, we will be doing PBE packaging
+            byte[] unwrappedPass = null;
+            Password pass = null;
+            
+            try {
+                unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.DECRYPT);
+                Cipher decryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
+                decryptor.initDecrypt(unwrappedSess, new IVParameterSpec(iv_in));
+                unwrappedPass = decryptor.doFinal(wrappedPassPhrase);
+                String passStr = new String(unwrappedPass, "UTF-8");
+
+                pass = new Password(passStr.toCharArray());
+                passStr = null;
+
+                if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+                    pbeWrappedData = createEncryptedContentInfo(ct, symKey, null,
+                            pass);
+                } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+                    pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData,
+                            pass);
+                }
+
+                params.put(ATTR_PASS_WRAPPED_DATA, pbeWrappedData);
+
+            } catch (Exception e) {
+                throw new EBaseException("Can't unwrap pass phase! " + e.toString());
+            } finally {
+                if ( pass != null) {
+                    pass.clear();
+                }
+                
+                if ( unwrappedPass != null) {
+                    java.util.Arrays.fill(unwrappedPass, (byte) 0);
+                }
+            }
+
+        } else { // No trans wrapped pass phrase, return session wrapped data.
+            if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+                //wrap the key with session key
+                try {
+                    unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.WRAP);
+                    KeyWrapper wrapper = ct.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+                    wrapper.initWrap(unwrappedSess, new IVParameterSpec(iv));
+                    key_data = wrapper.wrap(symKey);
+                } catch (Exception e) {
+                    throw new EBaseException("Can't wrap symmetric key! " + e.toString());
+                }
+
+            } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+                try {
+                    unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.ENCRYPT);
+                    Cipher encryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
+                    if (encryptor != null) {
+                        encryptor.initEncrypt(unwrappedSess, new IVParameterSpec(iv));
+                        key_data = encryptor.doFinal(unwrappedSecData);
+                    } else {
+                        throw new IOException("Failed to create cipher");
+                    }
+                } catch (Exception e) {
+                    throw new EBaseException("Can't wrap pass phrase!");
+                }
+            }
+            
+            String wrappedKeyData = com.netscape.osutil.OSUtil.BtoA(key_data);
+            params.put(ATTR_SESS_WRAPPED_DATA, wrappedKeyData);
+            params.put(IRequest.SECURITY_DATA_IV_STRING_OUT, ivStr);
+            
+        }
+        return false;
+    }
+
+    public SymmetricKey recoverSymKey(KeyRecord keyRecord)
+            throws EBaseException {
+
+        try {
+            SymmetricKey symKey =
+                    mStorageUnit.unwrap(
+                            keyRecord.getPrivateKeyData());
+
+            if (symKey == null) {
+                throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+                        "symmetric key unwrapping failure"));
+            }
+
+            return symKey;
+        } catch (Exception e) {
+
+            throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+                    "recoverSymKey() " + e.toString()));
+        }
+    }
+
+    public byte[] recoverSecurityData(KeyRecord keyRecord)
+            throws EBaseException {
+
+        byte[] decodedData = null;
+
+        try {
+            decodedData = mStorageUnit.decryptInternalPrivate(
+                    keyRecord.getPrivateKeyData());
+
+            if (decodedData == null) {
+                throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+                        "security data unwrapping failure"));
+            }
+
+            return decodedData;
+        } catch (Exception e) {
+
+            throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1",
+                    "recoverSecurityData() " + e.toString()));
+        }
+    }
+
+    //ToDo: This might fit in JSS.
+    private static EncryptedContentInfo
+            createEncryptedContentInfoPBEOfSymmKey(PBEAlgorithm keyGenAlg, Password password, byte[] salt,
+                    int iterationCount,
+                    KeyGenerator.CharToByteConverter charToByteConverter,
+                    SymmetricKey symKey, CryptoToken token)
+                    throws CryptoManager.NotInitializedException, NoSuchAlgorithmException,
+                    InvalidKeyException, InvalidAlgorithmParameterException, TokenException,
+                    CharConversionException {
+
+        if (!(keyGenAlg instanceof PBEAlgorithm)) {
+            throw new NoSuchAlgorithmException("Key generation algorithm" +
+                    " is not a PBE algorithm");
+        }
+        PBEAlgorithm pbeAlg = (PBEAlgorithm) keyGenAlg;
+
+        KeyGenerator kg = token.getKeyGenerator(keyGenAlg);
+        PBEKeyGenParams pbekgParams = new PBEKeyGenParams(
+                password, salt, iterationCount);
+        if (charToByteConverter != null) {
+            kg.setCharToByteConverter(charToByteConverter);
+        }
+        kg.initialize(pbekgParams);
+        SymmetricKey key = kg.generate();
+
+        EncryptionAlgorithm encAlg = pbeAlg.getEncryptionAlg();
+        AlgorithmParameterSpec params = null;
+        if (encAlg.getParameterClass().equals(IVParameterSpec.class)) {
+            params = new IVParameterSpec(kg.generatePBE_IV());
+        } else if (encAlg.getParameterClass().equals(
+                RC2ParameterSpec.class)) {
+            params = new RC2ParameterSpec(key.getStrength(),
+                                kg.generatePBE_IV());
+        }
+
+        KeyWrapper wrapper = token.getKeyWrapper(
+                KeyWrapAlgorithm.DES3_CBC_PAD);
+        wrapper.initWrap(key, params);
+        byte encrypted[] = wrapper.wrap(symKey);
+
+        PBEParameter pbeParam = new PBEParameter(salt, iterationCount);
+        AlgorithmIdentifier encAlgID = new AlgorithmIdentifier(
+                keyGenAlg.toOID(), pbeParam);
+
+        EncryptedContentInfo encCI = new EncryptedContentInfo(
+                ContentInfo.DATA,
+                encAlgID,
+                new OCTET_STRING(encrypted));
+
+        return encCI;
+
+    }
+
+    private static String createEncryptedContentInfo(CryptoToken ct, SymmetricKey symKey, byte[] securityData,
+            Password password)
+            throws EBaseException {
+
+        EncryptedContentInfo cInfo = null;
+        String retData = null;
+        PBEAlgorithm keyGenAlg = PBEAlgorithm.PBE_SHA1_DES3_CBC;
+
+        byte[] encoded = null;
+        try {
+            PasswordConverter passConverter = new
+                    PasswordConverter();
+            byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
+            if (symKey != null) {
+
+                cInfo = createEncryptedContentInfoPBEOfSymmKey(keyGenAlg, password, salt,
+                        1,
+                        passConverter,
+                        symKey, ct);
+
+            } else if (securityData != null) {
+
+                cInfo = EncryptedContentInfo.createPBE(keyGenAlg, password, salt, 1, passConverter, securityData);
+            }
+
+            ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+            cInfo.encode(oStream);
+            encoded = oStream.toByteArray();
+            retData = com.netscape.osutil.OSUtil.BtoA(encoded);
+
+        } catch (Exception e) {
+            throw new EBaseException("Can't create a PBE wrapped EncryptedContentInfo! " + e.toString());
+        }
+
+        return retData;
+    }
+
+}
diff --git a/pki/base/kra/src/com/netscape/kra/SecurityDataService.java b/pki/base/kra/src/com/netscape/kra/SecurityDataService.java
new file mode 100644
index 0000000..bef9537
--- /dev/null
+++ b/pki/base/kra/src/com/netscape/kra/SecurityDataService.java
@@ -0,0 +1,163 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.kra;
+
+import java.math.BigInteger;
+import org.mozilla.jss.crypto.SymmetricKey;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.profile.IEnrollProfile;
+import com.netscape.certsrv.request.IService;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.security.IStorageKeyUnit;
+import com.netscape.certsrv.security.ITransportKeyUnit;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.dbs.keydb.IKeyRecord;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.cms.servlet.request.KeyRequestResource;
+import com.netscape.cmscore.dbs.KeyRecord;
+
+/**
+ * This interface defines how requests are serviced.
+ * This covers certificate generation, revocation, renewals,
+ * revocation checking, and much more.
+ * <p>
+ * 
+ * @version $Revision$, $Date$
+ */
+public class SecurityDataService implements IService {
+
+    private final static String DEFAULT_OWNER = "IPA Agent";
+    public final static String ATTR_KEY_RECORD = "keyRecord";
+    private final static String STATUS_ACTIVE = "active";
+
+    private IKeyRecoveryAuthority mKRA = null;
+    private ITransportKeyUnit mTransportUnit = null;
+    private IStorageKeyUnit mStorageUnit = null;
+
+    public SecurityDataService(IKeyRecoveryAuthority kra) {
+        mKRA = kra;
+        mTransportUnit = kra.getTransportKeyUnit();
+        mStorageUnit = kra.getStorageKeyUnit();
+    }
+
+    /**
+     * Performs the service (such as certificate generation)
+     * represented by this request.
+     * <p>
+     * 
+     * @param request
+     *            The request that needs service. The service may use
+     *            attributes stored in the request, and may update the
+     *            values, or store new ones.
+     * @return
+     *         an indication of whether this request is still pending.
+     *         'false' means the request will wait for further notification.
+     * @exception EBaseException indicates major processing failure.
+     */
+    public boolean serviceRequest(IRequest request)
+            throws EBaseException {
+        String id = request.getRequestId().toString();
+        String clientId = request.getExtDataInString(IRequest.SECURITY_DATA_CLIENT_ID);
+        String wrappedSecurityData = request.getExtDataInString(IEnrollProfile.REQUEST_ARCHIVE_OPTIONS);
+        String dataType = request.getExtDataInString(IRequest.SECURITY_DATA_TYPE);
+
+        CMS.debug("SecurityDataService.serviceRequest. Request id: " + id);
+        CMS.debug("SecurityDataService.serviceRequest wrappedSecurityData: " + wrappedSecurityData);
+
+        String owner = getOwnerName(request);
+
+        //We need some info from the PKIArchiveOptions wrapped security data
+
+        byte[] encoded = com.netscape.osutil.OSUtil.AtoB(wrappedSecurityData);
+
+        ArchiveOptions options = ArchiveOptions.toArchiveOptions(encoded);
+
+        String algStr = options.getSymmAlgOID();
+        
+        SymmetricKey securitySymKey = null;
+        byte[] securityData = null;
+
+        String keyType = null;
+        if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+            // Symmetric Key
+            keyType = KeyRequestResource.SYMMETRIC_KEY_TYPE;
+            securitySymKey = mTransportUnit.unwrap_symmetric(options.getEncSymmKey(),
+                      options.getSymmAlgOID(),
+                      options.getSymmAlgParams(),
+                      options.getEncValue());
+
+        } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+            keyType = KeyRequestResource.PASS_PHRASE_TYPE;
+            securityData = mTransportUnit.decryptExternalPrivate(options.getEncSymmKey(),
+                      options.getSymmAlgOID(),
+                      options.getSymmAlgParams(),
+                      options.getEncValue());
+
+        }
+
+        byte[] publicKey = null;
+        byte privateSecurityData[] = null;
+
+        if (securitySymKey != null) {
+            privateSecurityData = mStorageUnit.wrap(securitySymKey);
+        } else if (securityData != null) {
+            privateSecurityData = mStorageUnit.encryptInternalPrivate(securityData);
+        } else { // We have no data.
+            throw new EBaseException("Failed to create security data to archive!");
+        }
+        // create key record
+        KeyRecord rec = new KeyRecord(null, publicKey,
+                privateSecurityData, owner,
+                algStr, owner);
+
+        rec.set(IKeyRecord.ATTR_CLIENT_ID, clientId);
+
+        //Now we need a serial number for our new key.
+
+        if (rec.getSerialNumber() != null) {
+            throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"));
+        }
+
+        IKeyRepository storage = mKRA.getKeyRepository();
+        BigInteger serialNo = storage.getNextSerialNumber();
+
+        if (serialNo == null) {
+            mKRA.log(ILogger.LL_FAILURE,
+                    CMS.getLogMessage("CMSCORE_KRA_GET_NEXT_SERIAL"));
+            throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"));
+        }
+
+        rec.set(KeyRecord.ATTR_ID, serialNo);
+        rec.set(KeyRecord.ATTR_DATA_TYPE, keyType);
+        rec.set(KeyRecord.ATTR_STATUS, STATUS_ACTIVE);
+        request.setExtData(ATTR_KEY_RECORD, serialNo);
+
+        CMS.debug("KRA adding Security Data key record " + serialNo);
+
+        storage.addKeyRecord(rec);
+
+        return true;
+
+    }
+    
+    private String getOwnerName(IRequest request) {
+        return DEFAULT_OWNER;
+    }
+}
\ No newline at end of file
diff --git a/pki/base/ocsp/shared/conf/schema.ldif b/pki/base/ocsp/shared/conf/schema.ldif
index caf71e9..70578e2 100644
--- a/pki/base/ocsp/shared/conf/schema.ldif
+++ b/pki/base/ocsp/shared/conf/schema.ldif
@@ -161,6 +161,21 @@ attributeTypes: ( keySize-oid NAME 'keySize' DESC 'CMS defined attribute' SYNTAX
 dn: cn=schema
 changetype: modify
 add: attributeTypes
+attributeTypes: ( clientId-oid NAME 'clientId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dataType-oid NAME 'dataType' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( status-oid NAME 'status' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
 attributeTypes: ( keyState-oid NAME 'keyState' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
 
 dn: cn=schema
@@ -446,7 +461,7 @@ objectClasses: ( userDetails-oid NAME 'userDetails' DESC 'CMS defined class' SUP
 dn: cn=schema
 changetype: modify
 add: objectClasses
-objectClasses: ( keyRecord-oid NAME 'keyRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ keyState $ privateKeyData $ ownerName $ keySize $ metaInfo $ dateOfArchival $ dateOfRecovery $ algorithm $ publicKeyFormat $ publicKeyData $ archivedBy ) X-ORIGIN 'user defined' )
+objectClasses: ( keyRecord-oid NAME 'keyRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ keyState $ privateKeyData $ ownerName $ keySize $ metaInfo $ dateOfArchival $ dateOfRecovery $ algorithm $ publicKeyFormat $ publicKeyData $ archivedBy $ clientId $ dataType $ status ) X-ORIGIN 'user defined' )
 
 dn: cn=schema
 changetype: modify
diff --git a/pki/base/tks/shared/conf/schema.ldif b/pki/base/tks/shared/conf/schema.ldif
index caf71e9..70578e2 100644
--- a/pki/base/tks/shared/conf/schema.ldif
+++ b/pki/base/tks/shared/conf/schema.ldif
@@ -161,6 +161,21 @@ attributeTypes: ( keySize-oid NAME 'keySize' DESC 'CMS defined attribute' SYNTAX
 dn: cn=schema
 changetype: modify
 add: attributeTypes
+attributeTypes: ( clientId-oid NAME 'clientId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( dataType-oid NAME 'dataType' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( status-oid NAME 'status' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
 attributeTypes: ( keyState-oid NAME 'keyState' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
 
 dn: cn=schema
@@ -446,7 +461,7 @@ objectClasses: ( userDetails-oid NAME 'userDetails' DESC 'CMS defined class' SUP
 dn: cn=schema
 changetype: modify
 add: objectClasses
-objectClasses: ( keyRecord-oid NAME 'keyRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ keyState $ privateKeyData $ ownerName $ keySize $ metaInfo $ dateOfArchival $ dateOfRecovery $ algorithm $ publicKeyFormat $ publicKeyData $ archivedBy ) X-ORIGIN 'user defined' )
+objectClasses: ( keyRecord-oid NAME 'keyRecord' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( serialno $ dateOfCreate $ dateOfModify $ keyState $ privateKeyData $ ownerName $ keySize $ metaInfo $ dateOfArchival $ dateOfRecovery $ algorithm $ publicKeyFormat $ publicKeyData $ archivedBy $ clientId $ dataType $ status ) X-ORIGIN 'user defined' )
 
 dn: cn=schema
 changetype: modify
-- 
1.7.7.1

