>From 9da43154ced33884395fe03cafb18d8ab23d2585 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Wed, 18 Jan 2012 23:28:11 -0500
Subject: [PATCH 11/14] New DRM proxy client and tests

Added new interfaces for each Resource, and renamed old Resource service classes.
---
 pki/.classpath                                     |    3 +
 pki/base/common/src/CMakeLists.txt                 |    7 +-
 .../servlet/admin/SystemCertificateResource.java   |   75 +----
 ....java => SystemCertificateResourceService.java} |   12 +-
 .../{CMSResource.java => CMSResourceService.java}  |    2 +-
 .../com/netscape/cms/servlet/key/KeyResource.java  |  114 +-----
 .../{KeyResource.java => KeyResourceService.java}  |   17 +-
 .../com/netscape/cms/servlet/key/KeysResource.java |   94 +----
 ...{KeysResource.java => KeysResourceService.java} |   21 +-
 .../cms/servlet/request/KeyRequestResource.java    |  141 +------
 ...esource.java => KeyRequestResourceService.java} |   38 +--
 .../cms/servlet/request/KeyRequestsResource.java   |  121 +-----
 ...source.java => KeyRequestsResourceService.java} |   30 +--
 .../netscape/cms/servlet/test/DRMRestClient.java   |  114 +++++
 .../src/com/netscape/cms/servlet/test/DRMTest.java |  437 ++++++++++++++++++++
 15 files changed, 622 insertions(+), 604 deletions(-)
 copy pki/base/common/src/com/netscape/cms/servlet/admin/{SystemCertificateResource.java => SystemCertificateResourceService.java} (88%)
 rename pki/base/common/src/com/netscape/cms/servlet/base/{CMSResource.java => CMSResourceService.java} (98%)
 copy pki/base/common/src/com/netscape/cms/servlet/key/{KeyResource.java => KeyResourceService.java} (89%)
 copy pki/base/common/src/com/netscape/cms/servlet/key/{KeysResource.java => KeysResourceService.java} (74%)
 copy pki/base/common/src/com/netscape/cms/servlet/request/{KeyRequestResource.java => KeyRequestResourceService.java} (80%)
 copy pki/base/common/src/com/netscape/cms/servlet/request/{KeyRequestsResource.java => KeyRequestsResourceService.java} (72%)
 create mode 100644 pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
 create mode 100644 pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java

diff --git a/pki/.classpath b/pki/.classpath
index 07ba2826ba16bf9d9c186de892b0a57e0514f88c..c4d60d871422aa48fd43e6ef963e1677038c9f02 100644
--- a/pki/.classpath
+++ b/pki/.classpath
@@ -13,6 +13,7 @@
 	<classpathentry excluding="**/CMakeLists.txt" kind="src" path="base/tks/src"/>
 	<classpathentry excluding="**/CMakeLists.txt" kind="src" path="base/util/src"/>
 	<classpathentry excluding="**/CMakeLists.txt" kind="src" path="base/silent/src"/>
+	<classpathentry kind="src" path="base/kra/functional/src"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="lib" path="/usr/share/java/idm-console-mcc.jar"/>
 	<classpathentry kind="lib" path="/usr/share/java/idm-console-base.jar"/>
@@ -25,5 +26,7 @@
 	<classpathentry kind="lib" path="/usr/share/java/xerces-j2.jar"/>
 	<classpathentry kind="lib" path="/usr/share/java/junit4.jar"/>
 	<classpathentry kind="lib" path="/usr/share/candlepin/lib/jaxrs-api-2.2.1.GA.jar"/>
+	<classpathentry kind="lib" path="/usr/share/candlepin/lib/resteasy-jaxrs-2.2.1.GA.jar"/>
+	<classpathentry kind="lib" path="/usr/share/java/apache-commons-cli.jar"/>
 	<classpathentry kind="output" path="build/classes"/>
 </classpath>
