From 0a4d08d6c4d79bf8dc45db6e186398e811443d22 Mon Sep 17 00:00:00 2001
From: Endi Sukma Dewata <edewata@redhat.com>
Date: Wed, 23 May 2012 14:14:38 -0500
Subject: [PATCH] Added cert revocation REST service.

The cert revocation REST service is based on DoRevoke and DoUnrevoke servlets.
It provides an interface to manage certificate revocation.

Ticket #161
---
 .classpath                                         |    2 +-
 .../netscape/cms/servlet/test/CARestClient.java    |    2 +-
 .../src/com/netscape/cms/servlet/test/CATest.java  |   12 +-
 base/common/src/CMakeLists.txt                     |    3 +
 .../netscape/certsrv/dbs/certdb/CertIdAdapter.java |    7 +-
 .../netscape/certsrv/dbs/keydb/KeyIdAdapter.java   |    7 +-
 .../netscape/certsrv/request/RequestIdAdapter.java |    7 +-
 .../com/netscape/certsrv/user/UserCertData.java    |   15 +-
 .../CertIdAdapter.java => util/DateAdapter.java}   |   21 +-
 .../netscape/cms/client/user/UserAddCertCLI.java   |    2 +-
 .../src/com/netscape/cms/client/user/UserCLI.java  |   26 +-
 .../netscape/cms/client/user/UserFindCertCLI.java  |    2 +-
 .../netscape/cms/client/user/UserShowCertCLI.java  |    8 +-
 .../cms/servlet/admin/UserCertResourceService.java |    5 +-
 .../cms/servlet/base/CMSResourceService.java       |    4 +-
 .../netscape/cms/servlet/cert/CertResource.java    |   17 +-
 .../cms/servlet/cert/CertResourceService.java      |  194 ++++++-
 .../cms/servlet/cert/CertsResourceService.java     |   15 +-
 .../com/netscape/cms/servlet/cert/DoRevoke.java    |  693 ++++----------------
 .../com/netscape/cms/servlet/cert/DoUnrevoke.java  |  331 +++-------
 .../cms/servlet/cert/RevocationProcessor.java      |  459 +++++++++++++
 .../netscape/cms/servlet/cert/model/CertDAO.java   |  134 ++---
 .../cms/servlet/cert/model/CertDataInfo.java       |  152 ++++-
 .../cms/servlet/cert/model/CertRevokeRequest.java  |  235 +++++++
 .../servlet/cert/model/CertUnrevokeRequest.java    |  124 ++++
 .../cms/servlet/cert/model/CertificateData.java    |  252 ++++++--
 .../servlet/processors/Processor.java}             |   31 +-
 .../netscape/cms/servlet/test/DRMRestClient.java   |    2 +-
 base/util/src/CMakeLists.txt                       |   10 +-
 .../src/com/netscape/cmsutil/ldap/LDAPUtil.java    |    4 +-
 .../netscape/security/x509/RevocationReason.java   |  138 ++--
 .../security/x509/RevocationReasonAdapter.java}    |   21 +-
 32 files changed, 1829 insertions(+), 1106 deletions(-)
 copy base/common/src/com/netscape/certsrv/{dbs/certdb/CertIdAdapter.java => util/DateAdapter.java} (62%)
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/RevocationProcessor.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/model/CertRevokeRequest.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/model/CertUnrevokeRequest.java
 copy base/common/src/com/netscape/{certsrv/dbs/certdb/CertIdAdapter.java => cms/servlet/processors/Processor.java} (57%)
 copy base/{common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java => util/src/netscape/security/x509/RevocationReasonAdapter.java} (60%)

diff --git a/.classpath b/.classpath
index c34b7f4c054659b6ea28e3b91d05456771ccb162..f58839361aac1305e8c0f7d022e0d8d28cdf7b92 100644
--- a/.classpath
+++ b/.classpath
@@ -27,7 +27,7 @@
 	<classpathentry kind="lib" path="/usr/share/java/jakarta-commons-httpclient.jar"/>
 	<classpathentry kind="lib" path="/usr/share/java/junit4.jar"/>
 	<classpathentry kind="lib" path="/usr/share/java/ldapjdk.jar"/>
-	<classpathentry kind="lib" path="/usr/share/java/glassfish-jaxb/jaxb-impl.jar"/>
+	<classpathentry kind="lib" path="/usr/share/java/jaxb-api.jar"/>
 	<classpathentry kind="lib" path="/usr/share/java/httpcomponents/httpclient.jar"/>
 	<classpathentry kind="lib" path="/usr/share/java/httpcomponents/httpcore.jar"/>
 	<classpathentry kind="lib" path="/usr/share/java/resteasy/jaxrs-api.jar"/>
diff --git a/base/ca/functional/src/com/netscape/cms/servlet/test/CARestClient.java b/base/ca/functional/src/com/netscape/cms/servlet/test/CARestClient.java
index 775c3d9b69b2bdbbf53c35ed9785705dfcad39a6..076d60d58c420b5429b51d53ed6d749420b93e07 100644
--- a/base/ca/functional/src/com/netscape/cms/servlet/test/CARestClient.java
+++ b/base/ca/functional/src/com/netscape/cms/servlet/test/CARestClient.java
@@ -100,7 +100,7 @@ public class CARestClient extends CMSRestClient {
             return null;
         }
 
-        return certClient.retrieveCert(id);
+        return certClient.getCert(id);
 
     }
 
diff --git a/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java b/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java
index c3d55527ca030dc14049a5f1bed683690d20cd58..00559dd3f324401f2d1a37d1574021b835aae25d 100644
--- a/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java
+++ b/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java
@@ -404,8 +404,8 @@ public class CATest {
             log("No CertInfo: ");
             return;
         }
-        log("CertId: " + info.getCertId().toString());
-        log("CertUrl: " + info.getCertURL());
+        log("CertId: " + info.getID().toString());
+        log("CertUrl: " + info.getLink().getHref());
 
     }
 
@@ -419,12 +419,12 @@ public class CATest {
         log("CertificateInfo: " + "\n");
         log("-----------------");
 
-        log("CertSerialNo:  \n" + info.getSerialNo() + "\n");
-        log("CertSubject:  \n" + info.getSubjectName() + "\n");
-        log("CertIssuer: \n" + info.getIssuerName() + "\n");
+        log("CertSerialNo:  \n" + info.getSerialNumber() + "\n");
+        log("CertSubject:  \n" + info.getSubjectDN() + "\n");
+        log("CertIssuer: \n" + info.getIssuerDN() + "\n");
         log("NotBefore:  \n" + info.getNotBefore() + "\n");
         log("NotAfter: \n" + info.getNotAfter() + "\n");
-        log("CertBase64: \n" + info.getB64() + "\n");
+        log("CertBase64: \n" + info.getEncoded() + "\n");
         log("CertPKCS7Chain: \n" + info.getPkcs7CertChain() + "\n");
         log("CertPrettyPrint: \n" + info.getPrettyPrint());
 
diff --git a/base/common/src/CMakeLists.txt b/base/common/src/CMakeLists.txt
index 7b73a8536c1c282e3491122f148cea456cbc4603..0a6fb8ad3866e2fb3c3e94dc7b14aa63ea819ce9 100644
--- a/base/common/src/CMakeLists.txt
+++ b/base/common/src/CMakeLists.txt
@@ -191,6 +191,7 @@ set(pki-certsrv_java_SRCS
     com/netscape/certsrv/publish/ERulePluginNotFound.java
     com/netscape/certsrv/publish/MapperProxy.java
     com/netscape/certsrv/publish/ILdapCrlMapper.java
+    com/netscape/certsrv/util/DateAdapter.java
     com/netscape/certsrv/util/IStatsSubsystem.java
     com/netscape/certsrv/util/HttpInput.java
     com/netscape/certsrv/util/StatsEvent.java
@@ -618,7 +619,9 @@ set(pki-cms_java_SRCS
     com/netscape/cms/servlet/cert/model/CertDAO.java
     com/netscape/cms/servlet/cert/model/CertDataInfo.java
     com/netscape/cms/servlet/cert/model/CertDataInfos.java
+    com/netscape/cms/servlet/cert/model/CertRevokeRequest.java
     com/netscape/cms/servlet/cert/model/CertSearchData.java
+    com/netscape/cms/servlet/cert/model/CertUnrevokeRequest.java
     com/netscape/cms/servlet/admin/OCSPAdminServlet.java
     com/netscape/cms/servlet/admin/CMSAdminServlet.java
     com/netscape/cms/servlet/admin/JobsAdminServlet.java
diff --git a/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java b/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
index cfafff0642a64dfce5a488940bfd0931916bc98a..f6e46cad5079df8c61d59b5d53046f001c5a962c 100644
--- a/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
+++ b/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
@@ -19,19 +19,20 @@ package com.netscape.certsrv.dbs.certdb;
 
 import javax.xml.bind.annotation.adapters.XmlAdapter;
 
+import org.apache.commons.lang.StringUtils;
+
 /**
  * The CertIdAdapter class provides custom marshaling for CertId.
  *
  * @author Endi S. Dewata
- * @version $Revision$ $Date$
  */
 public class CertIdAdapter extends XmlAdapter<String, CertId> {
 
     public CertId unmarshal(String value) throws Exception {
-        return new CertId(value);
+        return StringUtils.isEmpty(value) ? null : new CertId(value);
     }
 
     public String marshal(CertId value) throws Exception {
-        return value.toString();
+        return value == null ? null : value.toHexString();
     }
 }
diff --git a/base/common/src/com/netscape/certsrv/dbs/keydb/KeyIdAdapter.java b/base/common/src/com/netscape/certsrv/dbs/keydb/KeyIdAdapter.java
index 3232999fdc3f92693e80170b61a7d1d6d891787c..0f0c43c8238c66decdf74853b6fa41a09d589ee9 100644
--- a/base/common/src/com/netscape/certsrv/dbs/keydb/KeyIdAdapter.java
+++ b/base/common/src/com/netscape/certsrv/dbs/keydb/KeyIdAdapter.java
@@ -19,19 +19,20 @@ package com.netscape.certsrv.dbs.keydb;
 
 import javax.xml.bind.annotation.adapters.XmlAdapter;
 
+import org.apache.commons.lang.StringUtils;
+
 /**
  * The KeyIdAdapter class provides custom marshaling for KeyId.
  *
  * @author Endi S. Dewata
- * @version $Revision$ $Date$
  */
 public class KeyIdAdapter extends XmlAdapter<String, KeyId> {
 
     public KeyId unmarshal(String value) throws Exception {
-        return new KeyId(value);
+        return StringUtils.isEmpty(value) ? null : new KeyId(value);
     }
 
     public String marshal(KeyId value) throws Exception {
-        return value.toString();
+        return value == null ? null : value.toString();
     }
 }
diff --git a/base/common/src/com/netscape/certsrv/request/RequestIdAdapter.java b/base/common/src/com/netscape/certsrv/request/RequestIdAdapter.java
index 1780bc3377b55a9c2be61a5d7337b3f45dac8028..a6051fa8d3e98006d56c7bc3025e40b5330238ab 100644
--- a/base/common/src/com/netscape/certsrv/request/RequestIdAdapter.java
+++ b/base/common/src/com/netscape/certsrv/request/RequestIdAdapter.java
@@ -19,19 +19,20 @@ package com.netscape.certsrv.request;
 
 import javax.xml.bind.annotation.adapters.XmlAdapter;
 
+import org.apache.commons.lang.StringUtils;
+
 /**
  * The RequestIdAdapter class provides custom marshaling for RequestId.
  *
  * @author Endi S. Dewata
- * @version $Revision$ $Date$
  */
 public class RequestIdAdapter extends XmlAdapter<String, RequestId> {
 
     public RequestId unmarshal(String value) throws Exception {
-        return new RequestId(value);
+        return StringUtils.isEmpty(value) ? null : new RequestId(value);
     }
 
     public String marshal(RequestId value) throws Exception {
-        return value.toString();
+        return value == null ? null : value.toString();
     }
 }
\ No newline at end of file
diff --git a/base/common/src/com/netscape/certsrv/user/UserCertData.java b/base/common/src/com/netscape/certsrv/user/UserCertData.java
index d77e1dc8b152633be8e8c201a9f1bb677a045cd0..708d0343045867698ebf6d065cf1677564b85dd6 100644
--- a/base/common/src/com/netscape/certsrv/user/UserCertData.java
+++ b/base/common/src/com/netscape/certsrv/user/UserCertData.java
@@ -21,7 +21,6 @@ package com.netscape.certsrv.user;
 import java.io.PrintWriter;
 import java.io.StringReader;
 import java.io.StringWriter;
-import java.math.BigInteger;
 import java.util.StringTokenizer;
 
 import javax.ws.rs.FormParam;
@@ -31,10 +30,13 @@ import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.jboss.resteasy.plugins.providers.atom.Link;
 
 import com.netscape.certsrv.common.Constants;
+import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.certsrv.dbs.certdb.CertIdAdapter;
 
 /**
  * @author Endi S. Dewata
@@ -56,7 +58,7 @@ public class UserCertData {
     }
 
     Integer version;
-    BigInteger serialNumber;
+    CertId serialNumber;
     String issuerDN;
     String subjectDN;
     String prettyPrint;
@@ -76,7 +78,7 @@ public class UserCertData {
     public void setID(String id) {
         StringTokenizer st = new StringTokenizer(id, ";");
         version = Integer.valueOf(st.nextToken());
-        serialNumber = new BigInteger(st.nextToken());
+        serialNumber = new CertId(st.nextToken());
         issuerDN = st.nextToken();
         subjectDN = st.nextToken();
     }
@@ -91,11 +93,12 @@ public class UserCertData {
     }
 
     @XmlElement(name="SerialNumber")
-    public BigInteger getSerialNumber() {
+    @XmlJavaTypeAdapter(CertIdAdapter.class)
+    public CertId getSerialNumber() {
         return serialNumber;
     }
 
-    public void setSerialNumber(BigInteger serialNumber) {
+    public void setSerialNumber(CertId serialNumber) {
         this.serialNumber = serialNumber;
     }
 
@@ -240,7 +243,7 @@ public class UserCertData {
 
         UserCertData before = new UserCertData();
         before.setVersion(1);
-        before.setSerialNumber(new BigInteger("12512514865863765114"));
+        before.setSerialNumber(new CertId("12512514865863765114"));
         before.setIssuerDN("CN=Test User,UID=testuser,O=EXAMPLE-COM");
         before.setSubjectDN("CN=Test User,UID=testuser,O=EXAMPLE-COM");
         before.setEncoded(sw.toString());
diff --git a/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java b/base/common/src/com/netscape/certsrv/util/DateAdapter.java
similarity index 62%
copy from base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
copy to base/common/src/com/netscape/certsrv/util/DateAdapter.java
index cfafff0642a64dfce5a488940bfd0931916bc98a..e01f2d98a7615a8f75d5ae7c228a43aaafe615ca 100644
--- a/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
+++ b/base/common/src/com/netscape/certsrv/util/DateAdapter.java
@@ -12,26 +12,29 @@
 // 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.
+// (C) 2012 Red Hat, Inc.
 // All rights reserved.
 // --- END COPYRIGHT BLOCK ---
-package com.netscape.certsrv.dbs.certdb;
+package com.netscape.certsrv.util;
+
+import java.util.Date;
 
 import javax.xml.bind.annotation.adapters.XmlAdapter;
 
+import org.apache.commons.lang.StringUtils;
+
 /**
- * The CertIdAdapter class provides custom marshaling for CertId.
+ * The DateAdapter class provides custom marshaling for Date.
  *
  * @author Endi S. Dewata
- * @version $Revision$ $Date$
  */
-public class CertIdAdapter extends XmlAdapter<String, CertId> {
+public class DateAdapter extends XmlAdapter<String, Date> {
 
-    public CertId unmarshal(String value) throws Exception {
-        return new CertId(value);
+    public Date unmarshal(String value) throws Exception {
+        return StringUtils.isEmpty(value) ? null : new Date(Long.parseLong(value));
     }
 
-    public String marshal(CertId value) throws Exception {
-        return value.toString();
+    public String marshal(Date value) throws Exception {
+        return value == null ? null : Long.toString(value.getTime());
     }
 }
diff --git a/base/common/src/com/netscape/cms/client/user/UserAddCertCLI.java b/base/common/src/com/netscape/cms/client/user/UserAddCertCLI.java
index 2370865ad9694b6791b90b67c056414dd32cc1d2..61ca60137c18d8e69e2af5d8afb3a4cd1682855d 100644
--- a/base/common/src/com/netscape/cms/client/user/UserAddCertCLI.java
+++ b/base/common/src/com/netscape/cms/client/user/UserAddCertCLI.java
@@ -92,6 +92,6 @@ public class UserAddCertCLI extends CLI {
 
         MainCLI.printMessage("Added certificate \"" + userCertData.getID() + "\"");
 
-        UserCLI.printCert(userCertData);
+        UserCLI.printCert(userCertData, false, false);
     }
 }
diff --git a/base/common/src/com/netscape/cms/client/user/UserCLI.java b/base/common/src/com/netscape/cms/client/user/UserCLI.java
index a7bc752e14278a9b4d588968c76dc6737822de25..e9c9acd677a6052c90f87417db8c8d6c492852be 100644
--- a/base/common/src/com/netscape/cms/client/user/UserCLI.java
+++ b/base/common/src/com/netscape/cms/client/user/UserCLI.java
@@ -125,28 +125,32 @@ public class UserCLI extends CLI {
         }
     }
 
-    public static void printCert(UserCertData userCertData) throws Exception {
+    public static void printCert(
+            UserCertData userCertData,
+            boolean showPrettyPrint,
+            boolean showEncoded) {
+
         System.out.println("  Cert ID: " + userCertData.getID());
-        System.out.println("  Serial Number: " + userCertData.getSerialNumber());
         System.out.println("  Version: " + userCertData.getVersion());
-        System.out.println("  Issuer DN: " + userCertData.getIssuerDN());
-        System.out.println("  Subject DN: " + userCertData.getSubjectDN());
+        System.out.println("  Serial Number: " + userCertData.getSerialNumber().toHexString());
+        System.out.println("  Issuer: " + userCertData.getIssuerDN());
+        System.out.println("  Subject: " + userCertData.getSubjectDN());
+
+        Link link = userCertData.getLink();
+        if (verbose && link != null) {
+            System.out.println("  Link: " + link.getHref());
+        }
 
         String prettyPrint = userCertData.getPrettyPrint();
-        if (prettyPrint != null) {
+        if (showPrettyPrint && prettyPrint != null) {
             System.out.println();
             System.out.println(prettyPrint);
         }
 
         String encoded = userCertData.getEncoded();
-        if (encoded != null) {
+        if (showEncoded && encoded != null) {
             System.out.println();
             System.out.println(encoded);
         }
-
-        Link link = userCertData.getLink();
-        if (verbose && link != null) {
-            System.out.println("  Link: " + link.getHref());
-        }
     }
 }
diff --git a/base/common/src/com/netscape/cms/client/user/UserFindCertCLI.java b/base/common/src/com/netscape/cms/client/user/UserFindCertCLI.java
index 41fe3984a3c9cec5c7c08cee89db6426aae3c5b2..c06d21faf9ddd2105927f6397fa9373902986643 100644
--- a/base/common/src/com/netscape/cms/client/user/UserFindCertCLI.java
+++ b/base/common/src/com/netscape/cms/client/user/UserFindCertCLI.java
@@ -96,7 +96,7 @@ public class UserFindCertCLI extends CLI {
                 System.out.println();
             }
 
-            UserCLI.printCert(userCertData);
+            UserCLI.printCert(userCertData, false, false);
         }
 
         MainCLI.printMessage("Number of entries returned " + entries.size());
diff --git a/base/common/src/com/netscape/cms/client/user/UserShowCertCLI.java b/base/common/src/com/netscape/cms/client/user/UserShowCertCLI.java
index 7e58fb1b00638aaa3383ac18451cac634caefe7e..71e14b4fcfb0a419d4f2b4a4db58448c5808c241 100644
--- a/base/common/src/com/netscape/cms/client/user/UserShowCertCLI.java
+++ b/base/common/src/com/netscape/cms/client/user/UserShowCertCLI.java
@@ -50,6 +50,9 @@ public class UserShowCertCLI extends CLI {
         option.setArgName("file");
         options.addOption(option);
 
+        options.addOption(null, "pretty", false, "Pretty print");
+        options.addOption(null, "encoded", false, "Base-64 encoded");
+
         CommandLine cmd = null;
 
         try {
@@ -61,6 +64,9 @@ public class UserShowCertCLI extends CLI {
             System.exit(1);
         }
 
+        boolean showPrettyPrint = cmd.hasOption("pretty");
+        boolean showEncoded = cmd.hasOption("encoded");
+
         String[] cmdArgs = cmd.getArgs();
 
         if (cmdArgs.length != 2) {
@@ -82,6 +88,6 @@ public class UserShowCertCLI extends CLI {
             out.close();
         }
 
-        UserCLI.printCert(userCertData);
+        UserCLI.printCert(userCertData, showPrettyPrint, showEncoded);
     }
 }
diff --git a/base/common/src/com/netscape/cms/servlet/admin/UserCertResourceService.java b/base/common/src/com/netscape/cms/servlet/admin/UserCertResourceService.java
index ebeb5b134a462d14996c1b2fbb20ef94cdf89310..e0e2ddfde3921f35eff6df065b2e0e518c35f821 100644
--- a/base/common/src/com/netscape/cms/servlet/admin/UserCertResourceService.java
+++ b/base/common/src/com/netscape/cms/servlet/admin/UserCertResourceService.java
@@ -42,6 +42,7 @@ import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.ICertPrettyPrint;
 import com.netscape.certsrv.common.OpDef;
 import com.netscape.certsrv.common.ScopeDef;
+import com.netscape.certsrv.dbs.certdb.CertId;
 import com.netscape.certsrv.logging.IAuditor;
 import com.netscape.certsrv.logging.ILogger;
 import com.netscape.certsrv.user.UserCertCollection;
@@ -68,7 +69,7 @@ public class UserCertResourceService extends CMSResourceService implements UserC
         UserCertData userCertData = new UserCertData();
 
         userCertData.setVersion(cert.getVersion());
-        userCertData.setSerialNumber(cert.getSerialNumber());
+        userCertData.setSerialNumber(new CertId(cert.getSerialNumber()));
         userCertData.setIssuerDN(cert.getIssuerDN().toString());
         userCertData.setSubjectDN(cert.getSubjectDN().toString());
 
@@ -358,7 +359,7 @@ public class UserCertResourceService extends CMSResourceService implements UserC
                 // read the data back
 
                 userCertData.setVersion(cert.getVersion());
-                userCertData.setSerialNumber(cert.getSerialNumber());
+                userCertData.setSerialNumber(new CertId(cert.getSerialNumber()));
                 userCertData.setIssuerDN(cert.getIssuerDN().toString());
                 userCertData.setSubjectDN(cert.getSubjectDN().toString());
                 String certID = userCertData.getID();
diff --git a/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java b/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java
index 85ccbf9f7100e2e8768129b470721491ddf53713..2d95d1904839551234a306a88e26af90d32f05bf 100644
--- a/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java
+++ b/base/common/src/com/netscape/cms/servlet/base/CMSResourceService.java
@@ -90,7 +90,7 @@ public class CMSResourceService {
             throws CertificateEncodingException {
         CertificateData data = new CertificateData();
         String b64 = HEADER + CMS.BtoA(cert.getEncoded()) + TRAILER;
-        data.setB64(b64);
+        data.setEncoded(b64);
         return data;
     }
 
@@ -116,7 +116,7 @@ public class CMSResourceService {
                 null,
                 source,
                 level,
-                getClass().getSimpleName()+": " + message);
+                getClass().getSimpleName() + ": " + message);
     }
 
     public void audit(String message, String scope, String type, String id, Map<String, String> params, String status) {
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertResource.java b/base/common/src/com/netscape/cms/servlet/cert/CertResource.java
index 9df06d8e8e50c4bd99487d2c26c2df36c99a608a..8aa90c2cba8fe1f72629184a214ff1fd260fe0d1 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/CertResource.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertResource.java
@@ -1,12 +1,16 @@
 package com.netscape.cms.servlet.cert;
 
+import javax.ws.rs.Consumes;
 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.core.MediaType;
 
 import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.cms.servlet.cert.model.CertRevokeRequest;
+import com.netscape.cms.servlet.cert.model.CertUnrevokeRequest;
 import com.netscape.cms.servlet.cert.model.CertificateData;
 
 @Path("/cert")
@@ -15,6 +19,17 @@ public interface CertResource {
     @GET
     @Path("{id}")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
-    public CertificateData retrieveCert(@PathParam("id") CertId id);
+    public CertificateData getCert(@PathParam("id") CertId id);
 
+    @POST
+    @Path("{id}/revoke")
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    public CertificateData revokeCert(@PathParam("id") CertId id, CertRevokeRequest request);
+
+    @POST
+    @Path("{id}/unrevoke")
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    public CertificateData unrevokeCert(@PathParam("id") CertId id, CertUnrevokeRequest request);
 }
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertResourceService.java b/base/common/src/com/netscape/cms/servlet/cert/CertResourceService.java
index c05d61b1cb0e9641b38f8e1b94fdf2f412bbcdbd..a4ad60c60fe7c1ecdbf777ee3b2af4c5f7ef39e2 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/CertResourceService.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertResourceService.java
@@ -18,16 +18,26 @@
 
 package com.netscape.cms.servlet.cert;
 
-
+import java.io.IOException;
 import java.security.cert.CertificateEncodingException;
 
+import netscape.security.x509.RevocationReason;
+import netscape.security.x509.X509CertImpl;
+
+import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.ca.ICertificateAuthority;
 import com.netscape.certsrv.dbs.EDBRecordNotFoundException;
 import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.certsrv.dbs.certdb.ICertRecord;
+import com.netscape.certsrv.logging.AuditFormat;
+import com.netscape.certsrv.logging.ILogger;
 import com.netscape.cms.servlet.base.BadRequestException;
 import com.netscape.cms.servlet.base.CMSException;
 import com.netscape.cms.servlet.base.CMSResourceService;
 import com.netscape.cms.servlet.cert.model.CertDAO;
+import com.netscape.cms.servlet.cert.model.CertRevokeRequest;
+import com.netscape.cms.servlet.cert.model.CertUnrevokeRequest;
 import com.netscape.cms.servlet.cert.model.CertificateData;
 import com.netscape.cms.servlet.request.model.CertRetrievalRequestData;
 
@@ -35,7 +45,20 @@ import com.netscape.cms.servlet.request.model.CertRetrievalRequestData;
  * @author alee
  *
  */
-public class CertResourceService extends CMSResourceService implements CertResource{
+public class CertResourceService extends CMSResourceService implements CertResource {
+
+    ICertificateAuthority authority;
+
+    public CertResourceService() {
+        authority = (ICertificateAuthority) CMS.getSubsystem("ca");
+    }
+
+    public CertDAO createDAO() {
+        CertDAO dao = new CertDAO();
+        dao.setLocale(getLocale());
+        dao.setUriInfo(uriInfo);
+        return dao;
+    }
 
     private void validateRequest(CertId id) {
 
@@ -46,27 +69,184 @@ public class CertResourceService extends CMSResourceService implements CertResou
     }
 
     @Override
-    public CertificateData retrieveCert(CertId id) {
+    public CertificateData getCert(CertId id) {
 
         validateRequest(id);
 
         CertRetrievalRequestData data = new CertRetrievalRequestData();
         data.setCertId(id);
-        CertDAO dao = new CertDAO();
+        CertDAO dao = createDAO();
 
         CertificateData certData = null;
 
         try {
             certData = dao.getCert(data);
-        }  catch(EDBRecordNotFoundException e) {
+        } catch (EDBRecordNotFoundException e) {
             throw new CertNotFoundException(id);
-        }  catch (EBaseException e) {
+        } catch (EBaseException e) {
             throw new CMSException("Problem returning certificate: " + id);
-        }  catch(CertificateEncodingException e) {
+        } catch (CertificateEncodingException e) {
             throw new CMSException("Problem encoding certificate searched for: " + id);
         }
 
         return certData;
 
     }
+
+    @Override
+    public CertificateData revokeCert(CertId id, CertRevokeRequest request) {
+
+        RevocationProcessor processor = new RevocationProcessor();
+        processor.setStartTime(CMS.getCurrentDate().getTime());
+
+        // TODO: set initiative based on auth info
+        processor.setInitiative(AuditFormat.FROMAGENT);
+
+        processor.setSerialNumber(id);
+        processor.setRequestID(request.getRequestID());
+
+        RevocationReason revReason = request.getReason();
+        processor.setRevocationReason(revReason);
+        processor.setRequestType(revReason == RevocationReason.CERTIFICATE_HOLD
+                ? RevocationProcessor.ON_HOLD : RevocationProcessor.REVOKE);
+        processor.setInvalidityDate(request.getInvalidityDate());
+        processor.setComments(request.getComments());
+
+        processor.setAuthority(authority);
+
+        try {
+            // TODO: get user cert's serial number from auth info
+            // String userSerialNumber = null;
+
+            // TODO: get user cert's subject DN from auth info
+            // String userSubjectDN = null;
+
+            processor.createCRLExtension();
+
+            ICertRecord record = processor.getCertificateRecord(id);
+            X509CertImpl cert = record.getCertificate();
+
+            // we do not want to revoke the CA certificate accidentally
+            if (processor.isSystemCertificate(cert)) {
+                CMS.debug("revokeCert: rejected revocation request for system certificate " + cert.getSerialNumber());
+                throw new EBaseException(CMS.getLogMessage("CMSGW_UNAUTHORIZED"));
+            }
+
+            // TODO: verify user cert is not revoked
+            /*
+            if (userSerialNumber != null
+                    && userSerialNumber.equals(cert.getSerialNumber().toString())
+                    && record.getStatus().equals(ICertRecord.STATUS_REVOKED)) {
+
+                log(ILogger.LL_FAILURE,
+                        CMS.getLogMessage("CA_CERTIFICATE_ALREADY_REVOKED_1",
+                                cert.getSerialNumber().toString(16)));
+
+                throw new EBaseException(CMS.getLogMessage("CMSGW_UNAUTHORIZED"));
+            }
+            */
+
+            // verify target cert is not revoked
+            if (record.getStatus().equals(ICertRecord.STATUS_REVOKED)) {
+
+                throw new EBaseException(CMS.getLogMessage("CA_CERTIFICATE_ALREADY_REVOKED_1",
+                        cert.getSerialNumber().toString(16)));
+            }
+
+            // TODO: verify user cert's subject DN matches the target cert's subject DN
+            /*
+            if (eeSubjectDN != null && !eeSubjectDN.equals(cert.getSubjectDN().toString())) {
+
+                log(ILogger.LL_FAILURE,
+                        "Certificate 0x" + cert.getSerialNumber().toString(16) + " belongs to different subject.");
+
+                throw new EBaseException(CMS.getLogMessage("BASE_PERMISSION_DENIED"));
+            }
+            */
+
+            processor.addCertificateToRevoke(cert);
+            processor.createRevocationRequest();
+
+            processor.auditChangeRequest(ILogger.SUCCESS);
+
+        } catch (EBaseException e) {
+            log(ILogger.LL_FAILURE, "Error " + e);
+            processor.auditChangeRequest(ILogger.FAILURE);
+
+            throw new CMSException(e.getMessage());
+
+        } catch (IOException e) {
+            log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED_1", e.toString()));
+            processor.auditChangeRequest(ILogger.FAILURE);
+
+            throw new CMSException(CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED"));
+        }
+
+        // change audit processing from "REQUEST" to "REQUEST_PROCESSED"
+        // to distinguish which type of signed audit log message to save
+        // as a failure outcome in case an exception occurs
+
+        try {
+            processor.processRevocationRequest();
+
+            processor.auditChangeRequestProcessed(ILogger.SUCCESS);
+
+        } catch (EBaseException e) {
+            log(ILogger.LL_FAILURE, "Error " + e);
+            processor.auditChangeRequestProcessed(ILogger.FAILURE);
+
+            throw new CMSException(e.getMessage());
+        }
+
+        return getCert(id);
+    }
+
+    @Override
+    public CertificateData unrevokeCert(CertId id, CertUnrevokeRequest request) {
+
+        RevocationProcessor processor = new RevocationProcessor();
+
+        // TODO: set initiative based on auth info
+        processor.setInitiative(AuditFormat.FROMAGENT);
+
+        processor.setSerialNumber(id);
+        processor.setRequestID(request.getRequestID());
+        processor.setRevocationReason(RevocationReason.CERTIFICATE_HOLD);
+        processor.setAuthority(authority);
+
+        try {
+            processor.addSerialNumberToUnrevoke(id.toBigInteger());
+            processor.createUnrevocationRequest();
+
+            processor.auditChangeRequest(ILogger.SUCCESS);
+
+        } catch (EBaseException e) {
+            log(ILogger.LL_FAILURE, "Error " + e);
+            processor.auditChangeRequest(ILogger.FAILURE);
+
+            throw new CMSException(e.getMessage());
+        }
+
+        // change audit processing from "REQUEST" to "REQUEST_PROCESSED"
+        // to distinguish which type of signed audit log message to save
+        // as a failure outcome in case an exception occurs
+
+        try {
+            processor.processUnrevocationRequest();
+
+            processor.auditChangeRequestProcessed(ILogger.SUCCESS);
+
+        } catch (EBaseException e) {
+            log(ILogger.LL_FAILURE, "Error " + e);
+            processor.auditChangeRequestProcessed(ILogger.FAILURE);
+
+            throw new CMSException(e.getMessage());
+        }
+
+        return getCert(id);
+    }
+
+    public void log(int level, String message) {
+        log(ILogger.S_CA, level, message);
+    }
 }
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertsResourceService.java b/base/common/src/com/netscape/cms/servlet/cert/CertsResourceService.java
index ed503dad4939ccb778a6bf8617bdba9a56c08ced..60daee11ffc79abc4baa02393cbb104fca2bf40c 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/CertsResourceService.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertsResourceService.java
@@ -38,6 +38,13 @@ import com.netscape.cmsutil.ldap.LDAPUtil;
  */
 public class CertsResourceService extends CMSResourceService implements CertsResource {
 
+    public CertDAO createDAO() {
+        CertDAO dao = new CertDAO();
+        dao.setLocale(getLocale());
+        dao.setUriInfo(uriInfo);
+        return dao;
+    }
+
     private String createSearchFilter(String status) {
         String filter = "";
 
@@ -70,10 +77,10 @@ public class CertsResourceService extends CMSResourceService implements CertsRes
         String filter = createSearchFilter(status);
         CMS.debug("listKeys: filter is " + filter);
 
-        CertDAO dao = new CertDAO();
+        CertDAO dao = createDAO();
         CertDataInfos infos;
         try {
-            infos = dao.listCerts(filter, maxResults, maxTime, uriInfo);
+            infos = dao.listCerts(filter, maxResults, maxTime);
         } catch (EBaseException e) {
             e.printStackTrace();
             throw new CMSException("Error listing certs in CertsResourceService.listCerts!");
@@ -88,11 +95,11 @@ public class CertsResourceService extends CMSResourceService implements CertsRes
             throw new WebApplicationException(Response.Status.BAD_REQUEST);
         }
         String filter = createSearchFilter(data);
-        CertDAO dao = new CertDAO();
+        CertDAO dao = createDAO();
         CertDataInfos infos;
 
         try {
-            infos = dao.listCerts(filter, maxResults, maxTime, uriInfo);
+            infos = dao.listCerts(filter, maxResults, maxTime);
         } catch (EBaseException e) {
             e.printStackTrace();
             throw new CMSException("Error listing certs in CertsResourceService.listCerts!");
diff --git a/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java b/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java
index aac4315e720696ebddc5c886f7e863eb663a927f..86206ff9c121efe2da21d1f421183421e40f79ca 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/DoRevoke.java
@@ -18,9 +18,10 @@
 package com.netscape.cms.servlet.cert;
 
 import java.io.IOException;
-import java.math.BigInteger;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.Locale;
@@ -32,11 +33,7 @@ import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import netscape.security.x509.CRLExtensions;
-import netscape.security.x509.CRLReasonExtension;
-import netscape.security.x509.InvalidityDateExtension;
 import netscape.security.x509.RevocationReason;
-import netscape.security.x509.RevokedCertImpl;
 import netscape.security.x509.X509CertImpl;
 
 import com.netscape.certsrv.apps.CMS;
@@ -51,6 +48,7 @@ import com.netscape.certsrv.base.IArgBlock;
 import com.netscape.certsrv.base.Nonces;
 import com.netscape.certsrv.ca.ICRLIssuingPoint;
 import com.netscape.certsrv.ca.ICertificateAuthority;
+import com.netscape.certsrv.dbs.certdb.CertId;
 import com.netscape.certsrv.dbs.certdb.ICertRecord;
 import com.netscape.certsrv.dbs.certdb.ICertificateRepository;
 import com.netscape.certsrv.logging.AuditFormat;
@@ -58,7 +56,6 @@ import com.netscape.certsrv.logging.ILogger;
 import com.netscape.certsrv.publish.IPublisherProcessor;
 import com.netscape.certsrv.ra.IRegistrationAuthority;
 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.certsrv.usrgrp.Certificates;
@@ -86,21 +83,12 @@ public class DoRevoke extends CMSServlet {
 
     private ICertificateRepository mCertDB = null;
     private String mFormPath = null;
-    private IRequestQueue mQueue = null;
     private IPublisherProcessor mPublisherProcessor = null;
     private Nonces mNonces = null;
     private int mTimeLimits = 30; /* in seconds */
     private IUGSubsystem mUG = null;
     private ICertUserLocator mUL = null;
 
-    private final static String REVOKE = "revoke";
-    private final static String ON_HOLD = "on-hold";
-    private final static int ON_HOLD_REASON = 6;
-    private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST =
-            "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_5";
-    private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED =
-            "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED_7";
-
     public DoRevoke() {
         super();
     }
@@ -127,7 +115,6 @@ public class DoRevoke extends CMSServlet {
         if (mAuthority instanceof ICertAuthority) {
             mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor();
         }
-        mQueue = mAuthority.getRequestQueue();
 
         mTemplates.remove(CMSRequest.SUCCESS);
         if (mOutputTemplatePath != null)
@@ -424,114 +411,80 @@ public class DoRevoke extends CMSServlet {
             String comments,
             Locale locale)
             throws EBaseException {
-        boolean auditRequest = true;
-        String auditMessage = null;
-        String auditSubjectID = auditSubjectID();
-        String auditRequesterID = auditRequesterID(req);
-        String auditSerialNumber = auditSerialNumber(eeSerialNumber);
-        String auditRequestType = auditRequestType(reason);
-        String auditApprovalStatus = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
-        String auditReasonNum = String.valueOf(reason);
 
-        CMS.debug("DoRevoke: eeSerialNumber: " + eeSerialNumber + " auditSerialNumber: " + auditSerialNumber);
+        CMS.debug("DoRevoke: eeSerialNumber: " + eeSerialNumber);
         long startTime = CMS.getCurrentDate().getTime();
 
+        RevocationProcessor processor = new RevocationProcessor();
+        processor.setStartTime(startTime);
+        processor.setInitiative(initiative);
+        processor.setSerialNumber(auditSerialNumber(eeSerialNumber));
+        processor.setRequestID(auditRequesterID(req));
+
+        RevocationReason revReason = RevocationReason.fromInt(reason);
+        processor.setRevocationReason(revReason);
+        processor.setRequestType(
+                processor.getRevocationReason() == RevocationReason.CERTIFICATE_HOLD
+                        ? RevocationProcessor.ON_HOLD : RevocationProcessor.REVOKE);
+
+        processor.setInvalidityDate(invalidityDate);
+        processor.setComments(comments);
+
+        if (mAuthority instanceof ICertificateAuthority) {
+            processor.setAuthority((ICertificateAuthority)mAuthority);
+        }
+
         try {
-            int count = 0;
-            Vector<X509CertImpl> oldCertsV = new Vector<X509CertImpl>();
-            Vector<RevokedCertImpl> revCertImplsV = new Vector<RevokedCertImpl>();
-
-            // Construct a CRL reason code extension.
-            RevocationReason revReason = RevocationReason.fromInt(reason);
-            CRLReasonExtension crlReasonExtn = new CRLReasonExtension(revReason);
-
-            // Construct a CRL invalidity date extension.
-            InvalidityDateExtension invalidityDateExtn = null;
-
-            if (invalidityDate != null) {
-                invalidityDateExtn = new InvalidityDateExtension(invalidityDate);
-            }
-
-            // Construct a CRL extension for this request.
-            CRLExtensions entryExtn = new CRLExtensions();
-
-            if (crlReasonExtn != null) {
-                entryExtn.set(crlReasonExtn.getName(), crlReasonExtn);
-            }
-            if (invalidityDateExtn != null) {
-                entryExtn.set(invalidityDateExtn.getName(), invalidityDateExtn);
-            }
+            processor.createCRLExtension();
 
             if (mAuthority instanceof ICertificateAuthority) {
 
-                Enumeration<ICertRecord> e = mCertDB.searchCertificates(revokeAll,
-                        totalRecordCount, mTimeLimits);
+                Enumeration<ICertRecord> e = mCertDB.searchCertificates(revokeAll, totalRecordCount, mTimeLimits);
 
                 while (e != null && e.hasMoreElements()) {
-                    ICertRecord rec = e.nextElement();
-
-                    if (rec == null)
-                        continue;
-                    X509CertImpl xcert = rec.getCertificate();
-                    IArgBlock rarg = CMS.createArgBlock();
+                    ICertRecord record = e.nextElement();
+                    X509CertImpl cert = record.getCertificate();
 
                     // we do not want to revoke the CA certificate accidentially
-                    if (xcert != null && isSystemCertificate(xcert.getSerialNumber())) {
+                    if (processor.isSystemCertificate(cert)) {
                         CMS.debug("DoRevoke: skipped revocation request for system certificate "
-                                + xcert.getSerialNumber());
+                                + cert.getSerialNumber());
                         continue;
                     }
 
-                    if (xcert != null) {
-                        rarg.addStringValue("serialNumber",
-                                xcert.getSerialNumber().toString(16));
+                    IArgBlock rarg = CMS.createArgBlock();
 
-                        if (eeSerialNumber != null &&
-                                (eeSerialNumber.equals(xcert.getSerialNumber().toString())) &&
-                                rec.getStatus().equals(ICertRecord.STATUS_REVOKED)) {
-                            log(ILogger.LL_FAILURE,
-                                    CMS.getLogMessage("CA_CERTIFICATE_ALREADY_REVOKED_1", xcert.getSerialNumber()
-                                            .toString(16)));
+                    rarg.addStringValue("serialNumber", cert.getSerialNumber().toString(16));
 
-                            // store a message in the signed audit log file
-                            auditMessage = CMS.getLogMessage(
-                                        LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
-                                        auditSubjectID,
-                                        ILogger.FAILURE,
-                                        auditRequesterID,
-                                        auditSerialNumber,
-                                        auditRequestType);
+                    if (eeSerialNumber != null &&
+                            eeSerialNumber.equals(cert.getSerialNumber().toString()) &&
+                            record.getStatus().equals(ICertRecord.STATUS_REVOKED)) {
+                        log(ILogger.LL_FAILURE,
+                                CMS.getLogMessage("CA_CERTIFICATE_ALREADY_REVOKED_1",
+                                        cert.getSerialNumber().toString(16)));
 
-                            audit(auditMessage);
+                        throw new ECMSGWException(CMS.getLogMessage("CMSGW_UNAUTHORIZED"));
 
-                            throw new ECMSGWException(CMS.getLogMessage("CMSGW_UNAUTHORIZED"));
-                        } else if (rec.getStatus().equals(ICertRecord.STATUS_REVOKED)) {
-                            rarg.addStringValue("error", "Certificate 0x" +
-                                    xcert.getSerialNumber().toString(16) +
-                                    " is already revoked.");
-                        } else if (eeSubjectDN != null &&
-                                (!eeSubjectDN.equals(xcert.getSubjectDN().toString()))) {
-                            rarg.addStringValue("error", "Certificate 0x" +
-                                    xcert.getSerialNumber().toString(16) +
-                                    " belongs to different subject.");
-                        } else {
-                            oldCertsV.addElement(xcert);
+                    } else if (record.getStatus().equals(ICertRecord.STATUS_REVOKED)) {
+                        rarg.addStringValue("error", "Certificate 0x" +
+                                cert.getSerialNumber().toString(16) + " is already revoked.");
 
-                            RevokedCertImpl revCertImpl =
-                                    new RevokedCertImpl(xcert.getSerialNumber(),
-                                            CMS.getCurrentDate(), entryExtn);
+                    } else if (eeSubjectDN != null && !eeSubjectDN.equals(cert.getSubjectDN().toString())) {
+                        rarg.addStringValue("error", "Certificate 0x" +
+                                cert.getSerialNumber().toString(16) + " belongs to different subject.");
 
-                            revCertImplsV.addElement(revCertImpl);
-                            count++;
-                            rarg.addStringValue("error", null);
-                        }
-                        argSet.addRepeatRecord(rarg);
+                    } else {
+                        processor.addCertificateToRevoke(cert);
+
+                        rarg.addStringValue("error", null);
                     }
+
+                    argSet.addRepeatRecord(rarg);
                 }
 
             } else if (mAuthority instanceof IRegistrationAuthority) {
                 String reqIdStr = req.getParameter("requestId");
-                Vector<String> serialNumbers = new Vector<String>();
+                Collection<String> serialNumbers = new ArrayList<String>();
 
                 if (revokeAll != null && revokeAll.length() > 0) {
                     for (int i = revokeAll.indexOf('='); i < revokeAll.length() && i > -1;
@@ -549,11 +502,12 @@ public class DoRevoke extends CMSServlet {
                                 j++;
                             }
                             if (j > i) {
-                                serialNumbers.addElement(revokeAll.substring(i, j));
+                                serialNumbers.add(revokeAll.substring(i, j));
                             }
                         }
                     }
                 }
+
                 if (reqIdStr != null && reqIdStr.length() > 0 && serialNumbers.size() > 0) {
                     IRequest certReq = mRequestQueue.findRequest(new RequestId(reqIdStr));
                     X509CertImpl[] certs = certReq.getExtDataInCertArray(IRequest.OLD_CERTS);
@@ -562,52 +516,38 @@ public class DoRevoke extends CMSServlet {
                     for (int i = 0; i < certs.length; i++) {
                         boolean addToList = false;
 
-                        for (int j = 0; j < serialNumbers.size(); j++) {
+                        for (String serialNumber : serialNumbers) {
                             //xxxxx serial number in decimal?
-                            if (certs[i].getSerialNumber().toString().equals(serialNumbers.elementAt(j)) &&
+                            if (certs[i].getSerialNumber().toString().equals(serialNumber) &&
                                     eeSubjectDN != null && eeSubjectDN.equals(certs[i].getSubjectDN().toString())) {
                                 addToList = true;
                                 break;
                             }
                         }
-                        if (eeSerialNumber != null &&
-                                eeSerialNumber.equals(certs[i].getSerialNumber().toString())) {
+
+                        if (eeSerialNumber != null && eeSerialNumber.equals(certs[i].getSerialNumber().toString())) {
                             authorized = true;
                         }
+
                         if (addToList) {
                             IArgBlock rarg = CMS.createArgBlock();
 
-                            rarg.addStringValue("serialNumber",
-                                    certs[i].getSerialNumber().toString(16));
-                            oldCertsV.addElement(certs[i]);
+                            rarg.addStringValue("serialNumber", certs[i].getSerialNumber().toString(16));
 
-                            RevokedCertImpl revCertImpl =
-                                    new RevokedCertImpl(certs[i].getSerialNumber(),
-                                            CMS.getCurrentDate(), entryExtn);
+                            processor.addCertificateToRevoke(certs[i]);
 
-                            revCertImplsV.addElement(revCertImpl);
-                            count++;
                             rarg.addStringValue("error", null);
                             argSet.addRepeatRecord(rarg);
                         }
                     }
+
                     if (!authorized) {
-                        log(ILogger.LL_FAILURE,
-                                CMS.getLogMessage("CMSGW_REQ_AUTH_REVOKED_CERT"));
-
-                        // store a message in the signed audit log file
-                        auditMessage = CMS.getLogMessage(
-                                    LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
-                                    auditSubjectID,
-                                    ILogger.FAILURE,
-                                    auditRequesterID,
-                                    auditSerialNumber,
-                                    auditRequestType);
-
-                        audit(auditMessage);
+                        log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_REQ_AUTH_REVOKED_CERT"));
+                        processor.auditChangeRequest(ILogger.FAILURE);
 
                         throw new ECMSGWException(CMS.getLogMessage("CMSGW_UNAUTHORIZED"));
                     }
+
                 } else {
                     String b64eCert = req.getParameter("b64eCertificate");
 
@@ -618,185 +558,74 @@ public class DoRevoke extends CMSServlet {
                         X509CertImpl cert = new X509CertImpl(certBytes);
                         IArgBlock rarg = CMS.createArgBlock();
 
-                        rarg.addStringValue("serialNumber",
-                                cert.getSerialNumber().toString(16));
-                        oldCertsV.addElement(cert);
+                        rarg.addStringValue("serialNumber", cert.getSerialNumber().toString(16));
 
-                        RevokedCertImpl revCertImpl =
-                                new RevokedCertImpl(cert.getSerialNumber(),
-                                        CMS.getCurrentDate(), entryExtn);
+                        processor.addCertificateToRevoke(cert);
 
-                        revCertImplsV.addElement(revCertImpl);
-                        count++;
                         rarg.addStringValue("error", null);
                         argSet.addRepeatRecord(rarg);
                     }
                 }
             }
+
+            int count = processor.getCertificates().size();
             if (count == 0) {
                 log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_REV_CERTS_ZERO"));
-
-                // store a message in the signed audit log file
-                auditMessage = CMS.getLogMessage(
-                            LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
-                            auditSubjectID,
-                            ILogger.FAILURE,
-                            auditRequesterID,
-                            auditSerialNumber,
-                            auditRequestType);
-
-                audit(auditMessage);
-
                 throw new ECMSGWException(CMS.getLogMessage("CMSGW_REVOCATION_ERROR_CERT_NOT_FOUND"));
             }
 
             header.addIntegerValue("totalRecordCount", count);
 
-            X509CertImpl[] oldCerts = new X509CertImpl[count];
-            //Certificate[] oldCerts = new Certificate[count];
-            RevokedCertImpl[] revCertImpls = new RevokedCertImpl[count];
-
-            for (int i = 0; i < count; i++) {
-                oldCerts[i] = oldCertsV.elementAt(i);
-                revCertImpls[i] = revCertImplsV.elementAt(i);
-            }
-
-            IRequest revReq =
-                    mQueue.newRequest(IRequest.REVOCATION_REQUEST);
-
-            // store a message in the signed audit log file
-            auditMessage = CMS.getLogMessage(
-                        LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
-                        auditSubjectID,
-                        ILogger.SUCCESS,
-                        auditRequesterID,
-                        auditSerialNumber,
-                        auditRequestType);
-
-            audit(auditMessage);
-
-            revReq.setExtData(IRequest.CERT_INFO, revCertImpls);
-            revReq.setExtData(IRequest.REQ_TYPE, IRequest.REVOCATION_REQUEST);
-            if (initiative.equals(AuditFormat.FROMUSER))
-                revReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_EE);
-            else
-                revReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT);
-            revReq.setExtData(IRequest.OLD_CERTS, oldCerts);
-            if (comments != null) {
-                revReq.setExtData(IRequest.REQUESTOR_COMMENTS, comments);
-            }
-            revReq.setExtData(IRequest.REVOKED_REASON,
-                    Integer.valueOf(reason));
-
-            // change audit processing from "REQUEST" to "REQUEST_PROCESSED"
-            // to distinguish which type of signed audit log message to save
-            // as a failure outcome in case an exception occurs
-            auditRequest = false;
-
-            mQueue.processRequest(revReq);
+            processor.createRevocationRequest();
+
+            processor.auditChangeRequest(ILogger.SUCCESS);
+
+        } catch (CertificateException e) {
+            log(ILogger.LL_FAILURE, "Error " + e);
+            processor.auditChangeRequest(ILogger.FAILURE);
+
+            // TODO: throw exception or return?
+            // throw new EBaseException(e.getMessage());
+            return;
+
+        } catch (EBaseException e) {
+            log(ILogger.LL_FAILURE, "Error " + e);
+            processor.auditChangeRequest(ILogger.FAILURE);
+
+            throw e;
+
+        } catch (IOException e) {
+            log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED_1", e.toString()));
+            processor.auditChangeRequest(ILogger.FAILURE);
+
+            throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED"));
+        }
+
+        // change audit processing from "REQUEST" to "REQUEST_PROCESSED"
+        // to distinguish which type of signed audit log message to save
+        // as a failure outcome in case an exception occurs
+
+        try {
+            processor.processRevocationRequest();
+            IRequest revReq = processor.getRequest();
 
             // retrieve the request status
-            auditApprovalStatus = revReq.getRequestStatus().toString();
+            RequestStatus status = revReq.getRequestStatus();
+            processor.setRequestStatus(status);
 
-            RequestStatus stat = revReq.getRequestStatus();
             String type = revReq.getRequestType();
 
             // The SVC_PENDING check has been added for the Cloned CA request
             // that is meant for the Master CA. From Clone's point of view
             // the request is complete
-            if ((stat == RequestStatus.COMPLETE)
-                    || ((type.equals(IRequest.CLA_CERT4CRL_REQUEST)) && (stat == RequestStatus.SVC_PENDING))) {
-                // audit log the error
-                Integer result = revReq.getExtDataInInteger(IRequest.RESULT);
 
-                if (result.equals(IRequest.RES_ERROR)) {
-                    String[] svcErrors =
-                            revReq.getExtDataInStringArray(IRequest.SVCERRORS);
-
-                    if (svcErrors != null && svcErrors.length > 0) {
-                        for (int i = 0; i < svcErrors.length; i++) {
-                            String err = svcErrors[i];
-
-                            if (err != null) {
-                                //cmsReq.setErrorDescription(err);
-                                for (int j = 0; j < count; j++) {
-                                    if (oldCerts[j] instanceof X509CertImpl) {
-                                        X509CertImpl cert = oldCerts[j];
-
-                                        if (oldCerts[j] != null) {
-                                            mLogger.log(ILogger.EV_AUDIT,
-                                                    ILogger.S_OTHER,
-                                                    AuditFormat.LEVEL,
-                                                    AuditFormat.DOREVOKEFORMAT,
-                                                    new Object[] {
-                                                            revReq.getRequestId(),
-                                                            initiative,
-                                                            "completed with error: " +
-                                                                    err,
-                                                            cert.getSubjectDN(),
-                                                            cert.getSerialNumber().toString(16),
-                                                            RevocationReason.fromInt(reason).toString() }
-                                                    );
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-
-                    // store a message in the signed audit log file
-                    // if and only if "auditApprovalStatus" is
-                    // "complete", "revoked", or "canceled"
-                    if ((auditApprovalStatus.equals(
-                                RequestStatus.COMPLETE_STRING)) ||
-                            (auditApprovalStatus.equals(
-                                    RequestStatus.REJECTED_STRING)) ||
-                            (auditApprovalStatus.equals(
-                                    RequestStatus.CANCELED_STRING))) {
-                        auditMessage = CMS.getLogMessage(
-                                    LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED,
-                                    auditSubjectID,
-                                    ILogger.FAILURE,
-                                    auditRequesterID,
-                                    auditSerialNumber,
-                                    auditRequestType,
-                                    auditReasonNum,
-                                    auditApprovalStatus);
-
-                        audit(auditMessage);
-                    }
-
-                    return;
-                }
-
-                long endTime = CMS.getCurrentDate().getTime();
-
-                // audit log the success.
-                for (int j = 0; j < count; j++) {
-                    if (oldCerts[j] != null) {
-                        if (oldCerts[j] instanceof X509CertImpl) {
-                            X509CertImpl cert = oldCerts[j];
-
-                            mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER,
-                                    AuditFormat.LEVEL,
-                                    AuditFormat.DOREVOKEFORMAT,
-                                    new Object[] {
-                                            revReq.getRequestId(),
-                                            initiative,
-                                            "completed",
-                                            cert.getSubjectDN(),
-                                            cert.getSerialNumber().toString(16),
-                                            RevocationReason.fromInt(reason).toString()
-                                                    + " time: " + (endTime - startTime) }
-                                    );
-                        }
-                    }
-                }
+            if (status == RequestStatus.COMPLETE
+                    || status == RequestStatus.SVC_PENDING
+                        && type.equals(IRequest.CLA_CERT4CRL_REQUEST)) {
 
                 header.addStringValue("revoked", "yes");
 
-                Integer updateCRLResult =
-                        revReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS);
+                Integer updateCRLResult = revReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS);
 
                 if (updateCRLResult != null) {
                     header.addStringValue("updateCRL", "yes");
@@ -804,28 +633,24 @@ public class DoRevoke extends CMSServlet {
                         header.addStringValue("updateCRLSuccess", "yes");
                     } else {
                         header.addStringValue("updateCRLSuccess", "no");
-                        String crlError =
-                                revReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR);
+                        String crlError = revReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR);
 
                         if (crlError != null)
-                            header.addStringValue("updateCRLError",
-                                    crlError);
+                            header.addStringValue("updateCRLError", crlError);
                     }
+
                     // let known crl publishing status too.
-                    Integer publishCRLResult =
-                            revReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS);
+                    Integer publishCRLResult = revReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS);
 
                     if (publishCRLResult != null) {
                         if (publishCRLResult.equals(IRequest.RES_SUCCESS)) {
                             header.addStringValue("publishCRLSuccess", "yes");
                         } else {
                             header.addStringValue("publishCRLSuccess", "no");
-                            String publError =
-                                    revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR);
+                            String publError = revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR);
 
                             if (publError != null)
-                                header.addStringValue("publishCRLError",
-                                        publError);
+                                header.addStringValue("publishCRLError", publError);
                         }
                     }
                 }
@@ -841,6 +666,7 @@ public class DoRevoke extends CMSServlet {
 
                         if (crlId.equals(ICertificateAuthority.PROP_MASTER_CRL))
                             continue;
+
                         String updateStatusStr = crl.getCrlUpdateStatusStr();
                         Integer updateResult = revReq.getExtDataInInteger(updateStatusStr);
 
@@ -849,38 +675,35 @@ public class DoRevoke extends CMSServlet {
                                 CMS.debug("DoRevoke: "
                                         + CMS.getLogMessage("ADMIN_SRVLT_ADDING_HEADER", updateStatusStr));
                                 header.addStringValue(updateStatusStr, "yes");
+
                             } else {
                                 String updateErrorStr = crl.getCrlUpdateErrorStr();
 
                                 CMS.debug("DoRevoke: " + CMS.getLogMessage("ADMIN_SRVLT_ADDING_HEADER_NO",
                                         updateStatusStr));
                                 header.addStringValue(updateStatusStr, "no");
-                                String error =
-                                        revReq.getExtDataInString(updateErrorStr);
+                                String error = revReq.getExtDataInString(updateErrorStr);
 
                                 if (error != null)
-                                    header.addStringValue(updateErrorStr,
-                                            error);
+                                    header.addStringValue(updateErrorStr, error);
                             }
+
                             String publishStatusStr = crl.getCrlPublishStatusStr();
-                            Integer publishResult =
-                                    revReq.getExtDataInInteger(publishStatusStr);
+                            Integer publishResult = revReq.getExtDataInInteger(publishStatusStr);
 
                             if (publishResult == null)
                                 continue;
+
                             if (publishResult.equals(IRequest.RES_SUCCESS)) {
                                 header.addStringValue(publishStatusStr, "yes");
-                            } else {
-                                String publishErrorStr =
-                                        crl.getCrlPublishErrorStr();
 
+                            } else {
+                                String publishErrorStr = crl.getCrlPublishErrorStr();
                                 header.addStringValue(publishStatusStr, "no");
-                                String error =
-                                        revReq.getExtDataInString(publishErrorStr);
+                                String error = revReq.getExtDataInString(publishErrorStr);
 
                                 if (error != null)
-                                    header.addStringValue(
-                                            publishErrorStr, error);
+                                    header.addStringValue(publishErrorStr, error);
                             }
                         }
                     }
@@ -888,8 +711,7 @@ public class DoRevoke extends CMSServlet {
 
                 if (mPublisherProcessor != null && mPublisherProcessor.ldapEnabled()) {
                     header.addStringValue("dirEnabled", "yes");
-                    Integer[] ldapPublishStatus =
-                            revReq.getExtDataInIntegerArray("ldapPublishStatus");
+                    Integer[] ldapPublishStatus = revReq.getExtDataInIntegerArray("ldapPublishStatus");
                     int certsToUpdate = 0;
                     int certsUpdated = 0;
 
@@ -901,209 +723,55 @@ public class DoRevoke extends CMSServlet {
                             }
                         }
                     }
+
                     header.addIntegerValue("certsUpdated", certsUpdated);
                     header.addIntegerValue("certsToUpdate", certsToUpdate);
 
                     // add crl publishing status.
-                    String publError =
-                            revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR);
+                    String publError = revReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR);
 
                     if (publError != null) {
-                        header.addStringValue("crlPublishError",
-                                publError);
+                        header.addStringValue("crlPublishError", publError);
                     }
+
                 } else {
                     header.addStringValue("dirEnabled", "no");
                 }
+
                 header.addStringValue("error", null);
 
             } else {
-                if (stat == RequestStatus.PENDING || stat == RequestStatus.REJECTED) {
-                    header.addStringValue("revoked", stat.toString());
+                if (status == RequestStatus.PENDING || status == RequestStatus.REJECTED) {
+                    header.addStringValue("revoked", status.toString());
                 } else {
                     header.addStringValue("revoked", "no");
                 }
+
                 Vector<String> errors = revReq.getExtDataInStringVector(IRequest.ERRORS);
                 if (errors != null) {
-                    StringBuffer errInfo = new StringBuffer();
+                    StringBuilder errInfo = new StringBuilder();
                     for (int i = 0; i < errors.size(); i++) {
                         errInfo.append(errors.elementAt(i));
                         errInfo.append("\n");
                     }
                     header.addStringValue("error", errInfo.toString());
 
-                } else if (stat == RequestStatus.PENDING) {
+                } else if (status == RequestStatus.PENDING) {
                     header.addStringValue("error", "Request Pending");
+
                 } else {
                     header.addStringValue("error", null);
                 }
-
-                // audit log the pending, revoked and rest
-                for (int j = 0; j < count; j++) {
-                    if (oldCerts[j] != null) {
-                        if (oldCerts[j] instanceof X509CertImpl) {
-                            X509CertImpl cert = oldCerts[j];
-
-                            mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER,
-                                    AuditFormat.LEVEL,
-                                    AuditFormat.DOREVOKEFORMAT,
-                                    new Object[] {
-                                            revReq.getRequestId(),
-                                            initiative,
-                                            stat.toString(),
-                                            cert.getSubjectDN(),
-                                            cert.getSerialNumber().toString(16),
-                                            RevocationReason.fromInt(reason).toString() }
-                                    );
-                        }
-                    }
-                }
-            }
-
-            // store a message in the signed audit log file
-            // if and only if "auditApprovalStatus" is
-            // "complete", "revoked", or "canceled"
-            if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING))
-                    || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING))
-                    || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) {
-                auditMessage = CMS.getLogMessage(
-                            LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED,
-                            auditSubjectID,
-                            ILogger.SUCCESS,
-                            auditRequesterID,
-                            auditSerialNumber,
-                            auditRequestType,
-                            auditReasonNum,
-                            auditApprovalStatus);
-
-                audit(auditMessage);
             }
 
-        } catch (CertificateException e) {
-            if (auditRequest) {
-                // store a "CERT_STATUS_CHANGE_REQUEST" failure
-                // message in the signed audit log file
-                auditMessage = CMS.getLogMessage(
-                            LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
-                            auditSubjectID,
-                            ILogger.FAILURE,
-                            auditRequesterID,
-                            auditSerialNumber,
-                            auditRequestType);
-
-                audit(auditMessage);
-            } else {
-                // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure
-                // message in the signed audit log file
-                // if and only if "auditApprovalStatus" is
-                // "complete", "revoked", or "canceled"
-                if ((auditApprovalStatus.equals(
-                            RequestStatus.COMPLETE_STRING)) ||
-                        (auditApprovalStatus.equals(
-                                RequestStatus.REJECTED_STRING)) ||
-                        (auditApprovalStatus.equals(
-                                RequestStatus.CANCELED_STRING))) {
-                    auditMessage = CMS.getLogMessage(
-                                LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED,
-                                auditSubjectID,
-                                ILogger.FAILURE,
-                                auditRequesterID,
-                                auditSerialNumber,
-                                auditRequestType,
-                                auditReasonNum,
-                                auditApprovalStatus);
-
-                    audit(auditMessage);
-                }
-            }
+            processor.auditChangeRequestProcessed(ILogger.SUCCESS);
 
-            log(ILogger.LL_FAILURE, "error " + e);
         } catch (EBaseException e) {
-            log(ILogger.LL_FAILURE, "error " + e);
-
-            if (auditRequest) {
-                // store a "CERT_STATUS_CHANGE_REQUEST" failure
-                // message in the signed audit log file
-                auditMessage = CMS.getLogMessage(
-                            LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
-                            auditSubjectID,
-                            ILogger.FAILURE,
-                            auditRequesterID,
-                            auditSerialNumber,
-                            auditRequestType);
-
-                audit(auditMessage);
-            } else {
-                // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure
-                // message in the signed audit log file
-                // if and only if "auditApprovalStatus" is
-                // "complete", "revoked", or "canceled"
-                if ((auditApprovalStatus.equals(
-                            RequestStatus.COMPLETE_STRING)) ||
-                        (auditApprovalStatus.equals(
-                                RequestStatus.REJECTED_STRING)) ||
-                        (auditApprovalStatus.equals(
-                                RequestStatus.CANCELED_STRING))) {
-                    auditMessage = CMS.getLogMessage(
-                                LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED,
-                                auditSubjectID,
-                                ILogger.FAILURE,
-                                auditRequesterID,
-                                auditSerialNumber,
-                                auditRequestType,
-                                auditReasonNum,
-                                auditApprovalStatus);
-
-                    audit(auditMessage);
-                }
-            }
+            log(ILogger.LL_FAILURE, "Error " + e);
+            processor.auditChangeRequestProcessed(ILogger.FAILURE);
 
             throw e;
-        } catch (IOException e) {
-            log(ILogger.LL_FAILURE,
-                    CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED_1", e.toString()));
-
-            if (auditRequest) {
-                // store a "CERT_STATUS_CHANGE_REQUEST" failure
-                // message in the signed audit log file
-                auditMessage = CMS.getLogMessage(
-                            LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
-                            auditSubjectID,
-                            ILogger.FAILURE,
-                            auditRequesterID,
-                            auditSerialNumber,
-                            auditRequestType);
-
-                audit(auditMessage);
-            } else {
-                // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure
-                // message in the signed audit log file
-                // if and only if "auditApprovalStatus" is
-                // "complete", "revoked", or "canceled"
-                if ((auditApprovalStatus.equals(
-                            RequestStatus.COMPLETE_STRING)) ||
-                        (auditApprovalStatus.equals(
-                                RequestStatus.REJECTED_STRING)) ||
-                        (auditApprovalStatus.equals(
-                                RequestStatus.CANCELED_STRING))) {
-                    auditMessage = CMS.getLogMessage(
-                                LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED,
-                                auditSubjectID,
-                                ILogger.FAILURE,
-                                auditRequesterID,
-                                auditSerialNumber,
-                                auditRequestType,
-                                auditReasonNum,
-                                auditApprovalStatus);
-
-                    audit(auditMessage);
-                }
-            }
-
-            throw new ECMSGWException(CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED"));
         }
-
-        return;
     }
 
     /**
@@ -1116,24 +784,14 @@ public class DoRevoke extends CMSServlet {
      * @param req HTTP request
      * @return id string containing the signed audit log message RequesterID
      */
-    private String auditRequesterID(HttpServletRequest req) {
-        // if no signed audit object exists, bail
-        if (mSignedAuditLogger == null) {
-            return null;
-        }
-
-        String requesterID = null;
-
-        // Obtain the requesterID
-        requesterID = req.getParameter("requestId");
+    private RequestId auditRequesterID(HttpServletRequest req) {
+        String requesterID = req.getParameter("requestId");
 
         if (requesterID != null) {
-            requesterID = requesterID.trim();
+            return new RequestId(requesterID.trim());
         } else {
-            requesterID = ILogger.UNIDENTIFIED;
+            return null;
         }
-
-        return requesterID;
     }
 
     /**
@@ -1146,74 +804,11 @@ public class DoRevoke extends CMSServlet {
      * @param eeSerialNumber a string containing the un-normalized serialNumber
      * @return id string containing the signed audit log message RequesterID
      */
-    private String auditSerialNumber(String eeSerialNumber) {
-        // if no signed audit object exists, bail
-        if (mSignedAuditLogger == null) {
-            return null;
-        }
-
-        String serialNumber = null;
-
-        // Normalize the serialNumber
+    private CertId auditSerialNumber(String eeSerialNumber) {
         if (eeSerialNumber != null) {
-            serialNumber = eeSerialNumber.trim();
-
-            // find out if the value is hex or decimal
-
-            BigInteger value = BigInteger.ONE.negate();
-
-            //try int
-            try {
-                value = new BigInteger(serialNumber, 10);
-            } catch (NumberFormatException e) {
-            }
-
-            //try hex
-            if (value.compareTo(BigInteger.ONE.negate()) == 0) {
-                try {
-                    value = new BigInteger(serialNumber, 16);
-                } catch (NumberFormatException e) {
-                }
-            }
-            // give up if it isn't hex or dec
-            if (value.compareTo(BigInteger.ONE.negate()) == 0) {
-                throw new NumberFormatException();
-            }
-
-            // convert it to hexadecimal
-            serialNumber = "0x" + value.toString(16);
+            return new CertId(eeSerialNumber.trim());
         } else {
-            serialNumber = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
-        }
-
-        return serialNumber;
-    }
-
-    /**
-     * Signed Audit Log Request Type
-     *
-     * This method is called to obtain the "Request Type" for
-     * a signed audit log message.
-     * <P>
-     *
-     * @param reason an integer denoting the revocation reason
-     * @return string containing REVOKE or ON_HOLD
-     */
-    private String auditRequestType(int reason) {
-        // if no signed audit object exists, bail
-        if (mSignedAuditLogger == null) {
             return null;
         }
-
-        String requestType = null;
-
-        // Determine the revocation type based upon the revocation reason
-        if (reason == ON_HOLD_REASON) {
-            requestType = ON_HOLD;
-        } else {
-            requestType = REVOKE;
-        }
-
-        return requestType;
     }
 }
diff --git a/base/common/src/com/netscape/cms/servlet/cert/DoUnrevoke.java b/base/common/src/com/netscape/cms/servlet/cert/DoUnrevoke.java
index 5605acf6d7cdea26b7ea22fd7e9a8c94556f1129..e46dfaa204da08c2e83f48377d12427ecb44ad55 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/DoUnrevoke.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/DoUnrevoke.java
@@ -30,7 +30,7 @@ import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.RevocationReason;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.authentication.AuthToken;
@@ -42,13 +42,15 @@ import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IArgBlock;
 import com.netscape.certsrv.ca.ICRLIssuingPoint;
 import com.netscape.certsrv.ca.ICertificateAuthority;
+import com.netscape.certsrv.dbs.certdb.CertId;
 import com.netscape.certsrv.dbs.certdb.ICertificateRepository;
 import com.netscape.certsrv.logging.AuditFormat;
 import com.netscape.certsrv.logging.ILogger;
 import com.netscape.certsrv.publish.IPublisherProcessor;
 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.base.CMSException;
 import com.netscape.cms.servlet.base.CMSServlet;
 import com.netscape.cms.servlet.common.CMSRequest;
 import com.netscape.cms.servlet.common.CMSTemplate;
@@ -73,16 +75,8 @@ public class DoUnrevoke extends CMSServlet {
     private ICertificateRepository mCertDB;
 
     private String mFormPath = null;
-    private IRequestQueue mQueue = null;
     private IPublisherProcessor mPublisherProcessor = null;
 
-    private final static String OFF_HOLD = "off-hold";
-    private final static int OFF_HOLD_REASON = 6;
-    private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST =
-            "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_5";
-    private final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED =
-            "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED_7";
-
     public DoUnrevoke() {
         super();
     }
@@ -101,7 +95,6 @@ public class DoUnrevoke extends CMSServlet {
         if (mAuthority instanceof ICertAuthority) {
             mPublisherProcessor = ((ICertAuthority) mAuthority).getPublisherProcessor();
         }
-        mQueue = mAuthority.getRequestQueue();
 
         mTemplates.remove(CMSRequest.SUCCESS);
         if (mOutputTemplatePath != null)
@@ -243,175 +236,111 @@ public class DoUnrevoke extends CMSServlet {
             HttpServletResponse resp,
             Locale locale, String initiative)
             throws EBaseException {
-        boolean auditRequest = true;
-        String auditMessage = null;
-        String auditSubjectID = auditSubjectID();
-        String auditRequesterID = auditRequesterID(req);
-        String auditSerialNumber = auditSerialNumber(serialNumbers[0].toString());
-        String auditRequestType = OFF_HOLD;
-        String auditApprovalStatus = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
-        String auditReasonNum = String.valueOf(OFF_HOLD_REASON);
+
+        RevocationProcessor processor = new RevocationProcessor();
+        processor.setInitiative(initiative);
+        processor.setSerialNumber(auditSerialNumber(serialNumbers[0].toString()));
+        processor.setRequestID(auditRequesterID(req));
+
+        processor.setRevocationReason(RevocationReason.CERTIFICATE_HOLD);
+        processor.setRequestType(RevocationProcessor.OFF_HOLD);
+
+        if (mAuthority instanceof ICertificateAuthority) {
+            processor.setAuthority((ICertificateAuthority) mAuthority);
+        }
 
         try {
-            StringBuffer snList = new StringBuffer();
+            StringBuilder snList = new StringBuilder();
+
+            for (BigInteger serialNumber : serialNumbers) {
+
+                processor.addSerialNumberToUnrevoke(serialNumber);
 
-            // certs are for old cloning and they should be removed as soon as possible
-            X509CertImpl[] certs = new X509CertImpl[serialNumbers.length];
-            for (int i = 0; i < serialNumbers.length; i++) {
-                certs[i] = (X509CertImpl) getX509Certificate(serialNumbers[i]);
                 if (snList.length() > 0)
                     snList.append(", ");
                 snList.append("0x");
-                snList.append(serialNumbers[i].toString(16));
+                snList.append(serialNumber.toString(16));
             }
+
             header.addStringValue("serialNumber", snList.toString());
 
-            IRequest unrevReq = mQueue.newRequest(IRequest.UNREVOCATION_REQUEST);
+            processor.createUnrevocationRequest();
 
-            // store a message in the signed audit log file
-            auditMessage = CMS.getLogMessage(
-                        LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
-                        auditSubjectID,
-                        ILogger.SUCCESS,
-                        auditRequesterID,
-                        auditSerialNumber,
-                        auditRequestType);
+            processor.auditChangeRequest(ILogger.SUCCESS);
 
-            audit(auditMessage);
+        } catch (EBaseException e) {
+            log(ILogger.LL_FAILURE, "Error " + e);
+            processor.auditChangeRequest(ILogger.FAILURE);
 
-            unrevReq.setExtData(IRequest.REQ_TYPE, IRequest.UNREVOCATION_REQUEST);
-            unrevReq.setExtData(IRequest.OLD_SERIALS, serialNumbers);
-            unrevReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT);
+            throw new CMSException(e.getMessage());
+        }
 
-            // change audit processing from "REQUEST" to "REQUEST_PROCESSED"
-            // to distinguish which type of signed audit log message to save
-            // as a failure outcome in case an exception occurs
-            auditRequest = false;
+        // change audit processing from "REQUEST" to "REQUEST_PROCESSED"
+        // to distinguish which type of signed audit log message to save
+        // as a failure outcome in case an exception occurs
 
-            mQueue.processRequest(unrevReq);
-
-            // retrieve the request status
-            auditApprovalStatus = unrevReq.getRequestStatus().toString();
+        try {
+            processor.processUnrevocationRequest();
+            IRequest unrevReq = processor.getRequest();
 
             RequestStatus status = unrevReq.getRequestStatus();
             String type = unrevReq.getRequestType();
 
-            if ((status == RequestStatus.COMPLETE)
-                    || ((type.equals(IRequest.CLA_UNCERT4CRL_REQUEST)) && (status == RequestStatus.SVC_PENDING))) {
+            if (status == RequestStatus.COMPLETE
+                    || status == RequestStatus.SVC_PENDING && type.equals(IRequest.CLA_UNCERT4CRL_REQUEST)) {
 
                 Integer result = unrevReq.getExtDataInInteger(IRequest.RESULT);
 
                 if (result != null && result.equals(IRequest.RES_SUCCESS)) {
                     header.addStringValue("unrevoked", "yes");
-                    if (certs[0] != null) {
-                        mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER,
-                                AuditFormat.LEVEL,
-                                AuditFormat.DOUNREVOKEFORMAT,
-                                new Object[] {
-                                        unrevReq.getRequestId(),
-                                        initiative,
-                                        "completed",
-                                        certs[0].getSubjectDN(),
-                                        "0x" + serialNumbers[0].toString(16) }
-                                );
-                    }
+
                 } else {
                     header.addStringValue("unrevoked", "no");
                     String error = unrevReq.getExtDataInString(IRequest.ERROR);
 
                     if (error != null) {
                         header.addStringValue("error", error);
-                        if (certs[0] != null) {
-                            mLogger.log(ILogger.EV_AUDIT,
-                                    ILogger.S_OTHER,
-                                    AuditFormat.LEVEL,
-                                    AuditFormat.DOUNREVOKEFORMAT,
-                                    new Object[] {
-                                            unrevReq.getRequestId(),
-                                            initiative,
-                                            "completed with error: " +
-                                                    error,
-                                            certs[0].getSubjectDN(),
-                                            "0x" + serialNumbers[0].toString(16) }
-                                    );
-                        }
 
-                        /****************************************************/
-
-                        /* IMPORTANT:  In the event that the following      */
-
-                        /*             "throw error;" statement is          */
-
-                        /*             uncommented, uncomment the following */
-
-                        /*             signed audit log message, also!!!    */
-
-                        /****************************************************/
-
-                        //                  // store a message in the signed audit log file
-                        //                  // if and only if "auditApprovalStatus" is
-                        //                  // "complete", "revoked", or "canceled"
-                        //                  if( ( auditApprovalStatus.equals(
-                        //                            RequestStatus.COMPLETE_STRING ) ) ||
-                        //                      ( auditApprovalStatus.equals(
-                        //                            RequestStatus.REJECTED_STRING ) ) ||
-                        //                      ( auditApprovalStatus.equals(
-                        //                            RequestStatus.CANCELED_STRING ) ) ) {
-                        //                          auditMessage = CMS.getLogMessage(
-                        //                              LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED,
-                        //                              auditSubjectID,
-                        //                              ILogger.FAILURE,
-                        //                              auditRequesterID,
-                        //                              auditSerialNumber,
-                        //                              auditRequestType,
-                        //                              auditReasonNum,
-                        //                              auditApprovalStatus );
-                        //
-                        //                          audit( auditMessage );
-                        //                      }
-
-                        //                      throw error;
+                        // TODO: throw exception on error?
+                        // throw new EBaseException(error);
                     }
                 }
 
-                Integer updateCRLResult =
-                        unrevReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS);
+                Integer updateCRLResult = unrevReq.getExtDataInInteger(IRequest.CRL_UPDATE_STATUS);
 
                 if (updateCRLResult != null) {
                     header.addStringValue("updateCRL", "yes");
+
                     if (updateCRLResult.equals(IRequest.RES_SUCCESS)) {
                         header.addStringValue("updateCRLSuccess", "yes");
+
                     } else {
                         header.addStringValue("updateCRLSuccess", "no");
-                        String crlError =
-                                unrevReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR);
+                        String crlError = unrevReq.getExtDataInString(IRequest.CRL_UPDATE_ERROR);
 
                         if (crlError != null)
-                            header.addStringValue("updateCRLError",
-                                    crlError);
+                            header.addStringValue("updateCRLError", crlError);
                     }
+
                     // let known crl publishing status too.
-                    Integer publishCRLResult =
-                            unrevReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS);
+                    Integer publishCRLResult = unrevReq.getExtDataInInteger(IRequest.CRL_PUBLISH_STATUS);
 
                     if (publishCRLResult != null) {
                         if (publishCRLResult.equals(IRequest.RES_SUCCESS)) {
                             header.addStringValue("publishCRLSuccess", "yes");
+
                         } else {
                             header.addStringValue("publishCRLSuccess", "no");
-                            String publError =
-                                    unrevReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR);
+                            String publError = unrevReq.getExtDataInString(IRequest.CRL_PUBLISH_ERROR);
 
                             if (publError != null)
-                                header.addStringValue("publishCRLError",
-                                        publError);
+                                header.addStringValue("publishCRLError", publError);
                         }
                     }
                 }
 
                 // let known update and publish status of all crls.
-                Enumeration<ICRLIssuingPoint> otherCRLs =
-                        ((ICertificateAuthority) mAuthority).getCRLIssuingPoints();
+                Enumeration<ICRLIssuingPoint> otherCRLs = ((ICertificateAuthority) mAuthority).getCRLIssuingPoints();
 
                 while (otherCRLs.hasMoreElements()) {
                     ICRLIssuingPoint crl = otherCRLs.nextElement();
@@ -419,54 +348,49 @@ public class DoUnrevoke extends CMSServlet {
 
                     if (crlId.equals(ICertificateAuthority.PROP_MASTER_CRL))
                         continue;
+
                     String updateStatusStr = crl.getCrlUpdateStatusStr();
                     Integer updateResult = unrevReq.getExtDataInInteger(updateStatusStr);
 
                     if (updateResult != null) {
                         if (updateResult.equals(IRequest.RES_SUCCESS)) {
-                            CMS.debug("DoUnrevoke: adding header " +
-                                    updateStatusStr + " yes ");
+                            CMS.debug("DoUnrevoke: adding header " + updateStatusStr + " yes");
                             header.addStringValue(updateStatusStr, "yes");
+
                         } else {
                             String updateErrorStr = crl.getCrlUpdateErrorStr();
 
-                            CMS.debug("DoUnrevoke: adding header " +
-                                    updateStatusStr + " no ");
+                            CMS.debug("DoUnrevoke: adding header " + updateStatusStr + " no");
                             header.addStringValue(updateStatusStr, "no");
-                            String error =
-                                    unrevReq.getExtDataInString(updateErrorStr);
+                            String error = unrevReq.getExtDataInString(updateErrorStr);
 
                             if (error != null)
-                                header.addStringValue(
-                                        updateErrorStr, error);
+                                header.addStringValue(updateErrorStr, error);
                         }
+
                         String publishStatusStr = crl.getCrlPublishStatusStr();
-                        Integer publishResult =
-                                unrevReq.getExtDataInInteger(publishStatusStr);
+                        Integer publishResult = unrevReq.getExtDataInInteger(publishStatusStr);
 
                         if (publishResult == null)
                             continue;
+
                         if (publishResult.equals(IRequest.RES_SUCCESS)) {
                             header.addStringValue(publishStatusStr, "yes");
-                        } else {
-                            String publishErrorStr =
-                                    crl.getCrlPublishErrorStr();
 
+                        } else {
+                            String publishErrorStr = crl.getCrlPublishErrorStr();
                             header.addStringValue(publishStatusStr, "no");
-                            String error =
-                                    unrevReq.getExtDataInString(publishErrorStr);
+                            String error = unrevReq.getExtDataInString(publishErrorStr);
 
                             if (error != null)
-                                header.addStringValue(
-                                        publishErrorStr, error);
+                                header.addStringValue(publishErrorStr, error);
                         }
                     }
                 }
 
                 if (mPublisherProcessor != null && mPublisherProcessor.ldapEnabled()) {
                     header.addStringValue("dirEnabled", "yes");
-                    Integer[] ldapPublishStatus =
-                            unrevReq.getExtDataInIntegerArray("ldapPublishStatus");
+                    Integer[] ldapPublishStatus = unrevReq.getExtDataInIntegerArray("ldapPublishStatus");
 
                     if (ldapPublishStatus != null) {
                         if (ldapPublishStatus[0] == IRequest.RES_SUCCESS) {
@@ -482,94 +406,18 @@ public class DoUnrevoke extends CMSServlet {
             } else if (status == RequestStatus.PENDING) {
                 header.addStringValue("error", "Request Pending");
                 header.addStringValue("unrevoked", "pending");
-                if (certs[0] != null) {
-                    mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER,
-                            AuditFormat.LEVEL,
-                            AuditFormat.DOUNREVOKEFORMAT,
-                            new Object[] {
-                                    unrevReq.getRequestId(),
-                                    initiative,
-                                    "pending",
-                                    certs[0].getSubjectDN(),
-                                    "0x" + serialNumbers[0].toString(16) }
-                            );
-                }
+
             } else {
                 header.addStringValue("error", "Request Status.Error");
                 header.addStringValue("unrevoked", "no");
-                if (certs[0] != null) {
-                    mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER,
-                            AuditFormat.LEVEL,
-                            AuditFormat.DOUNREVOKEFORMAT,
-                            new Object[] {
-                                    unrevReq.getRequestId(),
-                                    initiative,
-                                    status.toString(),
-                                    certs[0].getSubjectDN(),
-                                    "0x" + serialNumbers[0].toString(16) }
-                            );
-                }
             }
 
-            // store a message in the signed audit log file
-            // if and only if "auditApprovalStatus" is
-            // "complete", "revoked", or "canceled"
-            if ((auditApprovalStatus.equals(RequestStatus.COMPLETE_STRING))
-                    || (auditApprovalStatus.equals(RequestStatus.REJECTED_STRING))
-                    || (auditApprovalStatus.equals(RequestStatus.CANCELED_STRING))) {
-                auditMessage = CMS.getLogMessage(
-                            LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED,
-                            auditSubjectID,
-                            ILogger.SUCCESS,
-                            auditRequesterID,
-                            auditSerialNumber,
-                            auditRequestType,
-                            auditReasonNum,
-                            auditApprovalStatus);
+            processor.auditChangeRequestProcessed(ILogger.SUCCESS);
 
-                audit(auditMessage);
-            }
-
-        } catch (EBaseException eAudit1) {
-            if (auditRequest) {
-                // store a "CERT_STATUS_CHANGE_REQUEST" failure
-                // message in the signed audit log file
-                auditMessage = CMS.getLogMessage(
-                            LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
-                            auditSubjectID,
-                            ILogger.FAILURE,
-                            auditRequesterID,
-                            auditSerialNumber,
-                            auditRequestType);
-
-                audit(auditMessage);
-            } else {
-                // store a "CERT_STATUS_CHANGE_REQUEST_PROCESSED" failure
-                // message in the signed audit log file
-                // if and only if "auditApprovalStatus" is
-                // "complete", "revoked", or "canceled"
-                if ((auditApprovalStatus.equals(
-                            RequestStatus.COMPLETE_STRING)) ||
-                        (auditApprovalStatus.equals(
-                                RequestStatus.REJECTED_STRING)) ||
-                        (auditApprovalStatus.equals(
-                                RequestStatus.CANCELED_STRING))) {
-                    auditMessage = CMS.getLogMessage(
-                                LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED,
-                                auditSubjectID,
-                                ILogger.FAILURE,
-                                auditRequesterID,
-                                auditSerialNumber,
-                                auditRequestType,
-                                auditReasonNum,
-                                auditApprovalStatus);
-
-                    audit(auditMessage);
-                }
-            }
+        } catch (EBaseException e) {
+            log(ILogger.LL_FAILURE, "Error " + e);
+            processor.auditChangeRequestProcessed(ILogger.FAILURE);
         }
-
-        return;
     }
 
     private BigInteger[] getSerialNumbers(HttpServletRequest req)
@@ -618,24 +466,14 @@ public class DoUnrevoke extends CMSServlet {
      * @param req HTTP request
      * @return id string containing the signed audit log message RequesterID
      */
-    private String auditRequesterID(HttpServletRequest req) {
-        // if no signed audit object exists, bail
-        if (mSignedAuditLogger == null) {
-            return null;
-        }
-
-        String requesterID = null;
-
-        // Obtain the requesterID
-        requesterID = req.getParameter("requestId");
+    private RequestId auditRequesterID(HttpServletRequest req) {
+        String requesterID = req.getParameter("requestId");
 
         if (requesterID != null) {
-            requesterID = requesterID.trim();
+            return new RequestId(requesterID.trim());
         } else {
-            requesterID = ILogger.UNIDENTIFIED;
+            return null;
         }
-
-        return requesterID;
     }
 
     /**
@@ -648,24 +486,11 @@ public class DoUnrevoke extends CMSServlet {
      * @param eeSerialNumber a string containing the un-normalized serialNumber
      * @return id string containing the signed audit log message RequesterID
      */
-    private String auditSerialNumber(String eeSerialNumber) {
-        // if no signed audit object exists, bail
-        if (mSignedAuditLogger == null) {
-            return null;
-        }
-
-        String serialNumber = null;
-
-        // Normalize the serialNumber
+    private CertId auditSerialNumber(String eeSerialNumber) {
         if (eeSerialNumber != null) {
-            serialNumber = eeSerialNumber.trim();
-
-            // convert it to hexadecimal
-            serialNumber = "0x" + (new BigInteger(serialNumber)).toString(16);
+            return new CertId(eeSerialNumber.trim());
         } else {
-            serialNumber = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+            return null;
         }
-
-        return serialNumber;
     }
 }
diff --git a/base/common/src/com/netscape/cms/servlet/cert/RevocationProcessor.java b/base/common/src/com/netscape/cms/servlet/cert/RevocationProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..287a3c9325e9fb5df12e8434d1b00241b86568f7
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/RevocationProcessor.java
@@ -0,0 +1,459 @@
+// --- 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.cert;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import netscape.security.x509.CRLExtensions;
+import netscape.security.x509.CRLReasonExtension;
+import netscape.security.x509.InvalidityDateExtension;
+import netscape.security.x509.RevocationReason;
+import netscape.security.x509.RevokedCertImpl;
+import netscape.security.x509.X509CertImpl;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.ca.ICertificateAuthority;
+import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.certsrv.dbs.certdb.ICertRecord;
+import com.netscape.certsrv.dbs.certdb.ICertificateRepository;
+import com.netscape.certsrv.logging.AuditFormat;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.publish.IPublisherProcessor;
+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.processors.Processor;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class RevocationProcessor extends Processor {
+
+    public final static String REVOKE = "revoke";
+    public final static String ON_HOLD = "on-hold";
+    public final static String OFF_HOLD = "off-hold";
+
+    public final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST =
+            "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_5";
+    public final static String LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED =
+            "LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED_7";
+
+    long startTime;
+
+    ICertificateAuthority authority;
+    ICertificateRepository repo;
+    IRequestQueue requestQueue;
+    IPublisherProcessor publisherProcessor;
+
+    String initiative;
+    RequestId requestID;
+    CertId serialNumber;
+    RevocationReason revocationReason;
+    Date invalidityDate;
+    String comments;
+    String requestType;
+
+    CRLExtensions entryExtn;
+    Collection<X509CertImpl> certificates = new ArrayList<X509CertImpl>();
+    Collection<RevokedCertImpl> revCertImpls = new ArrayList<RevokedCertImpl>();
+    IRequest request;
+    RequestStatus requestStatus;
+
+    public RevocationProcessor() {
+    }
+
+    public ICertificateAuthority getAuthority() {
+        return authority;
+    }
+
+    public void setAuthority(ICertificateAuthority authority) {
+        this.authority = authority;
+        repo = authority.getCertificateRepository();
+        requestQueue = authority.getRequestQueue();
+        publisherProcessor = authority.getPublisherProcessor();
+    }
+
+    public long getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(long startTime) {
+        this.startTime = startTime;
+    }
+
+    public String getInitiative() {
+        return initiative;
+    }
+
+    public void setInitiative(String initiative) {
+        this.initiative = initiative;
+    }
+
+    public RequestId getRequestID() {
+        return requestID;
+    }
+
+    public void setRequestID(RequestId requestID) {
+        this.requestID = requestID;
+    }
+
+    public CertId getSerialNumber() {
+        return serialNumber;
+    }
+
+    public void setSerialNumber(CertId serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
+    public RevocationReason getRevocationReason() {
+        return revocationReason;
+    }
+
+    public void setRevocationReason(RevocationReason revocationReason) {
+        this.revocationReason = revocationReason;
+    }
+
+    public Date getInvalidityDate() {
+        return invalidityDate;
+    }
+
+    public void setInvalidityDate(Date invalidityDate) {
+        this.invalidityDate = invalidityDate;
+    }
+
+    public String getComments() {
+        return comments;
+    }
+
+    public void setComments(String comments) {
+        this.comments = comments;
+    }
+
+    public String getRequestType() {
+        return requestType;
+    }
+
+    public void setRequestType(String requestType) {
+        this.requestType = requestType;
+    }
+
+    public RequestStatus getRequestStatus() {
+        return requestStatus;
+    }
+
+    public void setRequestStatus(RequestStatus requestStatus) {
+        this.requestStatus = requestStatus;
+    }
+
+    public void addCertificate(X509CertImpl cert) {
+        certificates.add(cert);
+    }
+
+    public Collection<X509CertImpl> getCertificates() {
+        return certificates;
+    }
+
+    public IRequest getRequest() {
+        return request;
+    }
+
+    public void addCertificateToRevoke(X509CertImpl cert) {
+        addCertificate(cert);
+        revCertImpls.add(new RevokedCertImpl(cert.getSerialNumber(), CMS.getCurrentDate(), entryExtn));
+    }
+
+    public void addSerialNumberToUnrevoke(BigInteger serialNumber) throws EBaseException {
+        ICertRecord records = getCertificateRecord(serialNumber);
+        X509CertImpl cert = records.getCertificate();
+        addCertificate(cert);
+    }
+
+    public ICertRecord[] getCertificateRecords(BigInteger[] serialNumbers) throws EBaseException {
+        ICertRecord[] records = new ICertRecord[serialNumbers.length];
+        for (int i=0; i<serialNumbers.length; i++) {
+            records[i] = getCertificateRecord(serialNumbers[i]);
+        }
+        return records;
+    }
+
+    public ICertRecord getCertificateRecord(CertId id) throws EBaseException {
+        return getCertificateRecord(id.toBigInteger());
+    }
+
+    public ICertRecord getCertificateRecord(BigInteger serialNumber) throws EBaseException {
+        return repo.readCertificateRecord(serialNumber);
+    }
+
+    public X509CertImpl[] getCertificates(ICertRecord[] records) throws EBaseException {
+        X509CertImpl[] certs = new X509CertImpl[records.length];
+        for (int i=0; i<records.length; i++) {
+            certs[i] = records[i].getCertificate();
+        }
+        return certs;
+    }
+
+    public void createCRLExtension() throws IOException {
+
+        // Construct a CRL extension for this request.
+        entryExtn = new CRLExtensions();
+
+        // Construct a CRL reason code extension.
+        CRLReasonExtension crlReasonExtn = new CRLReasonExtension(revocationReason);
+        entryExtn.set(crlReasonExtn.getName(), crlReasonExtn);
+
+        // Construct a CRL invalidity date extension.
+        if (invalidityDate != null) {
+            InvalidityDateExtension invalidityDateExtn = new InvalidityDateExtension(invalidityDate);
+            entryExtn.set(invalidityDateExtn.getName(), invalidityDateExtn);
+        }
+    }
+
+    public void createRevocationRequest() throws EBaseException {
+
+        request = requestQueue.newRequest(IRequest.REVOCATION_REQUEST);
+
+        request.setExtData(IRequest.REQ_TYPE, IRequest.REVOCATION_REQUEST);
+
+        request.setExtData(IRequest.OLD_CERTS, certificates.toArray(new X509CertImpl[certificates.size()]));
+        request.setExtData(IRequest.CERT_INFO, revCertImpls.toArray(new RevokedCertImpl[revCertImpls.size()]));
+
+        if (AuditFormat.FROMUSER.equals(initiative)) {
+            request.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_EE);
+        } else {
+            request.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT);
+        }
+
+        if (comments != null) {
+            request.setExtData(IRequest.REQUESTOR_COMMENTS, comments);
+        }
+
+        request.setExtData(IRequest.REVOKED_REASON, revocationReason.toInt());
+    }
+
+    public void processRevocationRequest() throws EBaseException {
+
+        requestQueue.processRequest(request);
+        requestStatus = request.getRequestStatus();
+
+        CMS.debug("revokeCert: status: " + requestStatus);
+
+        String type = request.getRequestType();
+
+        // The SVC_PENDING check has been added for the Cloned CA request
+        // that is meant for the Master CA. From Clone's point of view
+        // the request is complete
+
+        if (requestStatus == RequestStatus.COMPLETE
+                || requestStatus == RequestStatus.SVC_PENDING
+                    && type.equals(IRequest.CLA_CERT4CRL_REQUEST)) {
+
+            // audit log the error
+            Integer result = request.getExtDataInInteger(IRequest.RESULT);
+
+            if (result.equals(IRequest.RES_ERROR)) {
+                String[] svcErrors = request.getExtDataInStringArray(IRequest.SVCERRORS);
+
+                if (svcErrors != null) {
+                    for (String err : svcErrors) {
+                        //cmsReq.setErrorDescription(err);
+                        for (X509CertImpl cert : certificates) {
+                            logRevoke(
+                                    request, cert,
+                                    "completed with error: " + err,
+                                    revocationReason.toString());
+                        }
+                    }
+                }
+
+                throw new EBaseException(CMS.getLogMessage("CMSGW_ERROR_MARKING_CERT_REVOKED"));
+            }
+
+            long endTime = CMS.getCurrentDate().getTime();
+
+            // audit log the success.
+            for (X509CertImpl cert : certificates) {
+                logRevoke(request, cert,
+                        "completed",
+                        revocationReason + " time: " + (endTime - startTime));
+            }
+
+        } else {
+
+            // audit log the pending, revoked and rest
+            for (X509CertImpl cert : certificates) {
+                logRevoke(request, cert,
+                        requestStatus.toString(),
+                        revocationReason.toString());
+            }
+        }
+    }
+
+    public void createUnrevocationRequest() throws EBaseException {
+
+        request = requestQueue.newRequest(IRequest.UNREVOCATION_REQUEST);
+
+        request.setExtData(IRequest.REQ_TYPE, IRequest.UNREVOCATION_REQUEST);
+
+        Collection<BigInteger> serialNumbers = new ArrayList<BigInteger>();
+        for (X509CertImpl cert : certificates) {
+            serialNumbers.add(cert.getSerialNumber());
+        }
+        request.setExtData(IRequest.OLD_SERIALS, serialNumbers.toArray(new BigInteger[serialNumbers.size()]));
+        request.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_AGENT);
+    }
+
+    public void processUnrevocationRequest() throws EBaseException {
+
+        requestQueue.processRequest(request);
+        requestStatus = request.getRequestStatus();
+
+        String type = request.getRequestType();
+
+        if (requestStatus == RequestStatus.COMPLETE
+                || requestStatus == RequestStatus.SVC_PENDING && type.equals(IRequest.CLA_UNCERT4CRL_REQUEST)) {
+
+            Integer result = request.getExtDataInInteger(IRequest.RESULT);
+
+            if (result != null && result.equals(IRequest.RES_SUCCESS)) {
+                for (X509CertImpl cert : certificates) {
+                    logUnrevoke(request, cert, "completed");
+                }
+
+            } else {
+                String error = request.getExtDataInString(IRequest.ERROR);
+                for (X509CertImpl cert : certificates) {
+                    logUnrevoke(request, cert, "completed with error: " + error);
+                }
+            }
+
+        } else {
+            for (X509CertImpl cert : certificates) {
+                logUnrevoke(request, cert, requestStatus.toString());
+            }
+        }
+    }
+
+    /**
+     * A system certificate such as the CA signing certificate
+     * should not be allowed to delete.
+     * The main purpose is to avoid revoking the self signed
+     * CA certificate accidentally.
+     */
+    public boolean isSystemCertificate(X509Certificate cert) {
+
+        X509Certificate caCert = authority.getCACert();
+        if (caCert == null)
+            return false;
+
+        // check whether it's a CA certificate
+        if (!caCert.getSerialNumber().equals(cert.getSerialNumber()))
+            return false;
+
+        // check whether it's a self-signed we certificate
+        return caCert.getSubjectDN().equals(caCert.getIssuerDN());
+    }
+
+    public void logRevoke(IRequest revocationRequest, X509Certificate cert, String status, String message) {
+
+        if (logger == null)
+            return;
+
+        logger.log(
+                ILogger.EV_AUDIT,
+                ILogger.S_OTHER,
+                AuditFormat.LEVEL,
+                AuditFormat.DOREVOKEFORMAT,
+                new Object[] {
+                        revocationRequest.getRequestId(),
+                        initiative,
+                        status,
+                        cert.getSubjectDN(),
+                        cert.getSerialNumber().toString(16),
+                        message
+                });
+    }
+
+    public void logUnrevoke(IRequest unrevocationRequest, X509Certificate cert, String status) {
+
+        if (logger == null)
+            return;
+
+        logger.log(
+                ILogger.EV_AUDIT,
+                ILogger.S_OTHER,
+                AuditFormat.LEVEL,
+                AuditFormat.DOUNREVOKEFORMAT,
+                new Object[] {
+                        unrevocationRequest.getRequestId(),
+                        initiative,
+                        status,
+                        cert.getSubjectDN(),
+                        cert.getSerialNumber().toString(16),
+                });
+    }
+
+    public void auditChangeRequest(String status) {
+
+        if (auditor == null)
+            return;
+
+        String auditMessage = CMS.getLogMessage(
+                LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST,
+                auditor.getSubjectID(),
+                status,
+                requestID == null ? ILogger.UNIDENTIFIED : requestID.toString(),
+                serialNumber == null ? ILogger.SIGNED_AUDIT_EMPTY_VALUE : serialNumber.toHexString(),
+                requestType);
+
+        auditor.log(auditMessage);
+    }
+
+    public void auditChangeRequestProcessed(String status) {
+
+        if (auditor == null)
+            return;
+
+        // store a message in the signed audit log file
+        // if and only if "requestStatus" is
+        // "complete", "revoked", or "canceled"
+
+        if (!(requestStatus == RequestStatus.COMPLETE
+                || requestStatus == RequestStatus.REJECTED
+                || requestStatus == RequestStatus.CANCELED)) return;
+
+        String auditMessage = CMS.getLogMessage(
+                LOGGING_SIGNED_AUDIT_CERT_STATUS_CHANGE_REQUEST_PROCESSED,
+                auditor.getSubjectID(),
+                status,
+                requestID == null ? ILogger.UNIDENTIFIED : requestID.toString(),
+                serialNumber == null ? ILogger.SIGNED_AUDIT_EMPTY_VALUE : serialNumber.toHexString(),
+                requestType,
+                String.valueOf(revocationReason.toInt()),
+                requestStatus == null ? ILogger.SIGNED_AUDIT_EMPTY_VALUE : requestStatus.toString());
+
+        auditor.log(auditMessage);
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertDAO.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertDAO.java
index e71055580377899e611a46b5dcae393f0b225f38..1177b66f675ad2e0e493206585e535e9f677e98d 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/model/CertDAO.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertDAO.java
@@ -18,7 +18,7 @@
 package com.netscape.cms.servlet.cert.model;
 
 import java.io.ByteArrayOutputStream;
-import java.math.BigInteger;
+import java.net.URI;
 import java.security.Principal;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
@@ -26,9 +26,8 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.List;
+import java.util.Locale;
 
-import javax.ws.rs.Path;
-import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 
 import netscape.security.pkcs.ContentInfo;
@@ -37,8 +36,11 @@ import netscape.security.pkcs.SignerInfo;
 import netscape.security.x509.AlgorithmId;
 import netscape.security.x509.X509CertImpl;
 
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.ICertPrettyPrint;
 import com.netscape.certsrv.ca.ICertificateAuthority;
 import com.netscape.certsrv.dbs.certdb.CertId;
 import com.netscape.certsrv.dbs.certdb.ICertRecord;
@@ -53,6 +55,9 @@ import com.netscape.cmsutil.util.Utils;
  */
 public class CertDAO {
 
+    Locale locale;
+    UriInfo uriInfo;
+
     private ICertificateRepository repo;
     private ICertificateAuthority ca;
 
@@ -61,6 +66,22 @@ public class CertDAO {
         repo = ca.getCertificateRepository();
     }
 
+    public Locale getLocale() {
+        return locale;
+    }
+
+    public void setLocale(Locale locale) {
+        this.locale = locale;
+    }
+
+    public UriInfo getUriInfo() {
+        return uriInfo;
+    }
+
+    public void setUriInfo(UriInfo uriInfo) {
+        this.uriInfo = uriInfo;
+    }
+
     /**
      * Returns list of certs meeting specified search filter.
      * Currently, vlv searches are not used for certs.
@@ -72,7 +93,7 @@ public class CertDAO {
      * @return
      * @throws EBaseException
      */
-    public CertDataInfos listCerts(String filter, int maxResults, int maxTime, UriInfo uriInfo)
+    public CertDataInfos listCerts(String filter, int maxResults, int maxTime)
             throws EBaseException {
         List<CertDataInfo> list = new ArrayList<CertDataInfo>();
         Enumeration<ICertRecord> e = null;
@@ -85,7 +106,7 @@ public class CertDAO {
         while (e.hasMoreElements()) {
             ICertRecord rec = e.nextElement();
             if (rec != null) {
-                list.add(createCertDataInfo(rec, uriInfo));
+                list.add(createCertDataInfo(rec));
             }
         }
 
@@ -97,96 +118,61 @@ public class CertDAO {
 
     public CertificateData getCert(CertRetrievalRequestData data) throws EBaseException, CertificateEncodingException {
 
-        CertificateData certData = null;
         CertId certId = data.getCertId();
 
         //find the cert in question
+        ICertRecord record = repo.readCertificateRecord(certId.toBigInteger());
+        X509CertImpl cert = record.getCertificate();
 
-        ICertRecord rec = null;
-        BigInteger seq = certId.toBigInteger();
+        CertificateData certData = new CertificateData();
 
-        rec = repo.readCertificateRecord(seq);
-        X509CertImpl x509cert = null;
+        certData.setSerialNumber(certId);
 
-        if (rec != null) {
-            x509cert = rec.getCertificate();
-        }
+        Principal issuerDN = cert.getIssuerDN();
+        if (issuerDN != null) certData.setIssuerDN(issuerDN.toString());
 
-        if (x509cert != null) {
-            certData = new CertificateData();
+        Principal subjectDN = cert.getSubjectDN();
+        if (subjectDN != null) certData.setSubjectDN(subjectDN.toString());
 
-            byte[] ba = null;
-            String encoded64 = null;
+        String base64 = CMS.getEncodedCert(cert);
+        certData.setEncoded(base64);
 
-            ba = x509cert.getEncoded();
+        ICertPrettyPrint print = CMS.getCertPrettyPrint(cert);
+        certData.setPrettyPrint(print.toString(locale));
 
-            encoded64 = Utils.base64encode(ba);
+        String p7Str = getCertChainData(cert);
+        certData.setPkcs7CertChain(p7Str);
 
-            String prettyPrint = x509cert.toString();
+        Date notBefore = cert.getNotBefore();
+        if (notBefore != null) certData.setNotBefore(notBefore.toString());
 
-            certData.setB64(encoded64);
-            certData.setPrettyPrint(prettyPrint);
+        Date notAfter = cert.getNotAfter();
+        if (notAfter != null) certData.setNotAfter(notAfter.toString());
 
-            String subjectNameStr = null;
-            Principal subjectName = x509cert.getSubjectDN();
+        certData.setStatus(record.getStatus());
 
-            if (subjectName != null) {
-                subjectNameStr = subjectName.toString();
-            }
-
-            certData.setSubjectName(subjectNameStr);
-
-            //Try to get the chain
-
-            String p7Str = getCertChainData(x509cert);
-
-            certData.setPkcs7CertChain(p7Str);
-
-            certData.setSerialNo(certId);
-
-            Date notBefore = x509cert.getNotBefore();
-            Date notAfter = x509cert.getNotAfter();
-
-            String notBeforeStr = null;
-            String notAfterStr = null;
-
-            if (notBefore != null) {
-                notBeforeStr = notBefore.toString();
-            }
-
-            if (notAfter != null) {
-                notAfterStr = notAfter.toString();
-            }
-
-            certData.setNotBefore(notBeforeStr);
-            certData.setNotAfter(notAfterStr);
-
-            String issuerNameStr = null;
-
-            Principal issuerName = x509cert.getIssuerDN();
-
-            if (issuerName != null) {
-                issuerNameStr = issuerName.toString();
-            }
-
-            certData.setIssuerName(issuerNameStr);
-
-        }
+        URI uri = uriInfo.getBaseUriBuilder().path(CertResource.class).path("{id}").build(certId.toHexString());
+        certData.setLink(new Link("self", uri));
 
         return certData;
     }
 
-    private CertDataInfo createCertDataInfo(ICertRecord rec, UriInfo uriInfo) throws EBaseException {
-        CertDataInfo ret = new CertDataInfo();
+    private CertDataInfo createCertDataInfo(ICertRecord record) throws EBaseException {
 
-        Path certPath = CertResource.class.getAnnotation(Path.class);
-        BigInteger serial = rec.getSerialNumber();
+        CertDataInfo info = new CertDataInfo();
 
-        UriBuilder certBuilder = uriInfo.getBaseUriBuilder();
-        certBuilder.path(certPath.value() + "/" + serial);
-        ret.setCertURL(certBuilder.build().toString());
+        CertId id = new CertId(record.getSerialNumber());
+        info.setID(id);
 
-        return ret;
+        X509Certificate cert = record.getCertificate();
+        info.setSubjectDN(cert.getSubjectDN().toString());
+
+        info.setStatus(record.getStatus());
+
+        URI uri = uriInfo.getBaseUriBuilder().path(CertResource.class).path("{id}").build(id.toHexString());
+        info.setLink(new Link("self", uri));
+
+        return info;
     }
 
     private String getCertChainData(X509CertImpl x509cert) {
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfo.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfo.java
index 0f8d35e05180a02f39cf3a8d4c21d7010c71c0ca..4c6a9b19e5f9e2c19fce269096ae858b8cb5a752 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfo.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfo.java
@@ -20,48 +20,154 @@
  */
 package com.netscape.cms.servlet.cert.model;
 
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.jboss.resteasy.plugins.providers.atom.Link;
 
 import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.certsrv.dbs.certdb.CertIdAdapter;
 
 /**
  * @author alee
  *
  */
 @XmlRootElement(name = "CertDataInfo")
-@XmlAccessorType(XmlAccessType.FIELD)
 public class CertDataInfo {
 
-    @XmlElement
-    protected String certURL;
+    public static Marshaller marshaller;
+    public static Unmarshaller unmarshaller;
 
-    public CertDataInfo() {
-        // required for JAXB (defaults)
+    static {
+        try {
+            JAXBContext context = JAXBContext.newInstance(CertDataInfo.class);
+            marshaller = context.createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            unmarshaller = context.createUnmarshaller();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
     }
 
-    /**
-     * @return the CertURL
-     */
-    public String getCertURL() {
-        return certURL;
+    CertId id;
+    String subjectDN;
+    String status;
+
+    Link link;
+
+    @XmlAttribute(name="id")
+    @XmlJavaTypeAdapter(CertIdAdapter.class)
+    public CertId getID() {
+        return id;
+    }
+
+    public void setID(CertId id) {
+        this.id = id;
+    }
+
+    @XmlElement(name="SubjectDN")
+    public String getSubjectDN() {
+        return subjectDN;
+    }
+
+    public void setSubjectDN(String subjectDN) {
+        this.subjectDN = subjectDN;
+    }
+
+    @XmlElement(name="Status")
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    @XmlElement(name="Link")
+    public Link getLink() {
+        return link;
+    }
+
+    public void setLink(Link link) {
+        this.link = link;
     }
 
-    /**
-     * @param CertURL the certURL to set
-     */
-    public void setCertURL(String certURL) {
-        this.certURL = certURL;
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((id == null) ? 0 : id.hashCode());
+        result = prime * result + ((status == null) ? 0 : status.hashCode());
+        result = prime * result + ((subjectDN == null) ? 0 : subjectDN.hashCode());
+        return result;
     }
 
-    /**
-     * @return the Cert ID in the CertURL
-     */
-    public CertId getCertId() {
-        String id = certURL.substring(certURL.lastIndexOf("/") + 1);
-        return new CertId(id);
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        CertDataInfo other = (CertDataInfo) obj;
+        if (id == null) {
+            if (other.id != null)
+                return false;
+        } else if (!id.equals(other.id))
+            return false;
+        if (status == null) {
+            if (other.status != null)
+                return false;
+        } else if (!status.equals(other.status))
+            return false;
+        if (subjectDN == null) {
+            if (other.subjectDN != null)
+                return false;
+        } else if (!subjectDN.equals(other.subjectDN))
+            return false;
+        return true;
     }
 
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static CertDataInfo valueOf(String string) throws Exception {
+        try {
+            return (CertDataInfo)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        CertDataInfo before = new CertDataInfo();
+        before.setID(new CertId("12512514865863765114"));
+        before.setSubjectDN("CN=Test User,UID=testuser,O=EXAMPLE-COM");
+        before.setStatus("VALID");
+
+        String string = before.toString();
+        System.out.println(string);
+
+        CertDataInfo after = CertDataInfo.valueOf(string);
+
+        System.out.println(before.equals(after));
+    }
 }
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertRevokeRequest.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertRevokeRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5a79b010080d0e84b333762d42ce0e23ce977a50
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertRevokeRequest.java
@@ -0,0 +1,235 @@
+// --- 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.cert.model;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Date;
+
+import javax.ws.rs.FormParam;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import netscape.security.x509.RevocationReason;
+import netscape.security.x509.RevocationReasonAdapter;
+
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.certsrv.request.RequestIdAdapter;
+import com.netscape.certsrv.util.DateAdapter;
+
+/**
+ * @author Endi S. Dewata
+ */
+@XmlRootElement(name="CertRevokeRequest")
+public class CertRevokeRequest {
+
+    public static Marshaller marshaller;
+    public static Unmarshaller unmarshaller;
+
+    static {
+        try {
+            JAXBContext context = JAXBContext.newInstance(CertRevokeRequest.class);
+            marshaller = context.createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            unmarshaller = context.createUnmarshaller();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    RequestId requestID;
+    RevocationReason reason;
+    int totalRecordCount;
+    int verifiedRecordCount;
+    Date invalidityDate;
+    String comments;
+    String encoded;
+
+
+    @XmlElement(name="RequestID")
+    @FormParam("requestId")
+    @XmlJavaTypeAdapter(RequestIdAdapter.class)
+    public RequestId getRequestID() {
+        return requestID;
+    }
+
+    public void setRequestID(RequestId requestID) {
+        this.requestID = requestID;
+    }
+
+    @XmlElement(name="Reason")
+    @FormParam("revocationReason")
+    @XmlJavaTypeAdapter(RevocationReasonAdapter.class)
+    public RevocationReason getReason() {
+        return reason;
+    }
+
+    public void setReason(RevocationReason reason) {
+        this.reason = reason;
+    }
+
+    @XmlElement(name="TotalRecordCount")
+    @FormParam("totalRecordCount")
+    public int getTotalRecordCount() {
+        return totalRecordCount;
+    }
+
+    public void setTotalRecordCount(int totalRecordCount) {
+        this.totalRecordCount = totalRecordCount;
+    }
+
+    @XmlElement(name="VerifiedRecordCount")
+    @FormParam("verifiedRecordCount")
+    public int getVerifiedRecordCount() {
+        return verifiedRecordCount;
+    }
+
+    public void setVerifiedRecordCount(int verifiedRecordCount) {
+        this.verifiedRecordCount = verifiedRecordCount;
+    }
+
+    @XmlElement(name="InvalidityDate")
+    @FormParam("invalidityDate")
+    @XmlJavaTypeAdapter(DateAdapter.class)
+    public Date getInvalidityDate() {
+        return invalidityDate;
+    }
+
+    public void setInvalidityDate(Date invalidityDate) {
+        this.invalidityDate = invalidityDate;
+    }
+
+    @XmlElement(name="Comments")
+    @FormParam(IRequest.REQUESTOR_COMMENTS)
+    public String getComments() {
+        return comments;
+    }
+
+    public void setComments(String comments) {
+        this.comments = comments;
+    }
+
+    @XmlElement(name="Encoded")
+    @FormParam("b64eCertificate")
+    public String getEncoded() {
+        return encoded;
+    }
+
+    public void setEncoded(String encoded) {
+        this.encoded = encoded;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((comments == null) ? 0 : comments.hashCode());
+        result = prime * result + ((encoded == null) ? 0 : encoded.hashCode());
+        result = prime * result + ((invalidityDate == null) ? 0 : invalidityDate.hashCode());
+        result = prime * result + ((reason == null) ? 0 : reason.hashCode());
+        result = prime * result + ((requestID == null) ? 0 : requestID.hashCode());
+        result = prime * result + totalRecordCount;
+        result = prime * result + verifiedRecordCount;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        CertRevokeRequest other = (CertRevokeRequest) obj;
+        if (comments == null) {
+            if (other.comments != null)
+                return false;
+        } else if (!comments.equals(other.comments))
+            return false;
+        if (encoded == null) {
+            if (other.encoded != null)
+                return false;
+        } else if (!encoded.equals(other.encoded))
+            return false;
+        if (invalidityDate == null) {
+            if (other.invalidityDate != null)
+                return false;
+        } else if (!invalidityDate.equals(other.invalidityDate))
+            return false;
+        if (reason == null) {
+            if (other.reason != null)
+                return false;
+        } else if (!reason.equals(other.reason))
+            return false;
+        if (requestID == null) {
+            if (other.requestID != null)
+                return false;
+        } else if (!requestID.equals(other.requestID))
+            return false;
+        if (totalRecordCount != other.totalRecordCount)
+            return false;
+        if (verifiedRecordCount != other.verifiedRecordCount)
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static CertRevokeRequest valueOf(String string) throws Exception {
+        try {
+            return (CertRevokeRequest)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        CertRevokeRequest before = new CertRevokeRequest();
+        before.setRequestID(new RequestId("42323234"));
+        before.setReason(RevocationReason.CERTIFICATE_HOLD);
+        before.setTotalRecordCount(2);
+        before.setVerifiedRecordCount(3);
+        before.setInvalidityDate(new Date());
+        before.setComments("test");
+        before.setEncoded("test");
+
+        String string = before.toString();
+        System.out.println(string);
+
+        CertRevokeRequest after = CertRevokeRequest.valueOf(string);
+
+        System.out.println(before.equals(after));
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertUnrevokeRequest.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertUnrevokeRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..98d24d36367cc2c511e870d5f1baba8d3885b53b
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertUnrevokeRequest.java
@@ -0,0 +1,124 @@
+// --- 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.cert.model;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.ws.rs.FormParam;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.certsrv.request.RequestIdAdapter;
+
+/**
+ * @author Endi S. Dewata
+ */
+@XmlRootElement(name="CertUnrevokeRequest")
+public class CertUnrevokeRequest {
+
+    public static Marshaller marshaller;
+    public static Unmarshaller unmarshaller;
+
+    static {
+        try {
+            JAXBContext context = JAXBContext.newInstance(CertUnrevokeRequest.class);
+            marshaller = context.createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            unmarshaller = context.createUnmarshaller();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    RequestId requestID;
+
+    @XmlElement(name="requestID")
+    @FormParam("requestId")
+    @XmlJavaTypeAdapter(RequestIdAdapter.class)
+    public RequestId getRequestID() {
+        return requestID;
+    }
+
+    public void setRequestID(RequestId requestID) {
+        this.requestID = requestID;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((requestID == null) ? 0 : requestID.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        CertUnrevokeRequest other = (CertUnrevokeRequest) obj;
+        if (requestID == null) {
+            if (other.requestID != null)
+                return false;
+        } else if (!requestID.equals(other.requestID))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static CertUnrevokeRequest valueOf(String string) throws Exception {
+        try {
+            return (CertUnrevokeRequest)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        CertUnrevokeRequest before = new CertUnrevokeRequest();
+        before.setRequestID(new RequestId("42323234"));
+
+        String string = before.toString();
+        System.out.println(string);
+
+        CertUnrevokeRequest after = CertUnrevokeRequest.valueOf(string);
+
+        System.out.println(before.equals(after));
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java
index cb6ed937dc95700ca6cd8ecf4f7159ee12aca122..bfdb894cb199c238b00a45cd26a84f8d5b448bc3 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java
@@ -17,12 +17,20 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.servlet.cert.model;
 
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
 import com.netscape.certsrv.dbs.certdb.CertId;
 import com.netscape.certsrv.dbs.certdb.CertIdAdapter;
 
@@ -31,51 +39,62 @@ import com.netscape.certsrv.dbs.certdb.CertIdAdapter;
  *
  */
 @XmlRootElement(name = "CertificateData")
-@XmlAccessorType(XmlAccessType.FIELD)
 public class CertificateData {
-    @XmlElement
-    private String b64;
 
-    @XmlElement
-    private String prettyPrint;
+    public static Marshaller marshaller;
+    public static Unmarshaller unmarshaller;
 
-    @XmlElement
-    private String subjectName;
+    static {
+        try {
+            marshaller = JAXBContext.newInstance(CertificateData.class).createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            unmarshaller = JAXBContext.newInstance(CertificateData.class).createUnmarshaller();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
 
-    @XmlElement
-    private String pkcs7CertChain;
+    CertId serialNumber;
+    String issuerDN;
+    String subjectDN;
+    String prettyPrint;
+    String encoded;
+    String pkcs7CertChain;
+    String notBefore;
+    String notAfter;
+    String status;
 
-    @XmlElement
+    Link link;
+
+    @XmlAttribute(name="id")
     @XmlJavaTypeAdapter(CertIdAdapter.class)
-    private CertId serialNo;
-
-    @XmlElement
-    private String notBefore;
+    public CertId getSerialNumber() {
+        return serialNumber;
+    }
 
-    @XmlElement
-    private String notAfter;
+    public void setSerialNumber(CertId serialNumber) {
+        this.serialNumber = serialNumber;
+    }
 
-    @XmlElement
-    private String issuerName;
+    @XmlElement(name="IssuerDN")
+    public String getIssuerDN() {
+        return issuerDN;
+    }
 
-    public CertificateData() {
-        // required for jaxb
+    public void setIssuerDN(String issuerDN) {
+        this.issuerDN = issuerDN;
     }
 
-    /**
-     * @return the b64
-     */
-    public String getB64() {
-        return b64;
+    @XmlElement(name="SubjectDN")
+    public String getSubjectDN() {
+        return subjectDN;
     }
 
-    /**
-     * @param b64 the b64 to set
-     */
-    public void setB64(String b64) {
-        this.b64 = b64;
+    public void setSubjectDN(String subjectDN) {
+        this.subjectDN = subjectDN;
     }
 
+    @XmlElement(name="PrettyPrint")
     public String getPrettyPrint() {
         return prettyPrint;
     }
@@ -84,6 +103,16 @@ public class CertificateData {
         this.prettyPrint = prettyPrint;
     }
 
+    @XmlElement(name="Encoded")
+    public String getEncoded() {
+        return encoded;
+    }
+
+    public void setEncoded(String encoded) {
+        this.encoded = encoded;
+    }
+
+    @XmlElement(name="PKCS7CertChain")
     public void setPkcs7CertChain(String chain) {
         this.pkcs7CertChain = chain;
     }
@@ -92,22 +121,7 @@ public class CertificateData {
         return pkcs7CertChain;
     }
 
-    public String getSubjectName() {
-        return subjectName;
-    }
-
-    public void setSubjectName(String subjectName) {
-        this.subjectName = subjectName;
-    }
-
-    public CertId getSerialNo() {
-        return serialNo;
-    }
-
-    public void setSerialNo(CertId serialNo) {
-        this.serialNo = serialNo;
-    }
-
+    @XmlElement(name="NotBefore")
     public String getNotBefore() {
         return notBefore;
     }
@@ -116,6 +130,7 @@ public class CertificateData {
         this.notBefore = notBefore;
     }
 
+    @XmlElement(name="NotAfter")
     public String getNotAfter() {
         return notAfter;
     }
@@ -124,12 +139,145 @@ public class CertificateData {
         this.notAfter = notAfter;
     }
 
-    public String getIssuerName() {
-        return issuerName;
+    @XmlElement(name="Status")
+    public String getStatus() {
+        return status;
     }
 
-    public void setIssuerName(String issuerName) {
-        this.issuerName = issuerName;
+    public void setStatus(String status) {
+        this.status = status;
     }
 
+    @XmlElement(name="Link")
+    public Link getLink() {
+        return link;
+    }
+
+    public void setLink(Link link) {
+        this.link = link;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((encoded == null) ? 0 : encoded.hashCode());
+        result = prime * result + ((issuerDN == null) ? 0 : issuerDN.hashCode());
+        result = prime * result + ((notAfter == null) ? 0 : notAfter.hashCode());
+        result = prime * result + ((notBefore == null) ? 0 : notBefore.hashCode());
+        result = prime * result + ((pkcs7CertChain == null) ? 0 : pkcs7CertChain.hashCode());
+        result = prime * result + ((prettyPrint == null) ? 0 : prettyPrint.hashCode());
+        result = prime * result + ((serialNumber == null) ? 0 : serialNumber.hashCode());
+        result = prime * result + ((status == null) ? 0 : status.hashCode());
+        result = prime * result + ((subjectDN == null) ? 0 : subjectDN.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        CertificateData other = (CertificateData) obj;
+        if (encoded == null) {
+            if (other.encoded != null)
+                return false;
+        } else if (!encoded.equals(other.encoded))
+            return false;
+        if (issuerDN == null) {
+            if (other.issuerDN != null)
+                return false;
+        } else if (!issuerDN.equals(other.issuerDN))
+            return false;
+        if (notAfter == null) {
+            if (other.notAfter != null)
+                return false;
+        } else if (!notAfter.equals(other.notAfter))
+            return false;
+        if (notBefore == null) {
+            if (other.notBefore != null)
+                return false;
+        } else if (!notBefore.equals(other.notBefore))
+            return false;
+        if (pkcs7CertChain == null) {
+            if (other.pkcs7CertChain != null)
+                return false;
+        } else if (!pkcs7CertChain.equals(other.pkcs7CertChain))
+            return false;
+        if (prettyPrint == null) {
+            if (other.prettyPrint != null)
+                return false;
+        } else if (!prettyPrint.equals(other.prettyPrint))
+            return false;
+        if (serialNumber == null) {
+            if (other.serialNumber != null)
+                return false;
+        } else if (!serialNumber.equals(other.serialNumber))
+            return false;
+        if (status == null) {
+            if (other.status != null)
+                return false;
+        } else if (!status.equals(other.status))
+            return false;
+        if (subjectDN == null) {
+            if (other.subjectDN != null)
+                return false;
+        } else if (!subjectDN.equals(other.subjectDN))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static CertificateData valueOf(String string) throws Exception {
+        try {
+            return (CertificateData)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        StringWriter sw = new StringWriter();
+        PrintWriter out = new PrintWriter(sw, true);
+
+        out.println("-----BEGIN CERTIFICATE-----");
+        out.println("MIIB/zCCAWgCCQCtpWH58pqsejANBgkqhkiG9w0BAQUFADBEMRQwEgYDVQQKDAtF");
+        out.println("WEFNUExFLUNPTTEYMBYGCgmSJomT8ixkAQEMCHRlc3R1c2VyMRIwEAYDVQQDDAlU");
+        out.println("ZXN0IFVzZXIwHhcNMTIwNTE0MTcxNzI3WhcNMTMwNTE0MTcxNzI3WjBEMRQwEgYD");
+        out.println("VQQKDAtFWEFNUExFLUNPTTEYMBYGCgmSJomT8ixkAQEMCHRlc3R1c2VyMRIwEAYD");
+        out.println("VQQDDAlUZXN0IFVzZXIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKmmiPJp");
+        out.println("Agh/gPUAZjfgJ3a8QiHvpMzZ/hZy1FVP3+2sNhCkMv+D/I8Y7AsrbJGxxvD7bTDm");
+        out.println("zQYtYx2ryGyOgY7KBRxEj/IrNVHIkJMYq5G/aIU4FAzpc6ntNSwUQBYUAamfK8U6");
+        out.println("Wo4Cp6rLePXIDE6sfGn3VX6IeSJ8U2V+vwtzAgMBAAEwDQYJKoZIhvcNAQEFBQAD");
+        out.println("gYEAY9bjcD/7Z+oX6gsJtX6Rd79E7X5IBdOdArYzHNE4vjdaQrZw6oCxrY8ffpKC");
+        out.println("0T0q5PX9I7er+hx/sQjGPMrJDEN+vFBSNrZE7sTeLRgkyiqGvChSyuG05GtGzXO4");
+        out.println("bFBr+Gwk2VF2wJvOhTXU2hN8sfkkd9clzIXuL8WCDhWk1bY=");
+        out.println("-----END CERTIFICATE-----");
+
+        CertificateData before = new CertificateData();
+        before.setSerialNumber(new CertId("12512514865863765114"));
+        before.setIssuerDN("CN=Test User,UID=testuser,O=EXAMPLE-COM");
+        before.setSubjectDN("CN=Test User,UID=testuser,O=EXAMPLE-COM");
+        before.setEncoded(sw.toString());
+
+        String string = before.toString();
+        System.out.println(string);
+
+        CertificateData after = CertificateData.valueOf(string);
+        System.out.println(before.equals(after));
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java b/base/common/src/com/netscape/cms/servlet/processors/Processor.java
similarity index 57%
copy from base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
copy to base/common/src/com/netscape/cms/servlet/processors/Processor.java
index cfafff0642a64dfce5a488940bfd0931916bc98a..8cdbbc1d8d9b190f1a01adcd3572cc5e1f669d0c 100644
--- a/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
+++ b/base/common/src/com/netscape/cms/servlet/processors/Processor.java
@@ -12,26 +12,33 @@
 // 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.
+// (C) 2012 Red Hat, Inc.
 // All rights reserved.
 // --- END COPYRIGHT BLOCK ---
-package com.netscape.certsrv.dbs.certdb;
 
-import javax.xml.bind.annotation.adapters.XmlAdapter;
+package com.netscape.cms.servlet.processors;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.logging.IAuditor;
+import com.netscape.certsrv.logging.ILogger;
 
 /**
- * The CertIdAdapter class provides custom marshaling for CertId.
- *
  * @author Endi S. Dewata
- * @version $Revision$ $Date$
  */
-public class CertIdAdapter extends XmlAdapter<String, CertId> {
+public class Processor {
 
-    public CertId unmarshal(String value) throws Exception {
-        return new CertId(value);
-    }
+    protected ILogger logger = CMS.getLogger();
+    protected IAuditor auditor = CMS.getAuditor();
+
+    public void log(int source, int level, String message) {
 
-    public String marshal(CertId value) throws Exception {
-        return value.toString();
+        if (logger == null) return;
+
+        logger.log(ILogger.EV_SYSTEM,
+                null,
+                source,
+                level,
+                getClass().getSimpleName() + ": " + message);
     }
+
 }
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
index 772612bf494683e70448c2cbdcea4392082404cf..cd25d7b78338a803a16bbc0d8e64a8e0fcc1c8ce 100644
--- a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
@@ -49,7 +49,7 @@ public class DRMRestClient  extends CMSRestClient {
         ClientResponse<CertificateData> response = (ClientResponse<CertificateData>) systemCertClient
                 .getTransportCert();
         CertificateData certData = response.getEntity();
-        String transportCert = certData.getB64();
+        String transportCert = certData.getEncoded();
         return transportCert;
     }
 
diff --git a/base/util/src/CMakeLists.txt b/base/util/src/CMakeLists.txt
index f0c586ad6f82f1bf0214a766b2af74bf7b5d79be..24622d6c40e8962ffa329644011f167076f964d6 100644
--- a/base/util/src/CMakeLists.txt
+++ b/base/util/src/CMakeLists.txt
@@ -1,5 +1,12 @@
 project(pki-cmsutil_java Java)
 
+find_file(APACHE_COMMONS_LANG_JAR
+    NAMES
+        apache-commons-lang.jar
+    PATHS
+        /usr/share/java
+)
+
 find_file(JSS_JAR
     NAMES
         jss4.jar
@@ -106,6 +113,7 @@ set(pki-nsutil_java_SRCS
     netscape/security/x509/URIName.java
     netscape/security/x509/CertAndKeyGen.java
     netscape/security/x509/RevocationReason.java
+    netscape/security/x509/RevocationReasonAdapter.java
     netscape/security/x509/AVAValueConverter.java
     netscape/security/x509/CRLDistributionPointsExtension.java
     netscape/security/x509/GeneralSubtree.java
@@ -328,7 +336,7 @@ set(pki-cmsutil_java_SRCS
 )
 
 set(CMAKE_JAVA_INCLUDE_PATH
-    ${LDAPJDK_JAR} ${XALAN_JAR} ${XERCES_JAR}
+    ${APACHE_COMMONS_LANG_JAR} ${LDAPJDK_JAR} ${XALAN_JAR} ${XERCES_JAR}
     ${JSS_JAR} ${COMMONS_CODEC_JAR})
 
 set(CMAKE_JAVA_TARGET_VERSION ${APPLICATION_VERSION})
diff --git a/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java b/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java
index 4409ddeaf3107a61008727b428293ce84374a975..de8569e4de33fed2819a7d915cfeb2bdc77a09d9 100644
--- a/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java
+++ b/base/util/src/com/netscape/cmsutil/ldap/LDAPUtil.java
@@ -45,9 +45,9 @@ public class LDAPUtil {
      * @param string string to escape
      * @return escaped string
      */
-    public static String escapeFilter(String string) {
+    public static String escapeFilter(Object object) {
         StringBuilder sb = new StringBuilder();
-        for (char c : string.toCharArray()) {
+        for (char c : object.toString().toCharArray()) {
             if (SPECIAL_CHARS.indexOf(c) >= 0) {
                 sb.append('\\');
                 if (c < 0x10)
diff --git a/base/util/src/netscape/security/x509/RevocationReason.java b/base/util/src/netscape/security/x509/RevocationReason.java
index cbd7fe73d0cb0f2104fc15ca61a4a85dcab2d3b4..27fe2cf143d48d7f323d0b6c6bab1b0dcb50e589 100644
--- a/base/util/src/netscape/security/x509/RevocationReason.java
+++ b/base/util/src/netscape/security/x509/RevocationReason.java
@@ -17,6 +17,9 @@
 // --- END COPYRIGHT BLOCK ---
 package netscape.security.x509;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
+
 /**
  * Represent the enumerated type used in CRLReason Extension of CRL entry.
  *
@@ -26,94 +29,95 @@ package netscape.security.x509;
  */
 
 public final class RevocationReason {
+
+    public static final Map<Integer, RevocationReason> REASONS_BY_CODE = new LinkedHashMap<Integer, RevocationReason>();
+    public static final Map<String, RevocationReason> REASONS_BY_LABEL = new LinkedHashMap<String, RevocationReason>();
+
     /**
      * Reasons
      */
-    public static final RevocationReason UNSPECIFIED = new RevocationReason(0);
-    public static final RevocationReason KEY_COMPROMISE = new RevocationReason(1);
-    public static final RevocationReason CA_COMPROMISE = new RevocationReason(2);
-    public static final RevocationReason AFFILIATION_CHANGED = new RevocationReason(3);
-    public static final RevocationReason SUPERSEDED = new RevocationReason(4);
-    public static final RevocationReason CESSATION_OF_OPERATION = new RevocationReason(5);
-    public static final RevocationReason CERTIFICATE_HOLD = new RevocationReason(6);
-    public static final RevocationReason REMOVE_FROM_CRL = new RevocationReason(8);
-    public static final RevocationReason PRIVILEGE_WITHDRAWN = new RevocationReason(9);
-    public static final RevocationReason AA_COMPROMISE = new RevocationReason(10);
+    public static final RevocationReason UNSPECIFIED = new RevocationReason(0, "Unspecified");
+    public static final RevocationReason KEY_COMPROMISE = new RevocationReason(1, "Key_Compromise");
+    public static final RevocationReason CA_COMPROMISE = new RevocationReason(2, "CA_Compromise");
+    public static final RevocationReason AFFILIATION_CHANGED = new RevocationReason(3, "Affiliation_Changed");
+    public static final RevocationReason SUPERSEDED = new RevocationReason(4, "Superseded");
+    public static final RevocationReason CESSATION_OF_OPERATION = new RevocationReason(5, "Cessation_of_Operation");
+    public static final RevocationReason CERTIFICATE_HOLD = new RevocationReason(6, "Certificate_Hold");
+    public static final RevocationReason REMOVE_FROM_CRL = new RevocationReason(8, "Remove_from_CRL");
+    public static final RevocationReason PRIVILEGE_WITHDRAWN = new RevocationReason(9, "Privilege_Withdrawn");
+    public static final RevocationReason AA_COMPROMISE = new RevocationReason(10, "AA_Compromise");
 
     // Private data members
-    private int mReason;
+    private int code;
+    private String label;
 
     /**
-     * Create a RevocationReason with the passed integer value.
+     * Create a RevocationReason with the passed integer value and string label.
      *
      * @param reason integer value of the enumeration alternative.
+     * @param label string value of the enumeration alternative.
      */
-    private RevocationReason(int reason) {
-        this.mReason = reason;
+    private RevocationReason(int reason, String label) {
+        this.code = reason;
+        this.label = label;
+
+        REASONS_BY_CODE.put(reason, this);
+        REASONS_BY_LABEL.put(label.toLowerCase(), this);
+    }
+
+    public int getCode() {
+        return code;
     }
 
-    public int toInt() {
-        return mReason;
+    public String getLabel() {
+        return label;
     }
 
     public static RevocationReason fromInt(int reason) {
-        if (reason == UNSPECIFIED.mReason)
-            return UNSPECIFIED;
-        if (reason == KEY_COMPROMISE.mReason)
-            return KEY_COMPROMISE;
-        if (reason == CA_COMPROMISE.mReason)
-            return CA_COMPROMISE;
-        if (reason == AFFILIATION_CHANGED.mReason)
-            return AFFILIATION_CHANGED;
-        if (reason == SUPERSEDED.mReason)
-            return SUPERSEDED;
-        if (reason == CESSATION_OF_OPERATION.mReason)
-            return CESSATION_OF_OPERATION;
-        if (reason == CERTIFICATE_HOLD.mReason)
-            return CERTIFICATE_HOLD;
-        if (reason == REMOVE_FROM_CRL.mReason)
-            return REMOVE_FROM_CRL;
-        if (reason == PRIVILEGE_WITHDRAWN.mReason)
-            return PRIVILEGE_WITHDRAWN;
-        if (reason == AA_COMPROMISE.mReason)
-            return AA_COMPROMISE;
-        return null;
+        return valueOf(reason);
     }
 
-    public boolean equals(Object other) {
-        if (this == other)
+    public static RevocationReason valueOf(int reason) {
+        return REASONS_BY_CODE.get(reason);
+    }
+
+    public static RevocationReason valueOf(String string) {
+        return REASONS_BY_LABEL.get(string.toLowerCase());
+    }
+
+    public int toInt() {
+        return code;
+    }
+
+    public String toString() {
+        return label;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
             return true;
-        else if (other instanceof RevocationReason)
-            return ((RevocationReason) other).mReason == mReason;
-        else
+        if (obj == null)
             return false;
+        if (getClass() != obj.getClass())
+            return false;
+        RevocationReason other = (RevocationReason) obj;
+        if (code != other.code)
+            return false;
+        if (label == null) {
+            if (other.label != null)
+                return false;
+        } else if (!label.equals(other.label))
+            return false;
+        return true;
     }
 
+    @Override
     public int hashCode() {
-        return mReason;
-    }
-
-    public String toString() {
-        if (equals(UNSPECIFIED))
-            return "Unspecified";
-        if (equals(KEY_COMPROMISE))
-            return "Key_Compromise";
-        if (equals(CA_COMPROMISE))
-            return "CA_Compromise";
-        if (equals(AFFILIATION_CHANGED))
-            return "Affiliation_Changed";
-        if (equals(SUPERSEDED))
-            return "Superseded";
-        if (equals(CESSATION_OF_OPERATION))
-            return "Cessation_of_Operation";
-        if (equals(CERTIFICATE_HOLD))
-            return "Certificate_Hold";
-        if (equals(REMOVE_FROM_CRL))
-            return "Remove_from_CRL";
-        if (equals(PRIVILEGE_WITHDRAWN))
-            return "Privilege_Withdrawn";
-        if (equals(AA_COMPROMISE))
-            return "AA_Compromise";
-        return "[UNDEFINED]";
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + code;
+        result = prime * result + ((label == null) ? 0 : label.hashCode());
+        return result;
     }
 }
diff --git a/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java b/base/util/src/netscape/security/x509/RevocationReasonAdapter.java
similarity index 60%
copy from base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
copy to base/util/src/netscape/security/x509/RevocationReasonAdapter.java
index cfafff0642a64dfce5a488940bfd0931916bc98a..e9445bb4338c21e18d5d360f8f9aaf37d4b9b1a1 100644
--- a/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
+++ b/base/util/src/netscape/security/x509/RevocationReasonAdapter.java
@@ -12,26 +12,27 @@
 // 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.
+// (C) 2012 Red Hat, Inc.
 // All rights reserved.
 // --- END COPYRIGHT BLOCK ---
-package com.netscape.certsrv.dbs.certdb;
+package netscape.security.x509;
 
 import javax.xml.bind.annotation.adapters.XmlAdapter;
 
+import org.apache.commons.lang.StringUtils;
+
 /**
- * The CertIdAdapter class provides custom marshaling for CertId.
+ * The RevocationReasonAdapter class provides custom marshaling for RevocationReason.
  *
  * @author Endi S. Dewata
- * @version $Revision$ $Date$
  */
-public class CertIdAdapter extends XmlAdapter<String, CertId> {
+public class RevocationReasonAdapter extends XmlAdapter<String, RevocationReason> {
 
-    public CertId unmarshal(String value) throws Exception {
-        return new CertId(value);
+    public RevocationReason unmarshal(String value) throws Exception {
+        return StringUtils.isEmpty(value) ? null : RevocationReason.valueOf(value);
     }
 
-    public String marshal(CertId value) throws Exception {
-        return value.toString();
+    public String marshal(RevocationReason value) throws Exception {
+        return value == null ? null : value.toString();
     }
-}
+}
\ No newline at end of file
-- 
1.7.7.6