diff --git a/pki/base/common/src/CMakeLists.txt b/pki/base/common/src/CMakeLists.txt
index 4666a2d11e1f753b9ddbf219bb096cf8f6ee8a52..067321dac2c097f7329cf2c157c70aae88c44e63 100644
--- a/pki/base/common/src/CMakeLists.txt
+++ b/pki/base/common/src/CMakeLists.txt
@@ -538,6 +538,7 @@ set(pki-cms_java_SRCS
     com/netscape/cms/servlet/admin/RAAdminServlet.java
     com/netscape/cms/servlet/admin/AdminResources.java
     com/netscape/cms/servlet/admin/SystemCertificateResource.java
+    com/netscape/cms/servlet/admin/SystemCertificateResourceService.java
     com/netscape/cms/servlet/key/DisplayBySerial.java
     com/netscape/cms/servlet/key/SrchKey.java
     com/netscape/cms/servlet/key/DisplayTransport.java
@@ -553,7 +554,9 @@ set(pki-cms_java_SRCS
     com/netscape/cms/servlet/key/KeyRecordParser.java
     com/netscape/cms/servlet/key/DisplayBySerialForRecovery.java
     com/netscape/cms/servlet/key/KeyResource.java
+    com/netscape/cms/servlet/key/KeyResourceService.java
     com/netscape/cms/servlet/key/KeysResource.java
+    com/netscape/cms/servlet/key/KeysResourceService.java
     com/netscape/cms/servlet/key/model/KeyDAO.java
     com/netscape/cms/servlet/key/model/KeyDataInfo.java
     com/netscape/cms/servlet/key/model/KeyDataInfos.java
@@ -561,7 +564,7 @@ set(pki-cms_java_SRCS
     com/netscape/cms/servlet/base/IndexServlet.java
     com/netscape/cms/servlet/base/UserInfo.java
     com/netscape/cms/servlet/base/PortsServlet.java
-    com/netscape/cms/servlet/base/CMSResource.java
+    com/netscape/cms/servlet/base/CMSResourceService.java
     com/netscape/cms/servlet/base/CMSServlet.java
     com/netscape/cms/servlet/base/CMSStartServlet.java
     com/netscape/cms/servlet/base/ProxyServlet.java
@@ -651,7 +654,9 @@ set(pki-cms_java_SRCS
     com/netscape/cms/servlet/request/CertReqParser.java
     com/netscape/cms/servlet/request/KeyReqParser.java
     com/netscape/cms/servlet/request/KeyRequestResource.java
+    com/netscape/cms/servlet/request/KeyRequestResourceService.java
     com/netscape/cms/servlet/request/KeyRequestsResource.java
+    com/netscape/cms/servlet/request/KeyRequestsResourceService.java
     com/netscape/cms/servlet/request/model/ArchivalRequestData.java
     com/netscape/cms/servlet/request/model/KeyRequestDAO.java
     com/netscape/cms/servlet/request/model/KeyRequestInfo.java
diff --git a/pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResource.java b/pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResource.java
index b1e47ec3a618f20ed6239ce7ee86dc3759178cae..6c4c0bc5461bccc48e0ec2395d7464f79b292219 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResource.java
@@ -1,88 +1,21 @@
-// --- 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) 2012 Red Hat, Inc.
-// All rights reserved.
-// --- END COPYRIGHT BLOCK ---
-
 package com.netscape.cms.servlet.admin;
 
-import java.security.cert.CertificateEncodingException;
-
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Request;
 import javax.ws.rs.core.Response;
 
-import com.netscape.certsrv.apps.CMS;
-import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
-import com.netscape.certsrv.security.ITransportKeyUnit;
-import com.netscape.cms.servlet.base.CMSResource;
-import com.netscape.cms.servlet.cert.model.CertificateData;
-
-/**
- * This is the class used to list, retrieve and modify system certificates for all Java subsystems.
- * 
- * @author alee
- * 
- */
 @Path("/config/cert")
-public class SystemCertificateResource extends CMSResource {
-
-    @Context
-    Request request;
+public interface SystemCertificateResource {
 
     /**
      * Used to retrieve the transport certificate
      */
     @GET
     @Path("/transport")
+    //@ClientResponseType(CertificateData.class)
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
-    public Response getTransportCert() {
-        CertificateData cert = null;
-        IKeyRecoveryAuthority kra = null;
+    public Response getTransportCert();
 
-        // auth and authz
-
-        kra = (IKeyRecoveryAuthority) CMS.getSubsystem("kra");
-        if (kra == null) {
-            // no KRA
-            throw new WebApplicationException(Response.Status.NOT_FOUND);
-        }
-
-        ITransportKeyUnit tu = kra.getTransportKeyUnit();
-        if (tu == null) {
-            CMS.debug("getTransportCert: transport key unit is null");
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        org.mozilla.jss.crypto.X509Certificate transportCert = tu.getCertificate();
-        if (transportCert == null) {
-            CMS.debug("getTransportCert: transport cert is null");
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        try {
-            cert = createCertificateData(transportCert);
-        } catch (CertificateEncodingException e) {
-            CMS.debug("getTransportCert: certificate encoding exception with transport cert");
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        return sendConditionalGetResponse(DEFAULT_LONG_CACHE_LIFETIME, cert, request);
-    }
-
-}
+}
\ No newline at end of file
diff --git a/pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResource.java b/pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResourceService.java
similarity index 88%
copy from pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResource.java
copy to pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResourceService.java
index b1e47ec3a618f20ed6239ce7ee86dc3759178cae..48f410c73df5740cf3858d46b4da0bedf388a69d 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/admin/SystemCertificateResourceService.java
@@ -20,19 +20,15 @@ package com.netscape.cms.servlet.admin;
 
 import java.security.cert.CertificateEncodingException;
 
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Request;
 import javax.ws.rs.core.Response;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
 import com.netscape.certsrv.security.ITransportKeyUnit;
-import com.netscape.cms.servlet.base.CMSResource;
+import com.netscape.cms.servlet.base.CMSResourceService;
 import com.netscape.cms.servlet.cert.model.CertificateData;
 
 /**
@@ -41,8 +37,7 @@ import com.netscape.cms.servlet.cert.model.CertificateData;
  * @author alee
  * 
  */
-@Path("/config/cert")
-public class SystemCertificateResource extends CMSResource {
+public class SystemCertificateResourceService extends CMSResourceService implements SystemCertificateResource {
 
     @Context
     Request request;
@@ -50,9 +45,6 @@ public class SystemCertificateResource extends CMSResource {
     /**
      * Used to retrieve the transport certificate
      */
-    @GET
-    @Path("/transport")
-    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
     public Response getTransportCert() {
         CertificateData cert = null;
         IKeyRecoveryAuthority kra = null;
diff --git a/pki/base/common/src/com/netscape/cms/servlet/base/CMSResource.java b/pki/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java
similarity index 98%
rename from pki/base/common/src/com/netscape/cms/servlet/base/CMSResource.java
rename to pki/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java
index 48b04859bd1559596aed4268f547f696895a3777..74d847d0a42b9bc52839800c1a2aae54c832d4d5 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/base/CMSResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java
@@ -34,7 +34,7 @@ import com.netscape.cms.servlet.cert.model.CertificateData;
  * @author alee
  * 
  */
-public class CMSResource {
+public class CMSResourceService {
     protected static final String HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----";
     protected static final String TRAILER = "-----END NEW CERTIFICATE REQUEST-----";
 
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/KeyResource.java b/pki/base/common/src/com/netscape/cms/servlet/key/KeyResource.java
index 3f8e8b2cf18412215a27854ff7559b2568ef9f08..c6ddda6982afc78a9291f2868385c8f2e3924478 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/key/KeyResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/KeyResource.java
@@ -1,53 +1,18 @@
-// --- 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) 2011 Red Hat, Inc.
-// All rights reserved.
-// --- END COPYRIGHT BLOCK ---
-
 package com.netscape.cms.servlet.key;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
 
-import com.netscape.cms.servlet.base.CMSResource;
-import com.netscape.cms.servlet.key.model.KeyDAO;
 import com.netscape.cms.servlet.key.model.KeyData;
-import com.netscape.cms.servlet.request.model.KeyRequestDAO;
-import com.netscape.cms.servlet.request.model.KeyRequestInfo;
 import com.netscape.cms.servlet.request.model.RecoveryRequestData;
-import com.netscape.certsrv.request.IRequest;
-import com.netscape.certsrv.request.RequestStatus;
-import com.netscape.certsrv.base.EBaseException;
-/**
- * @author alee
- * 
- */
+
 @Path("/key")
-public class KeyResource extends CMSResource {
-    
-    @Context
-    UriInfo uriInfo;
-    
+public interface KeyResource {
+   
     /**
      * Used to retrieve a key
      * @param data
@@ -57,80 +22,11 @@ public class KeyResource extends CMSResource {
     @Path("retrieve")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    public KeyData retrieveKey(RecoveryRequestData data) {
-        // auth and authz
-        String keyId = validateRequest(data);
-        KeyDAO dao = new KeyDAO();
-        KeyData keyData;
-        try {
-            keyData = dao.getKey(keyId, data);
-        } catch (EBaseException e) {
-            // log error
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        if (keyData == null) {
-            // no key record
-            throw new WebApplicationException(Response.Status.GONE);
-        }
-        return keyData;
-    }
+    public KeyData retrieveKey(RecoveryRequestData data);
     
     // retrieval - used to test integration with a browser
     @POST
     @Path("retrieve")
     @Produces(MediaType.TEXT_XML)
-    public KeyData retrieveKey(MultivaluedMap<String, String> form) {
-        RecoveryRequestData data = new RecoveryRequestData(form);
-        return retrieveKey(data);
-    }
-    
-    private String validateRequest(RecoveryRequestData data) {
-        // confirm that at least one wrapping method exists
-        if ((data.getTransWrappedSessionKey() == null) && (data.getTransWrappedSessionKey() == null)) {
-            // log error
-            throw new WebApplicationException(Response.Status.BAD_REQUEST);
-        }
-        
-        // confirm request exists
-        String reqId = data.getRequestId();
-        if (reqId == null) {
-            // log error
-            throw new WebApplicationException(Response.Status.BAD_REQUEST);
-        }
-        KeyRequestDAO reqDAO = new KeyRequestDAO();
-        KeyRequestInfo reqInfo;
-        try {
-            reqInfo = reqDAO.getRequest(reqId, uriInfo);
-        } catch (EBaseException e1) {
-            // failed to get request
-            e1.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        if (reqInfo == null) {
-            // request not found
-            throw new WebApplicationException(Response.Status.GONE);
-        }
-        
-        //confirm request is of the right type
-        String type = reqInfo.getRequestType();
-        if (!type.equals(IRequest.SECURITY_DATA_RECOVERY_REQUEST)) {
-            // log error
-            throw new WebApplicationException(Response.Status.BAD_REQUEST);
-        }
-        
-        //confirm that agent is originator of request, else throw 401 
-        //  TO-DO
-        
-        // confirm request is in approved state
-        String status = reqInfo.getRequestStatus();
-        if (!status.equals(RequestStatus.APPROVED.toString())) {
-            // log error
-            throw new WebApplicationException(Response.Status.UNAUTHORIZED);
-        }
-        
-        String keyURL = reqInfo.getKeyURL();
-        return keyURL.substring(keyURL.lastIndexOf("/")); 
-    }
-
+    public KeyData retrieveKey(MultivaluedMap<String, String> form);
 }
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/KeyResource.java b/pki/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java
similarity index 89%
copy from pki/base/common/src/com/netscape/cms/servlet/key/KeyResource.java
copy to pki/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java
index 3f8e8b2cf18412215a27854ff7559b2568ef9f08..887820c3f138a935235b9638aee747930ec492b4 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/key/KeyResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/KeyResourceService.java
@@ -18,18 +18,13 @@
 
 package com.netscape.cms.servlet.key;
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
-import com.netscape.cms.servlet.base.CMSResource;
+import com.netscape.cms.servlet.base.CMSResourceService;
 import com.netscape.cms.servlet.key.model.KeyDAO;
 import com.netscape.cms.servlet.key.model.KeyData;
 import com.netscape.cms.servlet.request.model.KeyRequestDAO;
@@ -42,8 +37,7 @@ import com.netscape.certsrv.base.EBaseException;
  * @author alee
  * 
  */
-@Path("/key")
-public class KeyResource extends CMSResource {
+public class KeyResourceService extends CMSResourceService implements KeyResource{
     
     @Context
     UriInfo uriInfo;
@@ -53,10 +47,6 @@ public class KeyResource extends CMSResource {
      * @param data
      * @return
      */
-    @POST
-    @Path("retrieve")
-    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
-    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     public KeyData retrieveKey(RecoveryRequestData data) {
         // auth and authz
         String keyId = validateRequest(data);
@@ -77,9 +67,6 @@ public class KeyResource extends CMSResource {
     }
     
     // retrieval - used to test integration with a browser
-    @POST
-    @Path("retrieve")
-    @Produces(MediaType.TEXT_XML)
     public KeyData retrieveKey(MultivaluedMap<String, String> form) {
         RecoveryRequestData data = new RecoveryRequestData(form);
         return retrieveKey(data);
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java b/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java
index 4cf5db3f44e45a4d9fbf18e413fa854bbdf31358..35cd5ccbe45ab0b78e550c20837de6b8de0e91e1 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java
@@ -1,23 +1,3 @@
-// --- 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) 2011 Red Hat, Inc.
-// All rights reserved.
-// --- END COPYRIGHT BLOCK ---
-/**
- * 
- */
 package com.netscape.cms.servlet.key;
 
 import javax.ws.rs.DefaultValue;
@@ -25,81 +5,19 @@ import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
- 
-import com.netscape.certsrv.apps.CMS;
-import com.netscape.certsrv.base.EBaseException;
-import com.netscape.cms.servlet.base.CMSResource;
-import com.netscape.cms.servlet.key.model.KeyDAO;
 import com.netscape.cms.servlet.key.model.KeyDataInfos;
-
-/**
- * @author alee
- * 
- */
+ 
 @Path("/keys")
-public class KeysResource extends CMSResource {
-
-    private static final String DEFAULT_MAXTIME = "10";
-    private static final String DEFAULT_MAXRESULTS = "100";
-
-    @Context
-    UriInfo uriInfo;
-
-    /**
-     * Used to generate list of key infos based on the search parameters
-     */
+public interface KeysResource {
+    public static final String DEFAULT_MAXTIME = "10";
+    public static final String DEFAULT_MAXRESULTS = "100";
+    
     @GET
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
     public KeyDataInfos listKeys(@QueryParam("clientID") String clientID,
                                  @QueryParam("status") String status,
                                  @DefaultValue(DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults,
-                                 @DefaultValue(DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime) {
-        // auth and authz
-        
-        // get ldap filter
-        String filter = createSearchFilter(status, clientID);
-        CMS.debug("listKeys: filter is " + filter);
-       
-        KeyDAO dao = new KeyDAO();
-        KeyDataInfos infos;
-        try {
-            infos = dao.listKeys(filter, maxResults, maxTime, uriInfo);
-        } catch (EBaseException e) {
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        return infos;
-    }
+                                 @DefaultValue(DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime);
     
-    private String createSearchFilter(String status, String clientID) {
-        String filter = "";
-        int matches = 0;
-        
-        if ((status == null) && (clientID == null)) {
-            filter = "(serialno=*)";
-            return filter;
-        }
-        
-        if (status != null) {
-            filter += "(status=" + status + ")";
-            matches ++;
-        }
-        
-        if (clientID != null) {
-            filter += "(clientID=" + clientID + ")";
-            matches ++;
-        }
-        
-        if (matches > 1) {
-            filter = "(&" + filter + ")";
-        }
-        
-        return filter;
-    }
-
 }
diff --git a/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java b/pki/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java
similarity index 74%
copy from pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java
copy to pki/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java
index 4cf5db3f44e45a4d9fbf18e413fa854bbdf31358..b5032fa86c93c2b0fd5053df38f9f7b255748ed6 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/key/KeysResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/key/KeysResourceService.java
@@ -20,20 +20,14 @@
  */
 package com.netscape.cms.servlet.key;
 
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
  
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
-import com.netscape.cms.servlet.base.CMSResource;
+import com.netscape.cms.servlet.base.CMSResourceService;
 import com.netscape.cms.servlet.key.model.KeyDAO;
 import com.netscape.cms.servlet.key.model.KeyDataInfos;
 
@@ -41,11 +35,7 @@ import com.netscape.cms.servlet.key.model.KeyDataInfos;
  * @author alee
  * 
  */
-@Path("/keys")
-public class KeysResource extends CMSResource {
-
-    private static final String DEFAULT_MAXTIME = "10";
-    private static final String DEFAULT_MAXRESULTS = "100";
+public class KeysResourceService extends CMSResourceService implements KeysResource {
 
     @Context
     UriInfo uriInfo;
@@ -53,12 +43,7 @@ public class KeysResource extends CMSResource {
     /**
      * Used to generate list of key infos based on the search parameters
      */
-    @GET
-    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
-    public KeyDataInfos listKeys(@QueryParam("clientID") String clientID,
-                                 @QueryParam("status") String status,
-                                 @DefaultValue(DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults,
-                                 @DefaultValue(DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime) {
+    public KeyDataInfos listKeys(String clientID, String status, int maxResults, int maxTime) {                                 
         // auth and authz
         
         // get ldap filter
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 154986624ce6b1597be023e42bd64d106ac1b324..0a476c49c09d6862d9e7601f8d70a48d29dd67fa 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
@@ -1,21 +1,3 @@
-// --- 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) 2011 Red Hat, Inc.
-// All rights reserved.
-// --- END COPYRIGHT BLOCK ---
-
 package com.netscape.cms.servlet.request;
 
 import javax.ws.rs.GET;
@@ -24,146 +6,57 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.Consumes;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import com.netscape.certsrv.base.EBaseException;
-import com.netscape.cms.servlet.base.CMSResource;
 import com.netscape.cms.servlet.request.model.ArchivalRequestData;
-import com.netscape.cms.servlet.request.model.KeyRequestDAO;
 import com.netscape.cms.servlet.request.model.KeyRequestInfo;
 import com.netscape.cms.servlet.request.model.RecoveryRequestData;
- 
-/**
- * @author alee
- * 
- */
+
 @Path("/keyrequest")
-public class KeyRequestResource extends CMSResource {
+public interface KeyRequestResource {
 
-    @Context
-    UriInfo uriInfo;
-    
     /**
      * Used to retrieve key request info for a specific request
      */
     @GET
     @Path("{id}")
-    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML  })
-    public KeyRequestInfo getRequestInfo(@PathParam("id") String id) {
-        // auth and authz
-        KeyRequestDAO dao = new KeyRequestDAO();
-        KeyRequestInfo info;
-        try {
-            info = dao.getRequest(id, uriInfo);
-        } catch (EBaseException e) {
-            // log error
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        if (info == null) {
-            // request does not exist
-            throw new WebApplicationException(Response.Status.NOT_FOUND);
-        }
-        return info;
-    }
-    
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    public KeyRequestInfo getRequestInfo(@PathParam("id") String id);
+
     // Archiving - used to test integration with a browser
     @POST
     @Path("archive")
     @Produces({ MediaType.TEXT_XML })
-    public KeyRequestInfo archiveKey(MultivaluedMap<String, String> form) {
-        ArchivalRequestData data = new ArchivalRequestData(form);
-        return archiveKey(data);
-    }
+    public KeyRequestInfo archiveKey(MultivaluedMap<String, String> form);
 
     @POST
     @Path("archive")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    public KeyRequestInfo archiveKey(ArchivalRequestData data) {
-        // auth and authz
-        KeyRequestDAO dao = new KeyRequestDAO();
-        KeyRequestInfo info;
-        try {
-            info = dao.submitRequest(data, uriInfo);
-        } catch (EBaseException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        return info;
-    }
-    
+    public KeyRequestInfo archiveKey(ArchivalRequestData data);
+
     //Recovery - used to test integration with a browser
     @POST
     @Path("recover")
     @Produces({ MediaType.TEXT_XML })
-    public KeyRequestInfo recoverKey(MultivaluedMap<String, String> form) {
-        RecoveryRequestData data = new RecoveryRequestData(form);
-        return recoverKey(data);
-    }
+    public KeyRequestInfo recoverKey(MultivaluedMap<String, String> form);
 
     @POST
     @Path("recover")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    public KeyRequestInfo recoverKey(RecoveryRequestData data) {
-        // auth and authz
-        KeyRequestDAO dao = new KeyRequestDAO();
-        KeyRequestInfo info;
-        try {
-            info = dao.submitRequest(data, uriInfo);
-        } catch (EBaseException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        return info;
-    }
-    
+    public KeyRequestInfo recoverKey(RecoveryRequestData data);
+
     @POST
     @Path("approve/{id}")
-    public void approveRequest(@PathParam("id") String id) {
-        // auth and authz
-        KeyRequestDAO dao = new KeyRequestDAO();
-        try {
-            dao.approveRequest(id);
-        } catch (EBaseException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-    }
-    
+    public void approveRequest(@PathParam("id") String id);
+
     @POST
     @Path("reject/{id}")
-    public void rejectRequest(@PathParam("id") String id) {
-        // auth and authz
-        KeyRequestDAO dao = new KeyRequestDAO();
-        try {
-            dao.rejectRequest(id);
-        } catch (EBaseException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-    }
-    
+    public void rejectRequest(@PathParam("id") String id);
+
     @POST
     @Path("cancel/{id}")
-    public void cancelRequest(@PathParam("id") String id) {
-        // auth and authz
-        KeyRequestDAO dao = new KeyRequestDAO();
-        try {
-            dao.cancelRequest(id);
-        } catch (EBaseException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-    }
+    public void cancelRequest(@PathParam("id") String id);
+
 }
diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResource.java b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java
similarity index 80%
copy from pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResource.java
copy to pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java
index 154986624ce6b1597be023e42bd64d106ac1b324..da08c4d699750e3c3a1a1b3c26f6b0c49a7f2dd2 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestResourceService.java
@@ -18,20 +18,14 @@
 
 package com.netscape.cms.servlet.request;
 
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.Consumes;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import com.netscape.certsrv.base.EBaseException;
-import com.netscape.cms.servlet.base.CMSResource;
+import com.netscape.cms.servlet.base.CMSResourceService;
 import com.netscape.cms.servlet.request.model.ArchivalRequestData;
 import com.netscape.cms.servlet.request.model.KeyRequestDAO;
 import com.netscape.cms.servlet.request.model.KeyRequestInfo;
@@ -41,8 +35,7 @@ import com.netscape.cms.servlet.request.model.RecoveryRequestData;
  * @author alee
  * 
  */
-@Path("/keyrequest")
-public class KeyRequestResource extends CMSResource {
+public class KeyRequestResourceService extends CMSResourceService implements KeyRequestResource {
 
     @Context
     UriInfo uriInfo;
@@ -50,10 +43,7 @@ public class KeyRequestResource extends CMSResource {
     /**
      * Used to retrieve key request info for a specific request
      */
-    @GET
-    @Path("{id}")
-    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML  })
-    public KeyRequestInfo getRequestInfo(@PathParam("id") String id) {
+    public KeyRequestInfo getRequestInfo(String id) {
         // auth and authz
         KeyRequestDAO dao = new KeyRequestDAO();
         KeyRequestInfo info;
@@ -72,18 +62,11 @@ public class KeyRequestResource extends CMSResource {
     }
     
     // Archiving - used to test integration with a browser
-    @POST
-    @Path("archive")
-    @Produces({ MediaType.TEXT_XML })
     public KeyRequestInfo archiveKey(MultivaluedMap<String, String> form) {
         ArchivalRequestData data = new ArchivalRequestData(form);
         return archiveKey(data);
     }
 
-    @POST
-    @Path("archive")
-    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
-    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     public KeyRequestInfo archiveKey(ArchivalRequestData data) {
         // auth and authz
         KeyRequestDAO dao = new KeyRequestDAO();
@@ -99,18 +82,11 @@ public class KeyRequestResource extends CMSResource {
     }
     
     //Recovery - used to test integration with a browser
-    @POST
-    @Path("recover")
-    @Produces({ MediaType.TEXT_XML })
     public KeyRequestInfo recoverKey(MultivaluedMap<String, String> form) {
         RecoveryRequestData data = new RecoveryRequestData(form);
         return recoverKey(data);
     }
 
-    @POST
-    @Path("recover")
-    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
-    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     public KeyRequestInfo recoverKey(RecoveryRequestData data) {
         // auth and authz
         KeyRequestDAO dao = new KeyRequestDAO();
@@ -125,8 +101,6 @@ public class KeyRequestResource extends CMSResource {
         return info;
     }
     
-    @POST
-    @Path("approve/{id}")
     public void approveRequest(@PathParam("id") String id) {
         // auth and authz
         KeyRequestDAO dao = new KeyRequestDAO();
@@ -139,8 +113,6 @@ public class KeyRequestResource extends CMSResource {
         }
     }
     
-    @POST
-    @Path("reject/{id}")
     public void rejectRequest(@PathParam("id") String id) {
         // auth and authz
         KeyRequestDAO dao = new KeyRequestDAO();
@@ -152,9 +124,7 @@ public class KeyRequestResource extends CMSResource {
             throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
         }
     }
-    
-    @POST
-    @Path("cancel/{id}")
+         
     public void cancelRequest(@PathParam("id") String id) {
         // auth and authz
         KeyRequestDAO dao = new KeyRequestDAO();
diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java
index ce53053d4733f0936249d04fcdc9fe118f0a3f2a..0f8fbc78fd664ecb69d2fa407b0217fff5694227 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java
@@ -1,21 +1,3 @@
-// --- 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) 2011 Red Hat, Inc.
-// All rights reserved.
-// --- END COPYRIGHT BLOCK ---
- 
 package com.netscape.cms.servlet.request;
 
 import javax.ws.rs.DefaultValue;
@@ -23,32 +5,16 @@ import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import com.netscape.certsrv.apps.CMS;
-import com.netscape.certsrv.base.EBaseException;
-import com.netscape.cms.servlet.base.CMSResource;
-import com.netscape.cms.servlet.request.model.KeyRequestDAO;
 import com.netscape.cms.servlet.request.model.KeyRequestInfos;
- 
-/**
- * @author alee
- *
- */
+
 @Path("/keyrequests")
-public class KeyRequestsResource extends CMSResource {
+public interface KeyRequestsResource {
 
-    private static final int DEFAULT_START = 0;
-    private static final String DEFAULT_PAGESIZE = "20";
-    private static final String DEFAULT_MAXRESULTS = "100";
-    private static final String DEFAULT_MAXTIME = "10";
-
-    @Context
-    UriInfo uriInfo;
+    public static final String DEFAULT_START = "0";
+    public static final String DEFAULT_PAGESIZE = "20";
+    public static final String DEFAULT_MAXRESULTS = "100";
+    public static final String DEFAULT_MAXTIME = "10";
 
     /**
      * Used to generate list of key requests based on the search parameters
@@ -56,74 +22,11 @@ public class KeyRequestsResource extends CMSResource {
     @GET
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
     public KeyRequestInfos listRequests(@QueryParam("requestState") String requestState,
-                                        @QueryParam("requestType") String requestType,
-                                        @QueryParam("clientID") String clientID,
-                                        @QueryParam("start") String start_s,
-                                        @DefaultValue(DEFAULT_PAGESIZE) @QueryParam("pageSize") int pageSize,
-                                        @DefaultValue(DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults,
-                                        @DefaultValue(DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime) {
-        // auth and authz
-        
-        // get ldap filter
-        String filter = createSearchFilter(requestState, requestType, clientID);
-        CMS.debug("listRequests: filter is " + filter);
-       
-        
-        // get start marker
-        int start = DEFAULT_START;
-        if (start_s != null) {
-            try {
-                if (start_s.trim().startsWith("0x")) {
-                    start = Integer.parseInt(start_s.trim().substring(2), 16);
-                } else {
-                    start = Integer.parseInt(start_s.trim());
-                }
-            } catch (NumberFormatException e) {
-                CMS.debug("listRequests: NumberformatException: Invalid value for start " + start_s);
-                throw new WebApplicationException(Response.Status.NOT_FOUND);
-            }
-        }
-        
-        KeyRequestDAO reqDAO = new KeyRequestDAO();
-        KeyRequestInfos requests;
-        try {
-            requests = reqDAO.listRequests(filter, start, pageSize, maxResults, maxTime, uriInfo);
-        } catch (EBaseException e) {
-            CMS.debug("listRequests: error in obtaining request results" + e);
-            e.printStackTrace();
-            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
-        }
-        return requests;
-    }
+                                            @QueryParam("requestType") String requestType,
+                                            @QueryParam("clientID") String clientID,
+                                            @DefaultValue(DEFAULT_START) @QueryParam("start") String start_s,
+                                            @DefaultValue(DEFAULT_PAGESIZE) @QueryParam("pageSize") int pageSize,
+                                            @DefaultValue(DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults,
+                                            @DefaultValue(DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime);
 
-    private String createSearchFilter(String requestState, String requestType, String clientID) {
-        String filter = "";
-        int matches = 0;
-        
-        if ((requestState == null) && (requestType == null) && (clientID == null)) {
-            filter = "(requeststate=*)";
-            return filter;
-        }
-        
-        if (requestState != null) {
-            filter += "(requeststate=" + requestState + ")";
-            matches ++;
-        }
-        
-        if (requestType != null) {
-            filter += "(requesttype=" + requestType + ")";
-            matches ++;
-        }
-        
-        if (clientID != null) {
-            filter += "(clientID=" + clientID + ")";
-            matches ++;
-        }
-        
-        if (matches > 1) {
-            filter = "(&" + filter + ")";
-        }
-        
-        return filter;
-    }
 }
diff --git a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResourceService.java
similarity index 72%
copy from pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java
copy to pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResourceService.java
index ce53053d4733f0936249d04fcdc9fe118f0a3f2a..290868ab5574bafbcdcad6fc7d5f38d3d04085e1 100644
--- a/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResource.java
+++ b/pki/base/common/src/com/netscape/cms/servlet/request/KeyRequestsResourceService.java
@@ -18,20 +18,14 @@
  
 package com.netscape.cms.servlet.request;
 
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
-import com.netscape.cms.servlet.base.CMSResource;
+import com.netscape.cms.servlet.base.CMSResourceService;
 import com.netscape.cms.servlet.request.model.KeyRequestDAO;
 import com.netscape.cms.servlet.request.model.KeyRequestInfos;
  
@@ -39,13 +33,7 @@ import com.netscape.cms.servlet.request.model.KeyRequestInfos;
  * @author alee
  *
  */
-@Path("/keyrequests")
-public class KeyRequestsResource extends CMSResource {
-
-    private static final int DEFAULT_START = 0;
-    private static final String DEFAULT_PAGESIZE = "20";
-    private static final String DEFAULT_MAXRESULTS = "100";
-    private static final String DEFAULT_MAXTIME = "10";
+public class KeyRequestsResourceService extends CMSResourceService implements KeyRequestsResource{
 
     @Context
     UriInfo uriInfo;
@@ -53,15 +41,9 @@ public class KeyRequestsResource extends CMSResource {
     /**
      * Used to generate list of key requests based on the search parameters
      */
-    @GET
-    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
-    public KeyRequestInfos listRequests(@QueryParam("requestState") String requestState,
-                                        @QueryParam("requestType") String requestType,
-                                        @QueryParam("clientID") String clientID,
-                                        @QueryParam("start") String start_s,
-                                        @DefaultValue(DEFAULT_PAGESIZE) @QueryParam("pageSize") int pageSize,
-                                        @DefaultValue(DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults,
-                                        @DefaultValue(DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime) {
+    public KeyRequestInfos listRequests(String requestState, String requestType, String clientID,
+                                        String start_s, int pageSize, int maxResults,
+                                        int maxTime) {
         // auth and authz
         
         // get ldap filter
@@ -70,7 +52,7 @@ public class KeyRequestsResource extends CMSResource {
        
         
         // get start marker
-        int start = DEFAULT_START;
+        int start = Integer.parseInt(KeyRequestsResource.DEFAULT_START);
         if (start_s != null) {
             try {
                 if (start_s.trim().startsWith("0x")) {
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
new file mode 100644
index 0000000000000000000000000000000000000000..8447faaec9aa85c5e993c2b8aa3366a048207908
--- /dev/null
+++ b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
@@ -0,0 +1,114 @@
+package com.netscape.cms.servlet.test;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.ws.rs.core.Response;
+
+import org.jboss.resteasy.client.ProxyFactory;
+
+import com.netscape.cms.servlet.admin.SystemCertificateResource;
+import com.netscape.cms.servlet.cert.model.CertificateData;
+import com.netscape.cms.servlet.key.KeyResource;
+import com.netscape.cms.servlet.key.KeysResource;
+import com.netscape.cms.servlet.key.model.KeyData;
+import com.netscape.cms.servlet.key.model.KeyDataInfo;
+import com.netscape.cms.servlet.key.model.KeyDataInfos;
+import com.netscape.cms.servlet.request.KeyRequestResource;
+import com.netscape.cms.servlet.request.KeyRequestsResource;
+import com.netscape.cms.servlet.request.model.ArchivalRequestData;
+import com.netscape.cms.servlet.request.model.KeyRequestInfo;
+import com.netscape.cms.servlet.request.model.KeyRequestInfos;
+import com.netscape.cms.servlet.request.model.RecoveryRequestData;
+
+public class DRMRestClient {
+
+    private KeyResource keyClient;
+    private KeysResource keysClient;
+    private KeyRequestsResource keyRequestsClient;
+    private KeyRequestResource keyRequestClient;
+    private SystemCertificateResource systemCertClient;
+    
+    public DRMRestClient(String baseUri) {
+        systemCertClient = ProxyFactory.create(SystemCertificateResource.class, baseUri);
+        keyRequestsClient = ProxyFactory.create(KeyRequestsResource.class, baseUri);
+        keyRequestClient = ProxyFactory.create(KeyRequestResource.class, baseUri);
+        keysClient = ProxyFactory.create(KeysResource.class, baseUri);
+        keyClient = ProxyFactory.create(KeyResource.class, baseUri);
+    }
+    
+    public String getTransportCert() {
+        Response response = systemCertClient.getTransportCert();
+        CertificateData certData = (CertificateData) response.getEntity();
+        String transportCert = certData.getB64();
+        return transportCert;
+    }
+    
+    public Collection<KeyRequestInfo> listRequests(String requestState, String requestType) {
+        KeyRequestInfos infos = keyRequestsClient.listRequests(requestState, requestType, null, "0", 100, 100, 10);
+        Collection<KeyRequestInfo> list = infos.getRequests();
+        return list;
+    }
+    
+    public KeyRequestInfo archiveSecurityData(byte[] encoded, String clientId) {
+        // create archival request
+        ArchivalRequestData data = new ArchivalRequestData();
+        String req1 = com.netscape.osutil.OSUtil.BtoA(encoded);
+        data.setWrappedPrivateData(req1);
+        data.setClientId(clientId);
+
+        KeyRequestInfo info = keyRequestClient.archiveKey(data);
+        return info;
+    }
+    
+    public KeyDataInfo getKeyData(String clientId, String status) {
+        KeyDataInfos infos = keysClient.listKeys(clientId, status, 100, 10);
+        Collection<KeyDataInfo> list = infos.getKeyInfos();
+        Iterator<KeyDataInfo> iter = list.iterator();
+
+        while (iter.hasNext()) {
+            KeyDataInfo info = iter.next();
+            if (info != null) {
+                // return the first one
+                return info;
+            }
+        }
+        return null;
+    }
+    
+    public KeyRequestInfo requestRecovery(String keyId, byte[] rpwd, byte[] rkey) {
+        // create recovery request
+        RecoveryRequestData data = new RecoveryRequestData();
+        data.setKeyId(keyId);
+        if (rpwd != null) {
+            data.setTransWrappedPassphrase(com.netscape.osutil.OSUtil.BtoA(rpwd));
+        }
+        if (rkey != null) {
+            data.setTransWrappedSessionKey(com.netscape.osutil.OSUtil.BtoA(rkey));
+        }
+
+        KeyRequestInfo info = keyRequestClient.recoverKey(data);
+        return info;
+    }
+    
+    public void approveRecovery(String recoveryId) {
+        keyRequestClient.approveRequest(recoveryId);
+    }
+    
+    public KeyData retrieveKey(String keyId, String requestId, byte[] rpwd, byte[] rkey) { 
+        // create recovery request
+        RecoveryRequestData data = new RecoveryRequestData();
+        data.setKeyId(keyId);
+        data.setRequestId(requestId);
+        if (rkey != null) {
+            data.setTransWrappedSessionKey(com.netscape.osutil.OSUtil.BtoA(rkey));
+        } else {
+            data.setTransWrappedPassphrase(com.netscape.osutil.OSUtil.BtoA(rpwd));
+        }
+        KeyData key = keyClient.retrieveKey(data);
+        return key;
+    }
+     
+
+    
+}
\ No newline at end of file
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
new file mode 100644
index 0000000000000000000000000000000000000000..f222e54130e55f162044bf43b768b4ff600c2880
--- /dev/null
+++ b/pki/base/kra/functional/src/com/netscape/cms/servlet/test/DRMTest.java
@@ -0,0 +1,437 @@
+// --- 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) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.CharConversionException;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Iterator;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.asn1.BIT_STRING;
+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;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.KeyGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.crypto.X509Certificate;
+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;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+import com.netscape.cms.servlet.key.model.KeyData;
+import com.netscape.cms.servlet.key.model.KeyDataInfo;
+import com.netscape.cms.servlet.request.model.KeyRequestInfo;
+
+@SuppressWarnings("deprecation")
+public class DRMTest {
+
+    public static void usage(Options options) {
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printHelp("DRMTest", options);
+        System.exit(1);
+    }
+
+    public static void main(String args[]) {
+        String host = null;
+        String port = null;
+        String token_pwd = null;
+
+        // parse command line arguments
+        Options options = new Options();
+        options.addOption("h", true, "Hostname of the DRM");
+        options.addOption("p", true, "Port of the DRM");
+        options.addOption("w", true, "Token password");
+
+        try {
+            CommandLineParser parser = new PosixParser();
+            CommandLine cmd = parser.parse(options, args);
+
+            if (cmd.hasOption("h")) {
+                host = cmd.getOptionValue("h");
+            } else {
+                System.err.println("Error: no hostname provided.");
+                usage(options);
+            }
+
+            if (cmd.hasOption("p")) {
+                port = cmd.getOptionValue("p");
+            } else {
+                System.err.println("Error: no port provided");
+                usage(options);
+            }
+
+            if (cmd.hasOption("w")) {
+                token_pwd = cmd.getOptionValue("w");
+            } else {
+                System.err.println("Error: no token password provided");
+                usage(options);
+            }
+
+        } catch (ParseException e) {
+            System.err.println("Error in parsing command line options: " + e.getMessage());
+            usage(options);
+        }
+
+        // Initialize token
+        String db_dir = "./";
+        try {
+            CryptoManager.initialize(db_dir);
+        } catch (AlreadyInitializedException e) {
+            // it is ok if it is already initialized 
+        } catch (Exception e) {
+            log("INITIALIZATION ERROR: " + e.toString());
+            System.exit(1);
+        }
+
+        // log into token
+        CryptoManager manager = null;
+        CryptoToken token = null;
+        try {
+            manager = CryptoManager.getInstance();
+            token = manager.getInternalKeyStorageToken();
+            Password password = new Password(token_pwd.toCharArray());
+            try {
+                token.login(password);
+            } catch (Exception e) {
+                log("login Exception: " + e.toString());
+                if (!token.isLoggedIn()) {
+                    token.initPassword(password, password);
+                }
+            }
+        } catch (Exception e) {
+            log("Exception in logging into token:" + e.toString());
+        }
+
+        // Set base URI
+        String baseUri = "http://" + host + ":" + port + "/pki";
+
+        DRMRestClient client = new DRMRestClient(baseUri);
+
+        // Test 1: Get transport certificate from DRM
+        String transportCert = client.getTransportCert();
+        log("Transport Cert retrieved from DRM: " + transportCert);
+
+        // Test 2: Get list of completed key archival requests
+        log("\n\nList of completed archival requests");
+        Collection<KeyRequestInfo> list = client.listRequests("complete", "enrolment");
+        Iterator<KeyRequestInfo> iter = list.iterator();
+        while (iter.hasNext()) {
+            KeyRequestInfo info = iter.next();
+            printRequestInfo(info);
+        }
+
+        // Test 3: Get list of key recovery requests
+        log("\n\nList of completed recovery requests");
+        Collection<KeyRequestInfo> list2 = client.listRequests("complete", "recovery");
+        Iterator<KeyRequestInfo> iter2 = list2.iterator();
+        while (iter2.hasNext()) {
+            KeyRequestInfo info = iter2.next();
+            printRequestInfo(info);
+        }
+
+        // Test 4: Generate and archive a symmetric key
+        log("Archiving symmetric key");
+        SymmetricKey vek = null;
+        String keyId = null;
+        KeyGenerator kg1 = null;
+        String clientId = "UUID: 123-45-6789 VEK " + Calendar.getInstance().getTime().toString();
+        try {
+            kg1 = token.getKeyGenerator(KeyGenAlgorithm.DES3);
+            vek = kg1.generate();
+            byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, vek, null, kg1);
+
+            KeyRequestInfo info = client.archiveSecurityData(encoded, clientId);
+            log("Archival Results:");
+            printRequestInfo(info);
+            keyId = getId(info.getKeyURL());
+        } catch (Exception e) {
+            log("Exception in archiving symmetric key:" + e.getMessage());
+            e.printStackTrace();
+        }
+
+        //Test 5: Get keyId for active key with client ID
+        log("Getting key ID for symmetric key");
+        KeyDataInfo keyInfo = client.getKeyData(clientId, "active");
+        String keyId2 = getId(keyInfo.getKeyURL());
+        if (keyId2 == null) {
+            log("No archived key found");
+        } else {
+            log("Archived Key found: " + keyId);
+        }
+
+        if (!keyId.equals(keyId2)) {
+            log("Error: key ids from search and archival do not match");
+        }
+
+        // Test 6: Submit a recovery request for the symmetric key using a session key
+        log("Submitting a recovery request for the  symmetric key using session key");
+        SymmetricKey recoveryKey = null;
+        String recoveryRequestId = null;
+        byte[] wrappedRecoveryKey = null;
+        try {
+            recoveryKey = kg1.generate();
+            wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+            KeyRequestInfo info = client.requestRecovery(keyId, null, wrappedRecoveryKey);
+            recoveryRequestId = getId(info.getRequestURL());
+        } catch (Exception e) {
+            log("Exception in recovering symmetric key using session key: " + e.getMessage());
+        }
+
+        // Test 7: Approve recovery
+        log("Approving recovery request: " + recoveryRequestId);
+        client.approveRecovery(recoveryRequestId);
+
+        // Test 8: Get key
+        log("Getting key: " + keyId);
+
+        KeyData keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey);
+        String recoveredWrappedKey = keyData.getWrappedPrivateData();
+        String recoveredKey = unwrap(recoveredWrappedKey, recoveryKey);
+
+        if (!recoveredKey.equals(com.netscape.osutil.OSUtil.BtoA(vek.getEncoded()))) {
+            log("Error: recovered and archived keys do not match!");
+        }
+
+        // Test 9: Submit a recovery request for the symmetric key using a passphrase
+        log("Submitting a recovery request for the  symmetric key using session key");
+        String recoveryPassphrase = "Gimme me keys please";
+        byte[] wrappedRecoveryPassphrase = wrapPassphrase(recoveryPassphrase, transportCert);
+        KeyRequestInfo info = client.requestRecovery(keyId, wrappedRecoveryPassphrase, null);
+        recoveryRequestId = getId(info.getRequestURL());
+
+        //Test 10: Approve recovery
+        log("Approving recovery request: " + recoveryRequestId);
+        client.approveRecovery(recoveryRequestId);
+
+        // Test 11: Get key
+        log("Getting key: " + keyId);
+        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, null);
+        recoveredWrappedKey = keyData.getWrappedPrivateData();
+        recoveredKey = unwrap(recoveredWrappedKey, recoveryKey);
+
+        if (!recoveredKey.equals(com.netscape.osutil.OSUtil.BtoA(vek.getEncoded()))) {
+            log("Error: recovered and archived keys do not match!");
+        }
+
+        // Test 12: Generate and archive a passphrase
+        String passphrase = "Green Eggs and Ham 123";
+        clientId = "UUID: 123-45-6789 RKEK " + Calendar.getInstance().getTime().toString();
+        try {
+            byte[] encoded = createPKIArchiveOptions(manager, token, transportCert, null, passphrase, kg1);
+            info = client.archiveSecurityData(encoded, clientId);
+            log("Archival Results:");
+            printRequestInfo(info);
+            keyId = getId(info.getKeyURL());
+        } catch (Exception e) {
+            log("Exception in archiving symmetric key:" + e.toString());
+            e.printStackTrace();
+        }
+        
+        //Test 13: Get keyId for active passphrase with client ID
+        log("Getting key ID for passphrase");
+        keyInfo = client.getKeyData(clientId, "active");
+        keyId2 = getId(keyInfo.getKeyURL());
+        if (keyId2 == null) {
+            log("No archived key found");
+        } else {
+            log("Archived Key found: " + keyId);
+        }
+
+        if (!keyId.equals(keyId2)) {
+            log("Error: key ids from search and archival do not match");
+        }
+        
+        // Test 14: Submit a recovery request for the passphrase using a session key
+        log("Submitting a recovery request for the passphrase using session key");
+        recoveryKey = null;
+        recoveryRequestId = null;
+        wrappedRecoveryKey = null;
+        try {
+            recoveryKey = kg1.generate();
+            wrappedRecoveryKey = wrapSymmetricKey(manager, token, transportCert, recoveryKey);
+            info = client.requestRecovery(keyId, null, wrappedRecoveryKey);
+            recoveryRequestId = getId(info.getRequestURL());
+        } catch (Exception e) {
+            log("Exception in recovering passphrase using session key: " + e.getMessage());
+        }
+        
+        // Test 15: Approve recovery
+        log("Approving recovery request: " + recoveryRequestId);
+        client.approveRecovery(recoveryRequestId);
+
+        // Test 16: Get key
+        log("Getting passphrase: " + keyId);
+
+        keyData = client.retrieveKey(keyId, recoveryRequestId, null, wrappedRecoveryKey);
+        recoveredWrappedKey = keyData.getWrappedPrivateData();
+        recoveredKey = unwrap(recoveredWrappedKey, recoveryKey);
+
+        if (!unwrap(recoveredKey).equals(passphrase)) {
+            log("Error: recovered and archived passphrases do not match!");
+        }
+         
+        // Test 17: Submit a recovery request for the passphrase using a passphrase
+        log("Submitting a recovery request for the passphrase using a passphrase");
+        info = client.requestRecovery(keyId, wrappedRecoveryPassphrase, null);
+        recoveryRequestId = getId(info.getRequestURL());
+
+        //Test 18: Approve recovery
+        log("Approving recovery request: " + recoveryRequestId);
+        client.approveRecovery(recoveryRequestId);
+
+        // Test 19: Get key
+        log("Getting passphrase: " + keyId);
+        keyData = client.retrieveKey(keyId, recoveryRequestId, wrappedRecoveryPassphrase, null);
+        recoveredWrappedKey = keyData.getWrappedPrivateData();
+        recoveredKey = unwrap(recoveredWrappedKey, recoveryKey);
+
+        if (!unwrap(recoveredKey).equals(passphrase)) {
+            log("Error: recovered and archived passphrases do not match!");
+        }
+        
+    }
+
+    private static String unwrap(String recoveredKey) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    private static byte[] wrapPassphrase(String recoveryPassphrase, String transportCert) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    private static void log(String string) {
+        // TODO Auto-generated method stub
+        System.out.println(string);
+    }
+
+    private static String unwrap(String recoveredWrappedKey, SymmetricKey recoveryKey) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    private static String getId(String link) {
+        return link.substring(link.lastIndexOf("/"));
+    }
+
+    private static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert,
+            SymmetricKey vek, String passphrase, KeyGenerator kg1) throws TokenException, CharConversionException,
+            NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
+            CertificateEncodingException, IOException, IllegalStateException, IllegalBlockSizeException,
+            BadPaddingException {
+        EncryptionAlgorithm encryptionAlgorithm = null;
+        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();
+
+        if (passphrase != null) {
+            Cipher cipher = null;
+            encryptionAlgorithm = EncryptionAlgorithm.DES3_CBC_PAD;
+            cipher = token.getCipherContext(encryptionAlgorithm);
+            log("cipher " + cipher);
+
+            if (cipher != null) {
+                cipher.initEncrypt(sk, IV);
+                key_data = cipher.doFinal(passphrase.getBytes());
+                log("Pass phrase mode key_data: " + key_data);
+
+                // Try to decrypt
+                cipher.initDecrypt(sk, IV);
+                byte[] decrypted = cipher.doFinal(key_data);
+                String s = new String(decrypted);
+                log("Re decrypted pass phrase " + s);
+
+            } else {
+                throw new IOException("Failed to create cipher");
+            }
+        } else {
+            // wrap payload using session key
+            KeyWrapper wrapper1 = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+            wrapper1.initWrap(sk, new IVParameterSpec(iv));
+            key_data = wrapper1.wrap(vek);
+        }
+
+        // wrap session key using transport key
+        byte[] session_data = wrapSymmetricKey(manager, token, transportCert, sk);
+
+        // create PKIArchiveOptions structure
+        AlgorithmIdentifier algS = new AlgorithmIdentifier(new OBJECT_IDENTIFIER("1.2.840.113549.3.7"),
+                new OCTET_STRING(iv));
+        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();
+        return encoded;
+    }
+
+    private static byte[] wrapSymmetricKey(CryptoManager manager, CryptoToken token, String transportCert,
+            SymmetricKey sk) throws CertificateEncodingException, TokenException, NoSuchAlgorithmException,
+            InvalidKeyException, InvalidAlgorithmParameterException {
+        byte transport[] = com.netscape.osutil.OSUtil.AtoB(transportCert);
+        X509Certificate tcert = manager.importCACertPackage(transport);
+        KeyWrapper rsaWrap = token.getKeyWrapper(KeyWrapAlgorithm.RSA);
+        rsaWrap.initWrap(tcert.getPublicKey(), null);
+        byte session_data[] = rsaWrap.wrap(sk);
+        return session_data;
+    }
+
+    private static void printRequestInfo(KeyRequestInfo info) {
+        log("KeyRequestURL: " + info.getRequestURL());
+        log("Key URL:       " + info.getKeyURL());
+        log("Status:        " + info.getRequestStatus());
+        log("Type:          " + info.getRequestType());
+    }
+
+}
-- 
1.7.6.4

