>From c6a7a2024cddfb47a17e2c0f0309b93b656e8f53 Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu@redhat.com>
Date: Tue, 30 May 2017 14:12:06 -0700
Subject: [PATCH] Ticket #2619 Allow CA to process user-signed CMC revocation
 requests First of all, the original CMC revocation only supports agent-signed
 CMC revocation requests from the UI where CMCRevReqServlet handles it with
 CMCAuth.  It is in violation with https://tools.ietf.org/html/rfc5273 CMC
 Transport Protocols, as for HTTP/HTTPS, the body of the message is the binary
 value of the BER encoding of the PKI Request or Response,so HTML is not an
 approved method.The other way is through profileSubmitCMCFullServlet (or
 maybe not, as it was completely broken).

One thing that's much less crucial, but goes along with rfc update is the name of the revocation request ASN1 structure. In the new rfc5272, it is now called RevokeRequest insead of RevRequest.

This patch revamped the CMC revocation provision and fixing what's broken and adding what's missing.

On the client side:

CMCRequest

- Commented out the code where it made an assumption to use OtherMsg for the signer information. This makes no sense as the outer layer SignedData would have the same information when signing happens.

- removed the revRequest.nickname parameter from the configuration.  From the code it seems like it expects the certificate to be revoked to exist in the user database, and it uses the same certificate to sign the revocation request.  The RFC does allow for self-signed revocation, but it also allows for signing with another certificate provided that it has same subject.  By removing the revRequest.nickname parameter, I am using the "nickname" parameter as the signer cert, which may or may not be the same certificate specified in revRequest.serial.  It is less confusing. The change also eliminate the need for the cert to be revoked to be present in the db.  In addition, revRequest.issuer only needs to be specified if revRequest.sharedSecret is used. The code will extract the issuer info from the signing cert.

- added support for unsigned data in support of shared secret in both CMCRequest and server;  The original code assumed that a cmc revocation request that relies on shared secret still requires agent signing.

CMCRevoke

- The original code assumed that the nss db password is the same as Shared Secret (!!).  This patch added a "-t" to accept shred secret, and keep the -p for the nss db password.

- The original code printed out b64 encoded request to the screen output as well as the file CMCRevoke.out.  Both are unusable directly.  This patch fixes it so that the output to the screen can be directly copied and pasted into the CMC revocate ui at ee (processed by CMCRevReqServlet);  Again, this is not RFC conforming, but I fixed it anyways;

- The output to the file CMCRevoke.out has been fixed so that it is the BER encoding of the request, which can be fed directly into the updated server that now conforms to the RFC (see below)

- This code still requires the signer certificate nickname to run, making the shared secret method moot.  Since CMCRequest has been updated to work properly, we can leave this for now.

On the server side.

CMCUserSignedAuth has been updated to handle unsigned DATA;  Recall that the original CMC revocation only handled SIGNED_DATA (making assumption that agent always signs the requests).  This addition is important to support shared secrets properly.

Another thing that's important change on the server side is that it now checks the revoking cert's subject against the signer's subject, if authenticated by CMCUserSignedAuth.  The original code did not do that, I think it is because it always checks if it's an agent or not.

Something that could be improved on is to have its own servlet.  However, due to the time restriction, I only updated existing EnrollProfile, ProfileSubmitCMCServlet, and CMCOutputTemplate to handle the rfc conforming cmc revocation requests.

The shared secret handling is left in the CMCOutputTemplate for now.  Logically it would make sense to go into CMCUserSignedAuth. This could be left as a possible later ticket for improvement.   Shared Token plugin implementation will be added in later ticket as well.

Previously missed signing cert validation is also added for more complete check.
Some SHA1 are turned into SHA2

Finally, some auditing are added, but it is not finalized.  It will be done in the next ticket(s).
---
 base/common/src/com/netscape/certsrv/apps/CMS.java |  10 +
 .../src/com/netscape/certsrv/apps/ICMSEngine.java  |   8 +
 .../com/netscape/certsrv/base/SessionContext.java  |   5 +
 .../src/com/netscape/cmstools/CMCRequest.java      | 245 ++++++++-----
 .../src/com/netscape/cmstools/CMCRevoke.java       | 133 +++----
 .../com/netscape/cms/authentication/CMCAuth.java   |  19 +-
 .../cms/authentication/CMCUserSignedAuth.java      | 198 +++++-----
 .../netscape/cms/profile/common/EnrollProfile.java |  80 ++--
 .../cms/servlet/cert/CMCRevReqServlet.java         |   4 +-
 .../com/netscape/cms/servlet/cert/ListCerts.java   |  10 +-
 .../cms/servlet/common/CMCOutputTemplate.java      | 407 +++++++++++++++------
 .../servlet/common/GenPendingTemplateFiller.java   |  15 +-
 .../servlet/profile/ProfileSubmitCMCServlet.java   |  12 +-
 .../src/com/netscape/cmscore/apps/CMSEngine.java   |  33 ++
 .../netscape/cmscore/app/CMSEngineDefaultStub.java |   5 +
 base/util/src/com/netscape/cmsutil/util/Utils.java |   5 +
 16 files changed, 763 insertions(+), 426 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/apps/CMS.java b/base/common/src/com/netscape/certsrv/apps/CMS.java
index cc634cc..9df99ab 100644
--- a/base/common/src/com/netscape/certsrv/apps/CMS.java
+++ b/base/common/src/com/netscape/certsrv/apps/CMS.java
@@ -36,6 +36,7 @@ import org.dogtagpki.legacy.policy.ISubjAltNameConfig;
 import org.mozilla.jss.CryptoManager.CertificateUsage;
 import org.mozilla.jss.util.PasswordCallback;
 
+import com.netscape.certsrv.authentication.ISharedToken;
 import com.netscape.certsrv.acls.EACLsException;
 import com.netscape.certsrv.acls.IACL;
 import com.netscape.certsrv.authentication.IAuthSubsystem;
@@ -1575,6 +1576,15 @@ public final class CMS {
     }
 
     /**
+     * Retrieves the SharedToken class.
+     *
+     * @return named SharedToken class
+     */
+    public static ISharedToken getSharedTokenClass(String configName) {
+        return _engine.getSharedTokenClass(configName);
+    }
+
+    /**
      * Puts a password entry into the single-sign on cache.
      *
      * @param tag password tag
diff --git a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
index 3655b03..563b7c9 100644
--- a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
+++ b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
@@ -38,6 +38,7 @@ import org.mozilla.jss.util.PasswordCallback;
 
 import com.netscape.certsrv.acls.EACLsException;
 import com.netscape.certsrv.acls.IACL;
+import com.netscape.certsrv.authentication.ISharedToken;
 import com.netscape.certsrv.authority.IAuthority;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IArgBlock;
@@ -681,6 +682,13 @@ public interface ICMSEngine extends ISubsystem {
     public ILdapConnFactory getLdapAnonConnFactory(String id) throws ELdapException;
 
     /**
+     * Retrieves the named SharedToken class
+     *
+     * @return named shared token class
+     */
+    public ISharedToken getSharedTokenClass(String configName);
+
+    /**
      * Retrieves the password check.
      *
      * @return default password checker
diff --git a/base/common/src/com/netscape/certsrv/base/SessionContext.java b/base/common/src/com/netscape/certsrv/base/SessionContext.java
index 81debae..8bcb3c1 100644
--- a/base/common/src/com/netscape/certsrv/base/SessionContext.java
+++ b/base/common/src/com/netscape/certsrv/base/SessionContext.java
@@ -53,6 +53,11 @@ public class SessionContext extends Hashtable<Object, Object> {
     public static final String AUTH_MANAGER_ID = "authManagerId"; // String
 
     /**
+     * Principal name object of the signed CMC request
+     */
+    public static final String CMC_SIGNER_PRINCIPAL = "cmcSignerPrincipal";
+
+    /**
      * User object of the authenticated user in the current thread.
      */
     public static final String USER = "user"; // IUser
diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
index 8d49b20..ca3f80f 100644
--- a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
+++ b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
@@ -71,15 +71,14 @@ import org.mozilla.jss.pkix.cmc.GetCert;
 import org.mozilla.jss.pkix.cmc.IdentityProofV2;
 import org.mozilla.jss.pkix.cmc.LraPopWitness;
 import org.mozilla.jss.pkix.cmc.OtherInfo;
-import org.mozilla.jss.pkix.cmc.OtherMsg;
 import org.mozilla.jss.pkix.cmc.PKIData;
 import org.mozilla.jss.pkix.cmc.PendInfo;
 import org.mozilla.jss.pkix.cmc.PopLinkWitnessV2;
 import org.mozilla.jss.pkix.cmc.ResponseBody;
+import org.mozilla.jss.pkix.cmc.RevokeRequest;
 import org.mozilla.jss.pkix.cmc.TaggedAttribute;
 import org.mozilla.jss.pkix.cmc.TaggedCertificationRequest;
 import org.mozilla.jss.pkix.cmc.TaggedRequest;
-import org.mozilla.jss.pkix.cmmf.RevRequest;
 import org.mozilla.jss.pkix.cms.ContentInfo;
 import org.mozilla.jss.pkix.cms.EncapsulatedContentInfo;
 import org.mozilla.jss.pkix.cms.EncryptedContentInfo;
@@ -373,14 +372,24 @@ public class CMCRequest {
 
     /**
      * getCMCBlob create and return the enrollment request.
-     *
+     * It now handles two types of data input:
+     *  - SignedData (which is for signed data)
+     *  - data (which is for unsigned data)
      * @return the CMC enrollment request encoded in base64
      *
      */
-    static ContentInfo getCMCBlob(SignedData req) {
+    static ContentInfo getCMCBlob(SignedData signedData, byte[] data) {
         String method = "getCMCBlob: ";
         System.out.println(method + "begins");
-        ContentInfo fullEnrollmentReq = new ContentInfo(req);
+        ContentInfo fullEnrollmentReq = null;
+        if (signedData != null) {
+            System.out.println("getCMCBlob: generating signed data");
+            fullEnrollmentReq = new ContentInfo(signedData);
+        } else if (data != null) {
+            System.out.println("getCMCBlob: generating unsigned data");
+            fullEnrollmentReq = new ContentInfo(data);
+        }
+
         try {
             ByteArrayOutputStream bs = new ByteArrayOutputStream();
             PrintStream ps = new PrintStream(bs);
@@ -767,29 +776,32 @@ public class CMCRequest {
         System.out.println("");
         System.out.println("#input: full path for the PKCS10 request or CRMF request,");
         System.out.println("#the content must be in Base-64 encoded format");
-        System.out.println("#Multiple files are supported. They must be separated by space.");
+//        System.out.println("#Multiple files are supported. They must be separated by space.");
+        System.out.println("# in case of revocation, input will be ignored");
         System.out.println("input=crmf.req");
         System.out.println("");
         System.out.println("#output: full path for the CMC request in binary format");
         System.out.println("output=cmc.req");
         System.out.println("");
-        System.out.println("#tokenname: name of token where agent signing cert can be found (default is internal)");
+        System.out.println("#tokenname: name of token where user signing cert can be found (default is internal)");
         System.out.println("tokenname=internal");
         System.out.println("");
-        System.out.println("#nickname: nickname for agent certificate which will be used");
-        System.out.println("#to sign the CMC full request.");
+        System.out.println("#nickname: nickname for user certificate which will be used");
+        System.out.println("#to sign the CMC full request (enrollment or revocation).");
+        System.out.println("");
         System.out.println("#selfSign: if selfSign is true, the CMC request will be");
-        System.out.println("#signed with the pairing private key of the request;");
+        System.out.println("#signed with the pairing private key of the enrollment request;");
         System.out.println("#and in which case the nickname will be ignored");
-        System.out.println("nickname=CMS Agent Certificate");
+        System.out.println("#If revRequest.sharedSecret is specified, then nickname will also be ignored.");
+        System.out.println("nickname=CMS User Signing Certificate");
         System.out.println("");
         System.out.println("selfSign=false");
         System.out.println("");
         System.out.println("#dbdir: directory for cert8.db, key3.db and secmod.db");
         System.out.println("dbdir=./");
         System.out.println("");
-        System.out.println("#password: password for cert8.db which stores the agent");
-        System.out.println("#certificate");
+        System.out.println("#password: password for cert8.db which stores the user signing");
+        System.out.println("#certificate and keys");
         System.out.println("password=pass");
         System.out.println("");
         System.out.println("#format: request format, either pkcs10 or crmf");
@@ -843,13 +855,19 @@ public class CMCRequest {
         System.out.println("#control. Otherwise, false.");
         System.out.println("revRequest.enable=false");
         System.out.println("");
+/*
         System.out.println("#revRequest.nickname: The nickname for the revoke certificate");
         System.out.println("revRequest.nickname=newuser's 102504a ID");
         System.out.println("");
+*/
         System.out.println("#revRequest.issuer: The issuer name for the certificate being");
-        System.out.println("#revoked.");
+        System.out.println("#revoked. It only needs to be specified when the request is unsigned,;");
+        System.out.println("#as in the case when sharedSecret is used;");
         System.out.println("revRequest.issuer=cn=Certificate Manager,c=us");
         System.out.println("");
+        System.out.println("#revRequest.sharedSecret: The sharedSecret");
+        System.out.println("revRequest.sharedSecret=");
+        System.out.println("");
         System.out.println("#revRequest.serial: The serial number for the certificate being");
         System.out.println("#revoked.");
         System.out.println("revRequest.serial=61");
@@ -860,9 +878,6 @@ public class CMCRequest {
         System.out.println("#                   certificateHold, removeFromCRL");
         System.out.println("revRequest.reason=unspecified");
         System.out.println("");
-        System.out.println("#revRequest.sharedSecret: The sharedSecret");
-        System.out.println("revRequest.sharedSecret=");
-        System.out.println("");
         System.out.println("#revRequest.comment: The human readable comment");
         System.out.println("revRequest.comment=");
         System.out.println("");
@@ -971,27 +986,27 @@ public class CMCRequest {
 
     private static ENUMERATED toCRLReason(String str) {
         if (str.equalsIgnoreCase("unspecified")) {
-            return RevRequest.unspecified;
+            return RevokeRequest.unspecified;
         } else if (str.equalsIgnoreCase("keyCompromise")) {
-            return RevRequest.keyCompromise;
+            return RevokeRequest.keyCompromise;
         } else if (str.equalsIgnoreCase("caCompromise")) {
-            return RevRequest.cACompromise;
+            return RevokeRequest.cACompromise;
         } else if (str.equalsIgnoreCase("affiliationChanged")) {
-            return RevRequest.affiliationChanged;
+            return RevokeRequest.affiliationChanged;
         } else if (str.equalsIgnoreCase("superseded")) {
-            return RevRequest.superseded;
+            return RevokeRequest.superseded;
         } else if (str.equalsIgnoreCase("cessationOfOperation")) {
-            return RevRequest.cessationOfOperation;
+            return RevokeRequest.cessationOfOperation;
         } else if (str.equalsIgnoreCase("certificateHold")) {
-            return RevRequest.certificateHold;
+            return RevokeRequest.certificateHold;
         } else if (str.equalsIgnoreCase("removeFromCRL")) {
-            return RevRequest.removeFromCRL;
+            return RevokeRequest.removeFromCRL;
         }
 
         System.out.println("Unrecognized CRL reason");
         System.exit(1);
 
-        return RevRequest.unspecified;
+        return RevokeRequest.unspecified;
     }
 
     /**
@@ -1118,42 +1133,84 @@ public class CMCRequest {
         return bpid;
     }
 
-    private static int addRevRequestAttr(int bpid, SEQUENCE seq, SEQUENCE otherMsgSeq, CryptoToken token, String tokenName, String nickname,
+    /*
+    * addRevRequestAttr adds the RevokeRequest control
+    * If sharedSecret exist, issuer name needs to be supplied;
+    * else signing cert is needed to extract issuerName
+    */
+    private static int addRevRequestAttr(int bpid, SEQUENCE seq,
+            CryptoToken token, X509Certificate revokeSignCert,
             String revRequestIssuer, String revRequestSerial, String revRequestReason,
             String revRequestSharedSecret, String revRequestComment, String invalidityDatePresent,
             CryptoManager manager) {
+
+        String method = "addRevRequestAttr: ";
         try {
-            if (nickname.length() <= 0) {
-                System.out.println("The nickname for the certificate being revoked is null");
-                System.exit(1);
-            }
-            String nickname1 = nickname;
             UTF8String comment = null;
             OCTET_STRING sharedSecret = null;
             GeneralizedTime d = null;
-            X500Name subjectname = new X500Name(revRequestIssuer);
+            X500Name issuerName = null;
+
+            if ((revRequestSerial == null) || (revRequestSerial.length() <= 0)) {
+                System.out.println(method + "revocation serial number must be supplied");
+                System.exit(1);
+            }
+            if ((revRequestReason == null) || (revRequestReason.length() <= 0)) {
+                System.out.println(method + "revocation reason must be supplied");
+                System.exit(1);
+            }
             INTEGER snumber = new INTEGER(revRequestSerial);
             ENUMERATED reason = toCRLReason(revRequestReason);
-            if (revRequestSharedSecret.length() > 0)
+
+            if ((revRequestSharedSecret != null) && (revRequestSharedSecret.length() > 0)) {
                 sharedSecret = new OCTET_STRING(revRequestSharedSecret.getBytes());
-            if (revRequestComment.length() > 0)
+                // in case of sharedSecret,
+                // issuer name will have to be provided;
+                // revokeSignCert is ignored;
+                if (revRequestIssuer == null) {
+                    System.out.println(method + "issuer name must be supplied when shared secret is used");
+                    System.exit(1);
+                }
+                issuerName = new X500Name(revRequestIssuer);
+            } else { // signing case; revokeSignCert is required
+                if (revokeSignCert == null) {
+                    System.out.println(method + "revokeSignCert must be supplied in the signing case");
+                    System.exit(1);
+                }
+            }
+
+            if (revRequestComment != null && revRequestComment.length() > 0)
                 comment = new UTF8String(revRequestComment);
             if (invalidityDatePresent.equals("true"))
                 d = new GeneralizedTime(new Date());
-            RevRequest revRequest =
-                    new RevRequest(new ANY(subjectname.getEncoded()), snumber,
-                            reason, d, sharedSecret, comment);
-            int revokeBpid = bpid;
+
+            if (sharedSecret == null) {
+                System.out.println(method + "no sharedSecret found; request will be signed;");
+
+                // getting issuerName from revokeSignCert
+                byte[] certB = revokeSignCert.getEncoded();
+                X509CertImpl impl = new X509CertImpl(certB);
+                issuerName = (X500Name) impl.getIssuerDN();
+            } else {
+                System.out.println(method + "sharedSecret found; request will be unsigned;");
+            }
+
+            RevokeRequest revRequest = new RevokeRequest(new ANY(issuerName.getEncoded()), snumber,
+                    reason, d, sharedSecret, comment);
+
             TaggedAttribute revRequestControl = new TaggedAttribute(
                     new INTEGER(bpid++),
                     OBJECT_IDENTIFIER.id_cmc_revokeRequest, revRequest);
             seq.addElement(revRequestControl);
+            System.out.println(method + "RevokeRequest control created.");
 
-            if (sharedSecret != null) {
-                System.out.println("Successfully create revRequest control. bpid = " + (bpid - 1));
-                System.out.println("");
-                return bpid;
-            }
+            return bpid;
+/*
+ * Constructing OtherMsg to include the SignerInfo makes no sense here
+ * as the outer layer SignedData would have SignerInfo.
+ * It is possibly done because the original code assumed a self-signed
+ * revocation request that is subsequently signed by an agent...
+ * which is not conforming to the RFC.
 
             EncapsulatedContentInfo revokeContent = new EncapsulatedContentInfo(
                     OBJECT_IDENTIFIER.id_cct_PKIData, revRequestControl);
@@ -1240,6 +1297,7 @@ public class CMCRequest {
             otherMsgSeq.addElement(otherMsg);
             System.out.println("Successfully create revRequest control. bpid = " + (bpid - 1));
             System.out.println("");
+*/
         } catch (Exception e) {
             System.out.println("Error in creating revRequest control. Check the parameters. Exception="+ e.toString());
             System.exit(1);
@@ -1345,9 +1403,9 @@ public class CMCRequest {
             String salt = "lala123" + date.toString();
 
             try {
-                MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+                MessageDigest SHA256Digest = MessageDigest.getInstance("SHA256");
 
-                dig = SHA1Digest.digest(salt.getBytes());
+                dig = SHA256Digest.digest(salt.getBytes());
             } catch (NoSuchAlgorithmException ex) {
                 dig = salt.getBytes();
             }
@@ -1822,7 +1880,6 @@ public class CMCRequest {
         String dataReturnEnable = "false", dataReturnData = null;
         String transactionMgtEnable = "false", transactionMgtId = null;
         String senderNonceEnable = "false", senderNonce = null;
-        String revCertNickname = "";
         String revRequestEnable = "false", revRequestIssuer = null, revRequestSerial = null;
         String revRequestReason = null, revRequestSharedSecret = null, revRequestComment = null;
         String revRequestInvalidityDatePresent = "false";
@@ -1938,8 +1995,6 @@ public class CMCRequest {
                         revRequestComment = val;
                     } else if (name.equals("revRequest.invalidityDatePresent")) {
                         revRequestInvalidityDatePresent = val;
-                    } else if (name.equals("revRequest.nickname")) {
-                        revCertNickname = val;
                     } else if (name.equals("identification.enable")) {
                         identificationEnable = val;
                     } else if (name.equals("identification")) {
@@ -1982,7 +2037,8 @@ public class CMCRequest {
             printUsage();
         }
 
-        if (!selfSign.equals("true") && nickname == null) {
+        if ((!selfSign.equals("true") && (revRequestSharedSecret == null))
+                && nickname == null) {
             System.out.println("Missing nickname.");
             printUsage();
         }
@@ -2028,11 +2084,12 @@ public class CMCRequest {
                 certname.append(tokenName);
                 certname.append(":");
             }
-            if (!selfSign.equals("true") && nickname != null) {
+            if ((!selfSign.equals("true") || (revRequestSharedSecret == null))
+                    && nickname != null) {
                 certname.append(nickname);
                 signerCert = cm.findCertByNickname(certname.toString());
                 if (signerCert != null) {
-                    System.out.println("got signerCert: "+ certname.toString());
+                    System.out.println("got signerCert: " + certname.toString());
                 }
             }
 
@@ -2062,6 +2119,7 @@ public class CMCRequest {
                 }
             }
 
+            boolean isSharedSecretRevoke = false;
             if (decryptedPopEnable.equalsIgnoreCase("true")) {
                 if (encryptedPopResponseFile == null) {
                     System.out.println("ecryptedPop.enable = true, but encryptedPopResponseFile is not specified.");
@@ -2088,7 +2146,7 @@ public class CMCRequest {
                 }
             } else { // !decryptedPopEnable
 
-                if (ifilename == null) {
+                if (!revRequestEnable.equalsIgnoreCase("true") && ifilename == null) {
                     System.out.println("Missing input filename for PKCS10 or CRMF.");
                     printUsage();
                 }
@@ -2106,14 +2164,17 @@ public class CMCRequest {
                     }
                 }
 
-                StringTokenizer tokenizer = new StringTokenizer(ifilename, " ");
-                String[] ifiles = new String[num];
-                for (int i = 0; i < num; i++) {
-                    String ss = tokenizer.nextToken();
-                    ifiles[i] = ss;
-                    if (ss == null) {
-                        System.out.println("Missing input file for the request.");
-                        System.exit(1);
+                String[] ifiles = null;
+                if (revRequestEnable.equalsIgnoreCase("false")) {
+                    StringTokenizer tokenizer = new StringTokenizer(ifilename, " ");
+                    ifiles = new String[num];
+                    for (int i = 0; i < num; i++) {
+                        String ss = tokenizer.nextToken();
+                        ifiles[i] = ss;
+                        if (ss == null) {
+                            System.out.println("Missing input file for the request.");
+                            System.exit(1);
+                        }
                     }
                 }
 
@@ -2123,11 +2184,12 @@ public class CMCRequest {
                 }
 
                 if (format == null) {
-                    System.out.println("Missing format.");
-                    printUsage();
+                    System.out.println("Missing format..assume revocation");
+                    //printUsage();
                 }
+
                 String[] requests = new String[num];
-                for (int i = 0; i < num; i++) {
+                for (int i = 0; i < num && revRequestEnable.equalsIgnoreCase("false") ; i++) {
                     BufferedReader inputBlob = null;
                     try {
                         inputBlob = new BufferedReader(new InputStreamReader(
@@ -2219,20 +2281,20 @@ public class CMCRequest {
 
                 SEQUENCE otherMsgSeq = new SEQUENCE();
                 if (revRequestEnable.equalsIgnoreCase("true")) {
-                    if (revRequestIssuer.length() == 0 || revRequestSerial.length() == 0 ||
-                            revRequestReason.length() == 0) {
-                        System.out.println("Illegal parameters for revRequest control");
-                        printUsage();
-                        System.exit(1);
+                    if ((revRequestSharedSecret!= null)
+                             && (revRequestSharedSecret.length() > 0)) {
+                        isSharedSecretRevoke = true;
+                        //this will result in unsigned data
                     }
 
-                    bpid = addRevRequestAttr(bpid, controlSeq, otherMsgSeq, token, tokenName, revCertNickname,
+                    bpid = addRevRequestAttr(bpid, controlSeq, token, signerCert,
                             revRequestIssuer, revRequestSerial, revRequestReason, revRequestSharedSecret,
                             revRequestComment, revRequestInvalidityDatePresent, cm);
-                }
+                    pkidata = new PKIData(controlSeq, new SEQUENCE(), new SEQUENCE(), new SEQUENCE());
+                } else {
 
-                // create the request PKIData
-                pkidata = createPKIData(
+                    // create the request PKIData
+                    pkidata = createPKIData(
                         selfSign,
                         requests,
                         format, transactionMgtEnable, transactionMgtId,
@@ -2245,6 +2307,7 @@ public class CMCRequest {
                         popLinkWitnessV2keyGenAlg, popLinkWitnessV2macAlg,
                         controlSeq, otherMsgSeq, bpid,
                         token, privk);
+                }
 
                 if (pkidata == null) {
                     System.out.println("pkidata null after createPKIData(). Exiting with error");
@@ -2252,22 +2315,30 @@ public class CMCRequest {
                 }
             }
 
-            // sign the request
-            SignedData signedData = null;
-            if (selfSign.equalsIgnoreCase("true")) {
-                // selfSign signs with private key
-                System.out.println("selfSign is true...");
-                signedData = signData(privk, pkidata);
+            if (isSharedSecretRevoke) {
+                cmcblob = getCMCBlob(null,
+                        ASN1Util.encode(pkidata));
             } else {
-                // none selfSign signs with  existing cert
-                System.out.println("selfSign is false...");
-                signedData = signData(signerCert, tokenName, nickname, cm, pkidata);
-            }
-            if (signedData == null) {
-                System.out.println("signData() returns null. Exiting with error");
-                System.exit(1);
+
+                SignedData signedData = null;
+
+                // sign the request
+                if (selfSign.equalsIgnoreCase("true")) {
+                    // selfSign signs with private key
+                    System.out.println("selfSign is true...");
+                    signedData = signData(privk, pkidata);
+                } else {
+                    // none selfSign signs with  existing cert
+                    System.out.println("selfSign is false...");
+                    signedData = signData(signerCert, tokenName, nickname, cm, pkidata);
+                }
+                if (signedData == null) {
+                    System.out.println("signData() returns null. Exiting with error");
+                    System.exit(1);
+                }
+                cmcblob = getCMCBlob(signedData, null);
             }
-            cmcblob = getCMCBlob(signedData);
+
             if (cmcblob == null) {
                 System.out.println("getCMCBlob() returns null. Exiting with error");
                 System.exit(1);
diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java b/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java
index c2572e6..e46e883 100644
--- a/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java
+++ b/base/java-tools/src/com/netscape/cmstools/CMCRevoke.java
@@ -75,6 +75,7 @@ public class CMCRevoke {
     public static final String RFC7468_TRAILER = "-----END CERTIFICATE REQUEST-----";
     static String dValue = null, nValue = null, iValue = null, sValue = null, mValue = null, hValue = null,
             pValue = null, cValue = null;
+    static String tValue = null;
 
     public static final String CMS_BASE_CA_SIGNINGCERT_NOT_FOUND = "CA signing certificate not found";
     public static final String PR_REQUEST_CMC = "CMC";
@@ -109,8 +110,9 @@ public class CMCRevoke {
                     "-d<dir to cert8.db, key3.db> " +
                     "-n<nickname> " +
                     "-i<issuerName> " +
-                    "-s<serialName> " +
+                    "-s<serialNumber> " +
                     "-m<reason to revoke> " +
+                    "-t<shared secret> " +
                     "-p<password to db> " +
                     "-h<tokenname> " +
                     "-c<comment> ");
@@ -135,6 +137,8 @@ public class CMCRevoke {
                     mValue = cleanArgs(s[i].substring(2));
                 } else if (s[i].startsWith("-p")) {
                     pValue = cleanArgs(s[i].substring(2));
+                } else if (s[i].startsWith("-t")) {
+                    tValue = cleanArgs(s[i].substring(2));
                 } else if (s[i].startsWith("-h")) {
                     hValue = cleanArgs(s[i].substring(2));
                 } else if (s[i].startsWith("-c")) {
@@ -143,8 +147,6 @@ public class CMCRevoke {
 
             }
             // optional parameters
-            if (cValue == null)
-                cValue = "";
             if (hValue == null)
                 hValue = "";
 
@@ -160,7 +162,7 @@ public class CMCRevoke {
                         "-d<dir to cert8.db, key3.db> " +
                         "-n<nickname> " +
                         "-i<issuerName> " +
-                        "-s<serialName> " +
+                        "-s<serialNumber> " +
                         "-m<reason to revoke> " +
                         "-p<password to db> " +
                         "-h<tokenname> " +
@@ -191,9 +193,9 @@ public class CMCRevoke {
 
                 token.login(pass);
                 X509Certificate signerCert = getCertificate(cm, hValue, nValue);
-                String outBlob = createRevokeReq(hValue, signerCert, cm);
+                ContentInfo fullEnrollmentRequest = createRevokeReq(hValue, signerCert, cm);
 
-                printCMCRevokeRequest(outBlob);
+                printCMCRevokeRequest(fullEnrollmentRequest);
             } catch (Exception e) {
                 e.printStackTrace();
                 System.exit(1);
@@ -209,29 +211,48 @@ public class CMCRevoke {
      *
      * @param asciiBASE64Blob the ascii string of the request
      */
-    static void printCMCRevokeRequest(String asciiBASE64Blob) {
+    static void printCMCRevokeRequest(ContentInfo fullEnrollmentReq) {
+        String method = "printCMCRevokeRequest: ";
 
-        // (6) Finally, print the actual CMCSigning blob to the
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        ByteArrayOutputStream bs = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(bs);
+
+        if (fullEnrollmentReq == null) {
+            System.out.println(method + "param fullEnrollmentRequest is null");
+            System.exit(1);
+        }
+        // format is PR_REQUEST_CMC
+        try {
+            fullEnrollmentReq.encode(os);
+        } catch (IOException e) {
+            System.out.println("CMCSigning:  I/O error " +
+                    "encountered during write():\n" +
+                    e);
+            System.exit(1);
+        }
+        //ps.print(Utils.base64encode(os.toByteArray()));
+        // no line breaks for ease of copy/paste for CA acceptance
+        System.out.println(RFC7468_HEADER);
+        ps.print(Utils.base64encodeSingleLine(os.toByteArray()));
+        ////fullEnrollmentReq.print(ps); // no header/trailer
+
+        String asciiBASE64Blob = bs.toString();
+        System.out.println(asciiBASE64Blob + "\n" + RFC7468_TRAILER);
+
+        // (6) Finally, print the actual CMCSigning binary blob to the
         //     specified output file
         FileOutputStream outputBlob = null;
 
         try {
             outputBlob = new FileOutputStream("CMCRevoke.out");
+            fullEnrollmentReq.encode(outputBlob);
         } catch (IOException e) {
             System.out.println("CMCSigning:  unable to open file CMCRevoke.out for writing:\n" + e);
             return;
         }
 
-        System.out.println(RFC7468_HEADER);
-        System.out.println(asciiBASE64Blob + RFC7468_TRAILER);
-        try {
-            asciiBASE64Blob = RFC7468_HEADER + "\n" + asciiBASE64Blob + RFC7468_TRAILER;
-            outputBlob.write(asciiBASE64Blob.getBytes());
-        } catch (IOException e) {
-            System.out.println("CMCSigning:  I/O error " +
-                    "encountered during write():\n" +
-                    e);
-        }
+        System.out.println("\nCMC revocation binary blob written to CMCRevoke.out\n");
 
         try {
             outputBlob.close();
@@ -280,12 +301,11 @@ public class CMCRevoke {
      * @param manager the crypto manger.
      * @return the CMC revocation request encoded in base64
      */
-    static String createRevokeReq(String tokenname, X509Certificate signerCert, CryptoManager manager) {
+    static ContentInfo createRevokeReq(String tokenname, X509Certificate signerCert, CryptoManager manager) {
 
         java.security.PrivateKey privKey = null;
         SignerIdentifier si = null;
         ContentInfo fullEnrollmentReq = null;
-        String asciiBASE64Blob = null;
 
         try {
 
@@ -305,8 +325,8 @@ public class CMCRevoke {
 
             if (privKey == null) {
                 System.out.println("CMCRevoke::createRevokeReq() - " +
-                                    "privKey is null!");
-                return "";
+                        "privKey is null!");
+                return null;
             }
 
             int bpid = 1;
@@ -319,65 +339,64 @@ public class CMCRevoke {
             byte[] dig;
 
             try {
-                MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+                MessageDigest SHA2Digest = MessageDigest.getInstance("SHA256");
 
-                dig = SHA1Digest.digest(salt.getBytes());
+                dig = SHA2Digest.digest(salt.getBytes());
             } catch (NoSuchAlgorithmException ex) {
                 dig = salt.getBytes();
             }
             String sn = Utils.base64encode(dig);
 
-            TaggedAttribute senderNonce =
-                    new TaggedAttribute(new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_senderNonce,
-                            new OCTET_STRING(sn.getBytes()));
+            TaggedAttribute senderNonce = new TaggedAttribute(new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_senderNonce,
+                    new OCTET_STRING(sn.getBytes()));
 
             controlSeq.addElement(senderNonce);
 
             Name subjectName = new Name();
 
             subjectName.addCommonName(iValue);
-            org.mozilla.jss.pkix.cmmf.RevRequest lRevokeRequest =
-                    new org.mozilla.jss.pkix.cmmf.RevRequest(new ANY((new X500Name(iValue)).getEncoded()),
-                            new INTEGER(sValue),
-                            //org.mozilla.jss.pkix.cmmf.RevRequest.unspecified,
-                            new ENUMERATED((new Integer(mValue)).longValue()),
-                            null,
-                            new OCTET_STRING(pValue.getBytes()),
-                            new UTF8String(cValue.toCharArray()));
+            org.mozilla.jss.pkix.cmc.RevokeRequest lRevokeRequest = new org.mozilla.jss.pkix.cmc.RevokeRequest(
+                    new ANY((new X500Name(iValue)).getEncoded()),
+                    new INTEGER(sValue),
+                    //org.mozilla.jss.pkix.cmc.RevokeRequest.unspecified,
+                    new ENUMERATED((new Integer(mValue)).longValue()),
+                    null,
+                    (tValue != null) ? new OCTET_STRING(tValue.getBytes()) : null,
+                    (cValue != null) ? new UTF8String(cValue.toCharArray()) : null);
             //byte[] encoded = ASN1Util.encode(lRevokeRequest);
-            //org.mozilla.jss.asn1.ASN1Template template = new  org.mozilla.jss.pkix.cmmf.RevRequest.Template();
-            //org.mozilla.jss.pkix.cmmf.RevRequest revRequest = (org.mozilla.jss.pkix.cmmf.RevRequest)
+            //org.mozilla.jss.asn1.ASN1Template template = new  org.mozilla.jss.pkix.cmc.RevokeRequest.Template();
+            //org.mozilla.jss.pkix.cmc.RevokeRequest revRequest = (org.mozilla.jss.pkix.cmc.RevokeRequest)
             //                                                               template.decode(new java.io.ByteArrayInputStream(
             //                                                               encoded));
 
-            ByteArrayOutputStream os = new ByteArrayOutputStream();
-            //lRevokeRequest.encode(os); // khai
-            TaggedAttribute revokeRequestTag =
-                    new TaggedAttribute(new INTEGER(bpid++), OBJECT_IDENTIFIER.id_cmc_revokeRequest,
-                            lRevokeRequest);
+            TaggedAttribute revokeRequestTag = new TaggedAttribute(new INTEGER(bpid++),
+                    OBJECT_IDENTIFIER.id_cmc_revokeRequest,
+                    lRevokeRequest);
 
             controlSeq.addElement(revokeRequestTag);
             PKIData pkidata = new PKIData(controlSeq, new SEQUENCE(), new SEQUENCE(), new SEQUENCE());
 
             EncapsulatedContentInfo ci = new EncapsulatedContentInfo(OBJECT_IDENTIFIER.id_cct_PKIData, pkidata);
-            // SHA1 is the default digest Alg for now.
             DigestAlgorithm digestAlg = null;
             SignatureAlgorithm signAlg = null;
-            org.mozilla.jss.crypto.PrivateKey.Type signingKeyType = ((org.mozilla.jss.crypto.PrivateKey) privKey).getType();
+            org.mozilla.jss.crypto.PrivateKey.Type signingKeyType = ((org.mozilla.jss.crypto.PrivateKey) privKey)
+                    .getType();
             if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.RSA)) {
-                signAlg = SignatureAlgorithm.RSASignatureWithSHA1Digest;
+                signAlg = SignatureAlgorithm.RSASignatureWithSHA256Digest;
             } else if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.EC)) {
-                signAlg = SignatureAlgorithm.ECSignatureWithSHA1Digest;
-            } else if (signingKeyType.equals(org.mozilla.jss.crypto.PrivateKey.Type.DSA)) {
-                signAlg = SignatureAlgorithm.DSASignatureWithSHA1Digest;
+                signAlg = SignatureAlgorithm.ECSignatureWithSHA256Digest;
+            } else {
+                System.out.println("Algorithm not supported:" +
+                        signingKeyType);
+                return null;
             }
 
             MessageDigest SHADigest = null;
             byte[] digest = null;
 
             try {
-                SHADigest = MessageDigest.getInstance("SHA1");
-                digestAlg = DigestAlgorithm.SHA1;
+                SHADigest = MessageDigest.getInstance("SHA256");
+                digestAlg = DigestAlgorithm.SHA256;
 
                 ByteArrayOutputStream ostream = new ByteArrayOutputStream();
 
@@ -411,21 +430,11 @@ public class CMCRevoke {
 
             fullEnrollmentReq = new ContentInfo(req);
 
-            ByteArrayOutputStream bs = new ByteArrayOutputStream();
-            PrintStream ps = new PrintStream(bs);
-
-            if (fullEnrollmentReq != null) {
-                // format is PR_REQUEST_CMC
-                fullEnrollmentReq.encode(os);
-                ps.print(Utils.base64encode(os.toByteArray()));
-                ////fullEnrollmentReq.print(ps); // no header/trailer
-            }
-
-            asciiBASE64Blob = bs.toString();
         } catch (Exception e) {
             e.printStackTrace();
             System.exit(1);
         }
-        return asciiBASE64Blob;
+
+        return fullEnrollmentReq;
     }
 }
diff --git a/base/server/cms/src/com/netscape/cms/authentication/CMCAuth.java b/base/server/cms/src/com/netscape/cms/authentication/CMCAuth.java
index b898353..9441167 100644
--- a/base/server/cms/src/com/netscape/cms/authentication/CMCAuth.java
+++ b/base/server/cms/src/com/netscape/cms/authentication/CMCAuth.java
@@ -237,6 +237,9 @@ public class CMCAuth implements IAuthManager, IExtendedPluginInfo,
      */
     public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredential, EInvalidCredentials,
             EBaseException {
+        String method = "CMCAuth: authenticate: ";
+        String msg = "";
+
         String auditMessage = null;
         String auditSubjectID = auditSubjectID();
         String auditReqType = ILogger.UNIDENTIFIED;
@@ -261,7 +264,7 @@ public class CMCAuth implements IAuthManager, IExtendedPluginInfo,
             }
             String cmc = (String) returnVal;
             if (cmc == null) {
-                CMS.debug("CMCAuth: Authentication failed. Missing CMC.");
+                CMS.debug(method + "Authentication failed. Missing CMC.");
 
                 // store a message in the signed audit log file
                 auditMessage = CMS.getLogMessage(
@@ -279,8 +282,9 @@ public class CMCAuth implements IAuthManager, IExtendedPluginInfo,
             }
 
             if (cmc.equals("")) {
-                log(ILogger.LL_FAILURE,
-                        "cmc : attempted login with empty CMC.");
+                msg = "attempted login with empty CMC";
+                CMS.debug(method + msg);
+                log(ILogger.LL_FAILURE, method + msg);
 
                 // store a message in the signed audit log file
                 auditMessage = CMS.getLogMessage(
@@ -331,6 +335,7 @@ public class CMCAuth implements IAuthManager, IExtendedPluginInfo,
                 if (!cmcReq.getContentType().equals(
                         org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA) ||
                         !cmcReq.hasContent()) {
+                    CMS.debug(method + "malformed cmc: either not ContentInfo.SIGNED_DATA or cmcReq has no content");
                     // store a message in the signed audit log file
                     auditMessage = CMS.getLogMessage(
                             AuditEvent.CMC_SIGNED_REQUEST_SIG_VERIFY,
@@ -358,13 +363,13 @@ public class CMCAuth implements IAuthManager, IExtendedPluginInfo,
                 if (checkSignerInfo) {
                     IAuthToken agentToken = verifySignerInfo(authToken, cmcFullReq);
                     if (agentToken == null) {
-                        CMS.debug("CMCAuth: authenticate() agentToken null");
+                        CMS.debug(method + "agentToken null");
                         throw new EBaseException("CMCAuth: agent verifySignerInfo failure");
                     }
                     userid = agentToken.getInString("userid");
                     uid = agentToken.getInString("cn");
                 } else {
-                    CMS.debug("CMCAuth: authenticate() signerInfo verification bypassed");
+                    CMS.debug(method + "signerInfo verification bypassed");
                 }
                 // reset value of auditSignerInfo
                 if (uid != null) {
@@ -377,6 +382,8 @@ public class CMCAuth implements IAuthManager, IExtendedPluginInfo,
 
                 if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIData) ||
                         !ci.hasContent()) {
+                    msg = "request EncapsulatedContentInfo content type not OBJECT_IDENTIFIER.id_cct_PKIData";
+                    CMS.debug( method + msg);
                     // store a message in the signed audit log file
                     auditMessage = CMS.getLogMessage(
                             AuditEvent.CMC_SIGNED_REQUEST_SIG_VERIFY,
@@ -406,6 +413,7 @@ public class CMCAuth implements IAuthManager, IExtendedPluginInfo,
 
                 if (numReqs == 0) {
                     // revocation request
+                    CMS.debug(method + "numReqs 0, assume revocation request");
 
                     // reset value of auditReqType
                     auditReqType = SIGNED_AUDIT_REVOCATION_REQUEST_TYPE;
@@ -476,6 +484,7 @@ public class CMCAuth implements IAuthManager, IExtendedPluginInfo,
                     }
                 } else {
                     // enrollment request
+                    CMS.debug(method + "numReqs not 0, assume enrollment request");
 
                     // reset value of auditReqType
                     auditReqType = SIGNED_AUDIT_ENROLLMENT_REQUEST_TYPE;
diff --git a/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java b/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
index a18c25e..2e4d6dc 100644
--- a/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
+++ b/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
@@ -29,9 +29,9 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
-import java.security.cert.CertificateExpiredException;
 import java.security.MessageDigest;
 import java.security.PublicKey;
+import java.security.cert.CertificateExpiredException;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Locale;
@@ -323,85 +323,90 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                 byte[] cmcBlob = CMS.AtoB(asciiBASE64Blob);
                 ByteArrayInputStream cmcBlobIn = new ByteArrayInputStream(cmcBlob);
 
-                org.mozilla.jss.pkix.cms.ContentInfo cmcReq =
-                        (org.mozilla.jss.pkix.cms.ContentInfo) org.mozilla.jss.pkix.cms.ContentInfo
+                org.mozilla.jss.pkix.cms.ContentInfo cmcReq = (org.mozilla.jss.pkix.cms.ContentInfo) org.mozilla.jss.pkix.cms.ContentInfo
                         .getTemplate().decode(
                                 cmcBlobIn);
 
-                if (!cmcReq.getContentType().equals(
-                        org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA) ||
-                        !cmcReq.hasContent()) {
-
-                    cmcBlobIn.close();
-                    msg = "cmc rquest content type is not ContentInfo.SIGNED_DATA";
-                    CMS.debug(msg);
-                    throw new EBaseException(msg);
-                }
-
-                SignedData cmcFullReq = (SignedData) cmcReq.getInterpretedContent();
-
                 String userid = ILogger.UNIDENTIFIED;
                 String uid = ILogger.UNIDENTIFIED;
 
-                IConfigStore cmc_config = CMS.getConfigStore();
-                boolean checkSignerInfo = cmc_config.getBoolean("cmc.signerInfo.verify", true);
-                if (checkSignerInfo) {
-                    // selfSigned will be set in verifySignerInfo if applicable
-                    IAuthToken userToken = verifySignerInfo(auditContext, authToken, cmcFullReq);
-                    if (userToken == null) {
-                        msg = "userToken null; verifySignerInfo failure";
-                        CMS.debug(method + msg);
-                        throw new EBaseException(msg);
-                    } else {
-                        if (selfSigned) {
-                            CMS.debug(method
-                                    + " self-signed cmc request will not have user identification info at this point.");
-                            auditSignerInfo = "selfSigned";
+                SignedData cmcFullReq = null;
+                OCTET_STRING content = null;
+                OBJECT_IDENTIFIER id = null;
+                org.mozilla.jss.pkix.cms.SignerInfo selfsign_signerInfo = null;
+                if (cmcReq.getContentType().equals(
+                        org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA)) {
+                    CMS.debug(method + "cmc request content is signed data");
+                    cmcFullReq = (SignedData) cmcReq.getInterpretedContent();
+
+                    IConfigStore cmc_config = CMS.getConfigStore();
+                    boolean checkSignerInfo = cmc_config.getBoolean("cmc.signerInfo.verify", true);
+                    if (checkSignerInfo) {
+                        // selfSigned will be set in verifySignerInfo if applicable
+                        IAuthToken userToken = verifySignerInfo(auditContext, authToken, cmcFullReq);
+                        if (userToken == null) {
+                            msg = "userToken null; verifySignerInfo failure";
+                            CMS.debug(method + msg);
+                            throw new EBaseException(msg);
                         } else {
-                            CMS.debug(method + "signed with user cert");
-                            userid = userToken.getInString("userid");
-                            uid = userToken.getInString("cn");
-                            if (userid == null && uid == null) {
-                                msg = " verifySignerInfo failure... missing userid and cn";
-                                CMS.debug(method + msg);
-                                throw new EBaseException(msg);
-                            }
-                            // reset value of auditSignerInfo
-                            if (uid != null && !uid.equals(ILogger.UNIDENTIFIED)) {
-                                CMS.debug(method + "setting auditSignerInfo to uid:" + uid.trim());
-                                auditSignerInfo = uid.trim();
-                                auditSubjectID = uid.trim();
-                                authToken.set(IAuthToken.USER_ID, auditSubjectID);
-                            } else if (userid != null && !userid.equals(ILogger.UNIDENTIFIED)) {
-                                CMS.debug(method + "setting auditSignerInfo to userid:" + userid);
-                                auditSignerInfo = userid.trim();
-                                auditSubjectID = userid.trim();
-                                authToken.set(IAuthToken.USER_ID, auditSubjectID);
+                            if (selfSigned) {
+                                CMS.debug(method
+                                        + " self-signed cmc request will not have user identification info at this point.");
+                                auditSignerInfo = "selfSigned";
+                            } else {
+                                CMS.debug(method + "signed with user cert");
+                                userid = userToken.getInString("userid");
+                                uid = userToken.getInString("cn");
+                                if (userid == null && uid == null) {
+                                    msg = " verifySignerInfo failure... missing userid and cn";
+                                    CMS.debug(method + msg);
+                                    throw new EBaseException(msg);
+                                }
+                                // reset value of auditSignerInfo
+                                if (uid != null && !uid.equals(ILogger.UNIDENTIFIED)) {
+                                    CMS.debug(method + "setting auditSignerInfo to uid:" + uid.trim());
+                                    auditSignerInfo = uid.trim();
+                                    auditSubjectID = uid.trim();
+                                    authToken.set(IAuthToken.USER_ID, auditSubjectID);
+                                } else if (userid != null && !userid.equals(ILogger.UNIDENTIFIED)) {
+                                    CMS.debug(method + "setting auditSignerInfo to userid:" + userid);
+                                    auditSignerInfo = userid.trim();
+                                    auditSubjectID = userid.trim();
+                                    authToken.set(IAuthToken.USER_ID, auditSubjectID);
+                                }
                             }
                         }
+                    } else {
+                        CMS.debug(method + " signerInfo verification bypassed");
                     }
-                } else {
-                    CMS.debug(method + " signerInfo verification bypassed");
-                }
 
-                EncapsulatedContentInfo ci = cmcFullReq.getContentInfo();
-                SET sis = cmcFullReq.getSignerInfos();
-                // only one SignerInfo for selfSigned
-                org.mozilla.jss.pkix.cms.SignerInfo selfsign_signerInfo =
-                        (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(0);
+                    EncapsulatedContentInfo ci = cmcFullReq.getContentInfo();
+                    SET sis = cmcFullReq.getSignerInfos();
+                    // only one SignerInfo for selfSigned
+                    selfsign_signerInfo = (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(0);
 
-                OBJECT_IDENTIFIER id = ci.getContentType();
+                    id = ci.getContentType();
 
-                if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIData) ||
-                        !ci.hasContent()) {
-                    msg = "request EncapsulatedContentInfo content type not OBJECT_IDENTIFIER.id_cct_PKIData";
-                    CMS.debug(method + msg);
+                    if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIData) ||
+                            !ci.hasContent()) {
+                        msg = "request EncapsulatedContentInfo content type not OBJECT_IDENTIFIER.id_cct_PKIData";
+                        CMS.debug(method + msg);
+
+                        throw new EBaseException(msg);
+                    }
 
+                    content = ci.getContent();
+                } else if (cmcReq.getContentType().equals( //unsigned
+                        org.mozilla.jss.pkix.cms.ContentInfo.DATA)) {
+                    CMS.debug(method + "cmc request content is unsigned data...verifySignerInfo will not be called;");
+                    content = (OCTET_STRING) cmcReq.getInterpretedContent();
+                } else {
+                    cmcBlobIn.close();
+                    msg = "unsupported cmc rquest content type; must be either ContentInfo.SIGNED_DATA or ContentInfo.DATA;";
+                    CMS.debug(msg);
                     throw new EBaseException(msg);
                 }
 
-                OCTET_STRING content = ci.getContent();
-
                 ByteArrayInputStream s = new ByteArrayInputStream(content.toByteArray());
                 PKIData pkiData = (PKIData) (new PKIData.Template()).decode(s);
 
@@ -426,7 +431,8 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
 
                             if (type.equals(
                                     OBJECT_IDENTIFIER.id_cmc_revokeRequest)) {
-                                /* TODO: user-signed revocation to be handled in next ticket
+                                //further checks and actual revocation happen in CMCOutputTemplate
+
                                 // if( i ==1 ) {
                                 //     taggedAttribute.getType() ==
                                 //       OBJECT_IDENTIFIER.id_cmc_revokeRequest
@@ -440,25 +446,23 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                                 for (int j = 0; j < numVals; j++) {
                                     // serialNumber    INTEGER
 
-                                    // SEQUENCE RevRequest = (SEQUENCE)
+                                    // SEQUENCE RevokeRequest = (SEQUENCE)
                                     //     values.elementAt(j);
                                     byte[] encoded = ASN1Util.encode(
                                             values.elementAt(j));
-                                    org.mozilla.jss.asn1.ASN1Template template = new
-                                            org.mozilla.jss.pkix.cmmf.RevRequest.Template();
-                                    org.mozilla.jss.pkix.cmmf.RevRequest revRequest =
-                                            (org.mozilla.jss.pkix.cmmf.RevRequest)
-                                            ASN1Util.decode(template, encoded);
+                                    org.mozilla.jss.asn1.ASN1Template template = new org.mozilla.jss.pkix.cmc.RevokeRequest.Template();
+                                    org.mozilla.jss.pkix.cmc.RevokeRequest revRequest = (org.mozilla.jss.pkix.cmc.RevokeRequest) ASN1Util
+                                            .decode(template, encoded);
 
-                                    // SEQUENCE RevRequest = (SEQUENCE)
+                                    // SEQUENCE RevokeRequest = (SEQUENCE)
                                     //     ASN1Util.decode(
                                     //         SEQUENCE.getTemplate(),
                                     //         ASN1Util.encode(
                                     //         values.elementAt(j)));
 
-                                    // SEQUENCE RevRequest =
+                                    // SEQUENCE RevokeRequest =
                                     //     values.elementAt(j);
-                                    // int revReqSize = RevRequest.size();
+                                    // int revReqSize = RevokeRequest.size();
                                     // if( revReqSize > 3 ) {
                                     //     INTEGER serialNumber =
                                     //         new INTEGER((long)0);
@@ -473,13 +477,10 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                                     Integer IntObject = Integer.valueOf((int) reasonCode);
                                     authToken.set(REASON_CODE, IntObject);
 
-
                                     //authToken.set("uid", uid);
                                     //authToken.set("userid", userid);
 
                                 }
-                                */
-
                             }
                         }
 
@@ -648,8 +649,7 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                                 certInfoArray[i] = certInfo;
 
                                 if (selfSigned) {
-                                    selfsign_skiExtn =
-                                            (SubjectKeyIdentifierExtension) CryptoUtil
+                                    selfsign_skiExtn = (SubjectKeyIdentifierExtension) CryptoUtil
                                             .getExtensionFromCertTemplate(template, PKIXExtensions.SubjectKey_Id);
                                     if (selfsign_skiExtn != null) {
                                         CMS.debug(method +
@@ -702,16 +702,24 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                 throw new EInvalidCredentials(e.toString());
             }
 
-            // store a message in the signed audit log file
-            auditMessage = CMS.getLogMessage(
-                    AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS,
-                    auditSubjectID,
-                    ILogger.SUCCESS,
-                    auditReqType,
-                    auditCertSubject,
-                    auditSignerInfo);
-
-            audit(auditMessage);
+            // For accuracy, make sure revocation by shared secret doesn't
+            // log CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS
+            if (authToken.get(IAuthManager.CRED_CMC_SIGNING_CERT) != null ||
+                    authToken.get(IAuthManager.CRED_CMC_SELF_SIGNED) != null) {
+                // store a message in the signed audit log file
+                auditMessage = CMS.getLogMessage(
+                        AuditEvent.CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS,
+                        auditSubjectID,
+                        ILogger.SUCCESS,
+                        auditReqType,
+                        auditCertSubject,
+                        auditSignerInfo);
+
+                audit(auditMessage);
+            } else {
+                CMS.debug(method
+                        + "audit event CMC_USER_SIGNED_REQUEST_SIG_VERIFY_SUCCESS not logged due to unsigned data for revocation with shared secret.");
+            }
 
             CMS.debug(method + "ends successfully; returning authToken");
             return authToken;
@@ -1029,10 +1037,15 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                         } else {
                             CMS.debug(method + "found signing cert... verifying");
 
-                            //capture auditSubjectID first in case of failure
-                            netscape.security.x509.X500Name tempPrincipal =
+                            // capture auditSubjectID first in case of failure
+                            netscape.security.x509.X500Name principal =
                                     (X500Name) x509Certs[0].getSubjectDN();
-                            CN = tempPrincipal.getCommonName(); //tempToken.get("userid");
+
+                            // capture signer principal to be checked against
+                            // cert subject principal later in CMCOutputTemplate
+                            // in case of user signed revocation
+                            auditContext.put(SessionContext.CMC_SIGNER_PRINCIPAL, principal);
+                            CN = principal.getCommonName(); //tempToken.get("userid");
                             CMS.debug(method + " Principal name = " + CN);
                             auditContext.put(SessionContext.USER_ID, CN);
 
@@ -1093,15 +1106,18 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                         // now check revocation status of the cert
                         if (CMS.isRevoked(x509Certs)) {
                             CMS.debug(method + "CMC signing cert is a revoked certificate");
+                            s.close();
                             throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
                         }
                         try { //do this again anyways
                             cert.checkValidity();
                         } catch (CertificateExpiredException e) {
                             CMS.debug(method + "CMC signing cert is an expired certificate");
+                            s.close();
                             throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
                         } catch (Exception e) {
                             CMS.debug(method + e.toString());
+                            s.close();
                             throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
                         }
 
diff --git a/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java b/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java
index 12fb736..bc5de32 100644
--- a/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java
+++ b/base/server/cms/src/com/netscape/cms/profile/common/EnrollProfile.java
@@ -587,16 +587,25 @@ public abstract class EnrollProfile extends BasicProfile
         try {
             byte data[] = CMS.AtoB(creq);
             ByteArrayInputStream cmcBlobIn = new ByteArrayInputStream(data);
+            PKIData pkiData = null;
 
             org.mozilla.jss.pkix.cms.ContentInfo cmcReq = (org.mozilla.jss.pkix.cms.ContentInfo) org.mozilla.jss.pkix.cms.ContentInfo
                     .getTemplate().decode(cmcBlobIn);
-            org.mozilla.jss.pkix.cms.SignedData cmcFullReq = (org.mozilla.jss.pkix.cms.SignedData) cmcReq
-                    .getInterpretedContent();
-            org.mozilla.jss.pkix.cms.EncapsulatedContentInfo ci = cmcFullReq.getContentInfo();
-            OCTET_STRING content = ci.getContent();
-
+            OCTET_STRING content = null;
+            if (cmcReq.getContentType().equals(
+                    org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA)) {
+                CMS.debug(method + "cmc request content is signed data");
+                org.mozilla.jss.pkix.cms.SignedData cmcFullReq = (org.mozilla.jss.pkix.cms.SignedData) cmcReq
+                        .getInterpretedContent();
+                org.mozilla.jss.pkix.cms.EncapsulatedContentInfo ci = cmcFullReq.getContentInfo();
+                content = ci.getContent();
+
+            } else { // for unsigned revocation requests (using shared secret)
+                CMS.debug(method + "cmc request content is unsigned data");
+                content = (OCTET_STRING) cmcReq.getInterpretedContent();
+            }
             ByteArrayInputStream s = new ByteArrayInputStream(content.toByteArray());
-            PKIData pkiData = (PKIData) (new PKIData.Template()).decode(s);
+            pkiData = (PKIData) (new PKIData.Template()).decode(s);
 
             mCMCData = pkiData;
             //PKIData pkiData = (PKIData)
@@ -707,6 +716,8 @@ public abstract class EnrollProfile extends BasicProfile
             byte randomSeed[] = null;
             UTF8String ident_s = null;
             SessionContext context = SessionContext.getContext();
+
+            boolean id_cmc_revokeRequest = false;
             if (!context.containsKey("numOfControls")) {
                 CMS.debug(method + "numcontrols="+ numcontrols);
                 if (numcontrols > 0) {
@@ -734,7 +745,13 @@ public abstract class EnrollProfile extends BasicProfile
                     for (int i = 0; i < numcontrols; i++) {
                         attributes[i] = (TaggedAttribute) controlSeq.elementAt(i);
                         OBJECT_IDENTIFIER oid = attributes[i].getType();
-                        if (oid.equals(OBJECT_IDENTIFIER.id_cmc_decryptedPOP)) {
+                        if (oid.equals(OBJECT_IDENTIFIER.id_cmc_revokeRequest)) {
+                            id_cmc_revokeRequest = true;
+                            // put in context for processing in 
+                            // CMCOutputTemplate.java later
+                            context.put(OBJECT_IDENTIFIER.id_cmc_revokeRequest,
+                                    attributes[i]);
+                        } else if (oid.equals(OBJECT_IDENTIFIER.id_cmc_decryptedPOP)) {
                             CMS.debug(method + " id_cmc_decryptedPOP found");
                             id_cmc_decryptedPOP = true;
                             decPopVals = attributes[i].getValues();
@@ -765,6 +782,10 @@ public abstract class EnrollProfile extends BasicProfile
                      */
                     CMS.debug(method + "processing controls...");
 
+                    if (id_cmc_revokeRequest) {
+                        CMS.debug(method + "revocation control");
+                    }
+
                     if (id_cmc_identification) {
                         if (ident == null) {
                             msg = "id_cmc_identification contains null attribute value";
@@ -800,7 +821,7 @@ public abstract class EnrollProfile extends BasicProfile
 
                     // checking Proof Of Identity, if not pre-signed
 
-                    if (donePOI) {
+                    if (donePOI || id_cmc_revokeRequest) {
                         // for logging purposes
                         if (id_cmc_identityProofV2) {
                             CMS.debug(method
@@ -920,6 +941,7 @@ public abstract class EnrollProfile extends BasicProfile
             SEQUENCE otherMsgSeq = pkiData.getOtherMsgSequence();
             int numOtherMsgs = otherMsgSeq.size();
             if (!context.containsKey("numOfOtherMsgs")) {
+                CMS.debug(method + "found numOfOtherMsgs: " + numOtherMsgs);
                 context.put("numOfOtherMsgs", Integer.valueOf(numOtherMsgs));
                 for (int i = 0; i < numOtherMsgs; i++) {
                     OtherMsg omsg = (OtherMsg) (ASN1Util.decode(OtherMsg.getTemplate(),
@@ -958,6 +980,8 @@ public abstract class EnrollProfile extends BasicProfile
                 boolean valid = true;
                 for (int i = 0; i < nummsgs; i++) {
                     msgs[i] = (TaggedRequest) reqSeq.elementAt(i);
+                    if (id_cmc_revokeRequest)
+                        continue;
                     if (popLinkWitnessRequired &&
                             !context.containsKey("POPLinkWitnessV2") &&
                             !context.containsKey("POPLinkWitness")) {
@@ -1272,7 +1296,7 @@ public abstract class EnrollProfile extends BasicProfile
         boolean sharedSecretFound = true;
         String configName = "cmc.sharedSecret.class";
         String sharedSecret = null;
-        ISharedToken tokenClass = getSharedTokenClass(configName);
+        ISharedToken tokenClass = CMS.getSharedTokenClass(configName);
         if (tokenClass == null) {
             CMS.debug(method + " Failed to retrieve shared secret plugin class");
             sharedSecretFound = false;
@@ -1499,40 +1523,6 @@ public abstract class EnrollProfile extends BasicProfile
         return bpids;
     }
 
-
-    ISharedToken getSharedTokenClass(String configName) {
-        String method = "EnrollProfile: getSharedTokenClass: ";
-        ISharedToken tokenClass = null;
-
-        String name = null;
-        try {
-            CMS.debug(method + "getting :" + configName);
-            name = CMS.getConfigStore().getString(configName);
-            CMS.debug(method + "Shared Secret plugin class name retrieved:" +
-                    name);
-        } catch (Exception e) {
-            CMS.debug(method + " Failed to retrieve shared secret plugin class name");
-            return null;
-        }
-
-        try {
-            tokenClass = (ISharedToken) Class.forName(name).newInstance();
-            CMS.debug(method + "Shared Secret plugin class retrieved");
-        } catch (ClassNotFoundException e) {
-            CMS.debug(method + " Failed to find class name: " + name);
-            return null;
-        } catch (InstantiationException e) {
-            CMS.debug("EnrollProfile: Failed to instantiate class: " + name);
-            return null;
-        } catch (IllegalAccessException e) {
-            CMS.debug(method + " Illegal access: " + name);
-            return null;
-        }
-
-        return tokenClass;
-    }
-
-
     /**
      * verifyIdentityProofV2 handles IdentityProofV2 as defined by RFC5272
      *
@@ -1578,7 +1568,7 @@ public abstract class EnrollProfile extends BasicProfile
         }
 
         String configName = "cmc.sharedSecret.class";
-        ISharedToken tokenClass = getSharedTokenClass(configName);
+        ISharedToken tokenClass = CMS.getSharedTokenClass(configName);
 
         if (tokenClass == null) {
             msg = " Failed to retrieve shared secret plugin class";
@@ -1682,7 +1672,7 @@ public abstract class EnrollProfile extends BasicProfile
             return false;
 
         String configName = "cmc.sharedSecret.class";
-            ISharedToken tokenClass = getSharedTokenClass(configName);
+            ISharedToken tokenClass = CMS.getSharedTokenClass(configName);
         if (tokenClass == null) {
             CMS.debug(method + " Failed to retrieve shared secret plugin class");
             return false;
diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java b/base/server/cms/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java
index 24ba494..a66cd95 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/cert/CMCRevReqServlet.java
@@ -142,6 +142,8 @@ public class CMCRevReqServlet extends CMSServlet {
      * @param cmsReq the object holding the request and response information
      */
     protected void process(CMSRequest cmsReq) throws EBaseException {
+        String method = "CMCRevReqServlet: process: ";
+        CMS.debug(method + "begins");
 
         String cmcAgentSerialNumber = null;
         IArgBlock httpParams = cmsReq.getHttpParams();
@@ -151,7 +153,7 @@ public class CMCRevReqServlet extends CMSServlet {
         CMSTemplate form = null;
         Locale[] locale = new Locale[1];
 
-        CMS.debug("**** mFormPath = " + mFormPath);
+        CMS.debug(method + "**** mFormPath = " + mFormPath);
         try {
             form = getTemplate(mFormPath, req, locale);
         } catch (IOException e) {
diff --git a/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java b/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java
index 3794f10..01c4b6a 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/cert/ListCerts.java
@@ -461,11 +461,11 @@ public class ListCerts extends CMSServlet {
                 ICertRecord rec = e.nextElement();
 
                 if (rec == null) {
-                    CMS.debug("ListCerts: * record " + count + " is null");
+                    //CMS.debug("ListCerts: * record " + count + " is null");
                     break;
                 }
                 curSerial = rec.getSerialNumber();
-                CMS.debug("ListCerts: * record " + count + ": " + curSerial);
+                //CMS.debug("ListCerts: * record " + count + ": " + curSerial);
 
                 if (count == 0) {
                     firstSerial = curSerial;
@@ -493,11 +493,11 @@ public class ListCerts extends CMSServlet {
                 }
 
                 if (mReverse) {
-                    CMS.debug("ListCerts: returning with rcount: " + rcount);
+                    //CMS.debug("ListCerts: returning with rcount: " + rcount);
                     recs[rcount++] = rec;
 
                 } else {
-                    CMS.debug("ListCerts: returning with arg block");
+                    //CMS.debug("ListCerts: returning with arg block");
                     IArgBlock rarg = CMS.createArgBlock();
                     fillRecordIntoArg(rec, rarg);
                     argSet.addRepeatRecord(rarg);
@@ -514,7 +514,7 @@ public class ListCerts extends CMSServlet {
             CMS.debug("ListCerts: fill records into arg block and argSet");
             for (int ii = rcount - 1; ii >= 0; ii--) {
                 if (recs[ii] != null) {
-                    CMS.debug("ListCerts: processing recs[" + ii + "]");
+                    //CMS.debug("ListCerts: processing recs[" + ii + "]");
                     IArgBlock rarg = CMS.createArgBlock();
                     // CMS.debug("item " + ii + " is serial #" + recs[ii].getSerialNumber());
                     fillRecordIntoArg(recs[ii], rarg);
diff --git a/base/server/cms/src/com/netscape/cms/servlet/common/CMCOutputTemplate.java b/base/server/cms/src/com/netscape/cms/servlet/common/CMCOutputTemplate.java
index 8e47298..942e92f 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/common/CMCOutputTemplate.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/common/CMCOutputTemplate.java
@@ -25,6 +25,7 @@ import java.math.BigInteger;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
+import java.security.cert.CertificateExpiredException;
 import java.util.Date;
 import java.util.Hashtable;
 
@@ -55,9 +56,9 @@ import org.mozilla.jss.pkix.cmc.OtherInfo;
 import org.mozilla.jss.pkix.cmc.OtherMsg;
 import org.mozilla.jss.pkix.cmc.PendInfo;
 import org.mozilla.jss.pkix.cmc.ResponseBody;
+import org.mozilla.jss.pkix.cmc.RevokeRequest;
 import org.mozilla.jss.pkix.cmc.TaggedAttribute;
 import org.mozilla.jss.pkix.cmc.TaggedRequest;
-import org.mozilla.jss.pkix.cmmf.RevRequest;
 import org.mozilla.jss.pkix.cms.ContentInfo;
 import org.mozilla.jss.pkix.cms.EncapsulatedContentInfo;
 import org.mozilla.jss.pkix.cms.EnvelopedData;
@@ -76,8 +77,10 @@ import com.netscape.certsrv.base.SessionContext;
 import com.netscape.certsrv.ca.ICertificateAuthority;
 import com.netscape.certsrv.dbs.certdb.ICertRecord;
 import com.netscape.certsrv.dbs.certdb.ICertificateRepository;
+import com.netscape.certsrv.logging.AuditEvent;
 import com.netscape.certsrv.logging.AuditFormat;
 import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.logging.event.CertStatusChangeRequestProcessedEvent;
 import com.netscape.certsrv.profile.IEnrollProfile;
 import com.netscape.certsrv.request.IRequest;
 import com.netscape.certsrv.request.IRequestQueue;
@@ -101,6 +104,8 @@ import netscape.security.x509.X509Key;
  * @version $ $, $Date$
  */
 public class CMCOutputTemplate {
+    protected ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+
     public CMCOutputTemplate() {
     }
 
@@ -212,14 +217,12 @@ public class CMCOutputTemplate {
                     }
                 }
             } else {
-                CMS.debug(method + " reqs null.  why?");
+                CMS.debug(method + " reqs null. could be revocation");
             }
 
             TaggedAttribute tagattr = null;
             CMCStatusInfo cmcStatusInfo = null;
 
-//cfu
-
             SEQUENCE decryptedPOPBpids = (SEQUENCE) context.get("decryptedPOP");
             if (decryptedPOPBpids != null && decryptedPOPBpids.size() > 0) {
                 OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL,
@@ -882,8 +885,8 @@ public class CMCOutputTemplate {
                 String salt = "lala123" + date.toString();
                 byte[] dig;
                 try {
-                    MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
-                    dig = SHA1Digest.digest(salt.getBytes());
+                    MessageDigest SHA2Digest = MessageDigest.getInstance("SHA256");
+                    dig = SHA2Digest.digest(salt.getBytes());
                 } catch (NoSuchAlgorithmException ex) {
                     dig = salt.getBytes();
                 }
@@ -922,22 +925,59 @@ public class CMCOutputTemplate {
     private int processRevokeRequestControl(TaggedAttribute attr,
             SEQUENCE controlSeq, int bpid) throws InvalidBERException, EBaseException,
             IOException {
+        String method = "CMCOutputTemplate: processRevokeRequestControl: ";
+        String msg = "";
+        CMS.debug(method + "begins");
         boolean revoke = false;
         SessionContext context = SessionContext.getContext();
+        String authManagerId = (String) context.get(SessionContext.AUTH_MANAGER_ID);
+        if (authManagerId == null) {
+            CMS.debug(method + "authManagerId null.????");
+            //unlikely, but...
+            authManagerId = "none";
+        } else {
+            CMS.debug(method + "authManagerId =" + authManagerId);
+        }
+
+        // in case of CMCUserSignedAuth,
+        // for matching signer and revoked cert principal
+        X500Name signerPrincipal = null;
+
+        // for auditing
+        String auditRequesterID = null;
+        auditRequesterID = (String) context.get(SessionContext.USER_ID);
+
+        if (auditRequesterID != null) {
+            auditRequesterID = auditRequesterID.trim();
+        } else {
+            auditRequesterID = ILogger.NONROLEUSER;
+        }
+        signerPrincipal = (X500Name) context.get(SessionContext.CMC_SIGNER_PRINCIPAL);
+        String auditSubjectID = null;
+        String auditRequestType = "revoke";
+        String auditSerialNumber = null;
+        String auditReasonNum = null;
+        RequestStatus auditApprovalStatus = RequestStatus.REJECTED;
+
         if (attr != null) {
             INTEGER attrbpid = attr.getBodyPartID();
             CMCStatusInfo cmcStatusInfo = null;
             SET vals = attr.getValues();
             if (vals.size() > 0) {
-                RevRequest revRequest =
-                        (RevRequest) (ASN1Util.decode(new RevRequest.Template(),
-                                ASN1Util.encode(vals.elementAt(0))));
-                OCTET_STRING str = revRequest.getSharedSecret();
+                RevokeRequest revRequest = (RevokeRequest) (ASN1Util.decode(new RevokeRequest.Template(),
+                        ASN1Util.encode(vals.elementAt(0))));
+                OCTET_STRING reqSecret = revRequest.getSharedSecret();
                 INTEGER pid = attr.getBodyPartID();
                 TaggedAttribute tagattr = null;
                 INTEGER revokeCertSerial = revRequest.getSerialNumber();
+                ENUMERATED n = revRequest.getReason();
+                RevocationReason reason = toRevocationReason(n);
+                auditReasonNum = reason.toString();
                 BigInteger revokeSerial = new BigInteger(revokeCertSerial.toByteArray());
-                if (str == null) {
+                auditSerialNumber = revokeSerial.toString();
+
+                if (reqSecret == null) {
+                    CMS.debug(method + "no shared secret in request; Checking signature;");
                     boolean needVerify = true;
                     try {
                         needVerify = CMS.getConfigStore().getBoolean("cmc.revokeCert.verify", true);
@@ -945,67 +985,75 @@ public class CMCOutputTemplate {
                     }
 
                     if (needVerify) {
-                        Integer num1 = (Integer) context.get("numOfOtherMsgs");
-                        int num = num1.intValue();
-                        for (int i = 0; i < num; i++) {
-                            OtherMsg data = (OtherMsg) context.get("otherMsg" + i);
-                            INTEGER dpid = data.getBodyPartID();
-                            if (pid.longValue() == dpid.longValue()) {
-                                ANY msgValue = data.getOtherMsgValue();
-                                SignedData msgData =
-                                        (SignedData) msgValue.decodeWith(SignedData.getTemplate());
-                                if (!verifyRevRequestSignature(msgData)) {
-                                    OtherInfo otherInfo =
-                                            new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_MESSAGE_CHECK),
-                                                    null);
-                                    SEQUENCE failed_bpids = new SEQUENCE();
-                                    failed_bpids.addElement(attrbpid);
-                                    cmcStatusInfo =
-                                            new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null,
-                                                    otherInfo);
-                                    tagattr = new TaggedAttribute(
-                                            new INTEGER(bpid++),
-                                            OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo);
-                                    controlSeq.addElement(tagattr);
-                                    return bpid;
+                        if (authManagerId.equals("CMCUserSignedAuth")) {
+                            if (signerPrincipal == null) {
+                                CMS.debug(method + "missing CMC signer principal");
+                                OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL,
+                                        new INTEGER(OtherInfo.BAD_MESSAGE_CHECK),
+                                        null);
+                                SEQUENCE failed_bpids = new SEQUENCE();
+                                failed_bpids.addElement(attrbpid);
+                                cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null,
+                                        otherInfo);
+                                tagattr = new TaggedAttribute(
+                                        new INTEGER(bpid++),
+                                        OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo);
+                                controlSeq.addElement(tagattr);
+                                return bpid;
+                            }
+                        } else { // !CMCUserSignedAuth
+
+                            // this code is making the assumption that OtherMsg
+                            // is used for signer info in signed cmc revocation,
+                            // when in fact the signer info is
+                            // in the outer layer and should have already been
+                            // verified in the auth manager;
+                            // Left here for possible legacy client(s)
+
+                            Integer num1 = (Integer) context.get("numOfOtherMsgs");
+                            CMS.debug(method + "found numOfOtherMsgs =" + num1.toString());
+                            int num = num1.intValue();
+                            for (int i = 0; i < num; i++) {
+                                OtherMsg data = (OtherMsg) context.get("otherMsg" + i);
+                                INTEGER dpid = data.getBodyPartID();
+                                if (pid.longValue() == dpid.longValue()) {
+                                    CMS.debug(method + "body part id match;");
+                                    ANY msgValue = data.getOtherMsgValue();
+                                    SignedData msgData = (SignedData) msgValue.decodeWith(SignedData.getTemplate());
+                                    if (!verifyRevRequestSignature(msgData)) {
+                                        OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL,
+                                                new INTEGER(OtherInfo.BAD_MESSAGE_CHECK),
+                                                null);
+                                        SEQUENCE failed_bpids = new SEQUENCE();
+                                        failed_bpids.addElement(attrbpid);
+                                        cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids,
+                                                (String) null,
+                                                otherInfo);
+                                        tagattr = new TaggedAttribute(
+                                                new INTEGER(bpid++),
+                                                OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo);
+                                        controlSeq.addElement(tagattr);
+                                        return bpid;
+                                    }
+                                } else {
+                                    CMS.debug(method + "body part id do not match;");
                                 }
                             }
                         }
                     }
 
                     revoke = true;
+                } else { //use shared secret; request unsigned
+                    CMS.debug(method + "checking shared secret");
                     // check shared secret
-                } else {
-                    ISharedToken tokenClass = null;
-                    boolean sharedSecretFound = true;
-                    String name = null;
-                    try {
-                        name = CMS.getConfigStore().getString("cmc.revokeCert.sharedSecret.class");
-                    } catch (EPropertyNotFound e) {
-                        CMS.debug("EnrollProfile: Failed to find the token class in the configuration file.");
-                        sharedSecretFound = false;
-                    } catch (EBaseException e) {
-                        CMS.debug("EnrollProfile: Failed to find the token class in the configuration file.");
-                        sharedSecretFound = false;
-                    }
-
-                    try {
-                        tokenClass = (ISharedToken) Class.forName(name).newInstance();
-                    } catch (ClassNotFoundException e) {
-                        CMS.debug("EnrollProfile: Failed to find class name: " + name);
-                        sharedSecretFound = false;
-                    } catch (InstantiationException e) {
-                        CMS.debug("EnrollProfile: Failed to instantiate class: " + name);
-                        sharedSecretFound = false;
-                    } catch (IllegalAccessException e) {
-                        CMS.debug("EnrollProfile: Illegal access: " + name);
-                        sharedSecretFound = false;
-                    }
-
-                    if (!sharedSecretFound) {
-                        CMS.debug("CMCOutputTemplate: class for shared secret was not found.");
-                        OtherInfo otherInfo =
-                                new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.INTERNAL_CA_ERROR), null);
+                    //TODO: remember to provide one-time-use when working
+                    //      on shared token
+                    ISharedToken tokenClass =
+                            CMS.getSharedTokenClass("cmc.revokeCert.sharedSecret.class");
+                    if (tokenClass == null) {
+                        CMS.debug(method + " Failed to retrieve shared secret plugin class");
+                        OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.INTERNAL_CA_ERROR),
+                                null);
                         SEQUENCE failed_bpids = new SEQUENCE();
                         failed_bpids.addElement(attrbpid);
                         cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, otherInfo);
@@ -1016,15 +1064,13 @@ public class CMCOutputTemplate {
                         return bpid;
                     }
 
-                    String sharedSecret = null;
-                    if (tokenClass != null) {
-                        sharedSecret = tokenClass.getSharedToken(revokeSerial);
-                    }
+                    String sharedSecret = 
+                            sharedSecret = tokenClass.getSharedToken(revokeSerial);
 
                     if (sharedSecret == null) {
-                        CMS.debug("CMCOutputTemplate: class for shared secret was not found.");
-                        OtherInfo otherInfo =
-                                new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.INTERNAL_CA_ERROR), null);
+                        CMS.debug("CMCOutputTemplate: shared secret not found.");
+                        OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.INTERNAL_CA_ERROR),
+                                null);
                         SEQUENCE failed_bpids = new SEQUENCE();
                         failed_bpids.addElement(attrbpid);
                         cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, otherInfo);
@@ -1035,15 +1081,17 @@ public class CMCOutputTemplate {
                         return bpid;
                     }
 
-                    byte[] strb = str.toByteArray();
-                    String clientSC = new String(strb);
+                    byte[] reqSecretb = reqSecret.toByteArray();
+                    String clientSC = new String(reqSecretb);
                     if (clientSC.equals(sharedSecret)) {
-                        CMS.debug("CMCOutputTemplate: Both client and server shared secret are the same, can go ahead to revoke certificate.");
+                        CMS.debug(method
+                                + " Client and server shared secret are the same, can go ahead and revoke certificate.");
                         revoke = true;
                     } else {
-                        CMS.debug("CMCOutputTemplate: Both client and server shared secret are not the same, cant revoke certificate.");
-                        OtherInfo otherInfo =
-                                new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_MESSAGE_CHECK), null);
+                        CMS.debug(method
+                                + " Client and server shared secret are not the same, cannot revoke certificate.");
+                        OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_MESSAGE_CHECK),
+                                null);
                         SEQUENCE failed_bpids = new SEQUENCE();
                         failed_bpids.addElement(attrbpid);
                         cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, otherInfo);
@@ -1051,6 +1099,16 @@ public class CMCOutputTemplate {
                                 new INTEGER(bpid++),
                                 OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo);
                         controlSeq.addElement(tagattr);
+
+                        audit(new CertStatusChangeRequestProcessedEvent(
+                                auditSubjectID,
+                                ILogger.FAILURE,
+                                auditRequesterID,
+                                auditSerialNumber,
+                                auditRequestType,
+                                auditReasonNum,
+                                auditApprovalStatus));
+
                         return bpid;
                     }
                 }
@@ -1062,11 +1120,11 @@ public class CMCOutputTemplate {
                     try {
                         record = repository.readCertificateRecord(revokeSerial);
                     } catch (EBaseException ee) {
-                        CMS.debug("CMCOutputTemplate: Exception: " + ee.toString());
+                        CMS.debug(method + "Exception: " + ee.toString());
                     }
 
                     if (record == null) {
-                        CMS.debug("CMCOutputTemplate: The certificate is not found");
+                        CMS.debug(method + " The certificate is not found");
                         OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_CERT_ID), null);
                         SEQUENCE failed_bpids = new SEQUENCE();
                         failed_bpids.addElement(attrbpid);
@@ -1090,11 +1148,46 @@ public class CMCOutputTemplate {
                         controlSeq.addElement(tagattr);
                         return bpid;
                     }
+
                     X509CertImpl impl = record.getCertificate();
+
+                    X500Name certPrincipal = (X500Name) impl.getSubjectDN();
+                    auditSubjectID = certPrincipal.getCommonName();
+
+                    // in case of user-signed request, check if signer
+                    // principal matches that of the revoking cert
+                    if ((reqSecret == null) && authManagerId.equals("CMCUserSignedAuth")) {
+                        if (!certPrincipal.equals(signerPrincipal)) {
+                            msg = "certificate principal and signer do not match";
+                            CMS.debug(method + msg);
+                            OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_IDENTITY),
+                                    null);
+                            SEQUENCE failed_bpids = new SEQUENCE();
+                            failed_bpids.addElement(attrbpid);
+                            cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, msg,
+                                    otherInfo);
+                            tagattr = new TaggedAttribute(
+                                    new INTEGER(bpid++),
+                                    OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo);
+                            controlSeq.addElement(tagattr);
+
+                            audit(new CertStatusChangeRequestProcessedEvent(
+                                    auditSubjectID,
+                                    ILogger.FAILURE,
+                                    auditRequesterID,
+                                    auditSerialNumber,
+                                    auditRequestType,
+                                    auditReasonNum,
+                                    auditApprovalStatus));
+
+                            return bpid;
+                        } else {
+                            CMS.debug(method + "certificate principal and signer match");
+                        }
+                    }
+
                     X509CertImpl[] impls = new X509CertImpl[1];
                     impls[0] = impl;
-                    ENUMERATED n = revRequest.getReason();
-                    RevocationReason reason = toRevocationReason(n);
                     CRLReasonExtension crlReasonExtn = new CRLReasonExtension(reason);
                     CRLExtensions entryExtn = new CRLExtensions();
                     GeneralizedTime t = revRequest.getInvalidityDate();
@@ -1107,8 +1200,8 @@ public class CMCOutputTemplate {
                         entryExtn.set(crlReasonExtn.getName(), crlReasonExtn);
                     }
 
-                    RevokedCertImpl revCertImpl =
-                            new RevokedCertImpl(impl.getSerialNumber(), CMS.getCurrentDate(), entryExtn);
+                    RevokedCertImpl revCertImpl = new RevokedCertImpl(impl.getSerialNumber(), CMS.getCurrentDate(),
+                            entryExtn);
                     RevokedCertImpl[] revCertImpls = new RevokedCertImpl[1];
                     revCertImpls[0] = revCertImpl;
                     IRequestQueue queue = ca.getRequestQueue();
@@ -1124,20 +1217,30 @@ public class CMCOutputTemplate {
                     RequestStatus stat = revReq.getRequestStatus();
                     if (stat == RequestStatus.COMPLETE) {
                         Integer result = revReq.getExtDataInInteger(IRequest.RESULT);
-                        CMS.debug("CMCOutputTemplate: revReq result = " + result);
+                        CMS.debug(method + " revReq result = " + result);
                         if (result.equals(IRequest.RES_ERROR)) {
                             CMS.debug("CMCOutputTemplate: revReq exception: " +
                                     revReq.getExtDataInString(IRequest.ERROR));
-                            OtherInfo otherInfo =
-                                    new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_REQUEST), null);
+                            OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_REQUEST),
+                                    null);
                             SEQUENCE failed_bpids = new SEQUENCE();
                             failed_bpids.addElement(attrbpid);
-                            cmcStatusInfo =
-                                    new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null, otherInfo);
+                            cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.FAILED, failed_bpids, (String) null,
+                                    otherInfo);
                             tagattr = new TaggedAttribute(
                                     new INTEGER(bpid++),
                                     OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo);
                             controlSeq.addElement(tagattr);
+
+                            audit(new CertStatusChangeRequestProcessedEvent(
+                                    auditSubjectID,
+                                    ILogger.FAILURE,
+                                    auditRequesterID,
+                                    auditSerialNumber,
+                                    auditRequestType,
+                                    auditReasonNum,
+                                    auditApprovalStatus));
+
                             return bpid;
                         }
                     }
@@ -1150,7 +1253,7 @@ public class CMCOutputTemplate {
                                     impl.getSubjectDN(),
                                     impl.getSerialNumber().toString(16),
                                     reason.toString() });
-                    CMS.debug("CMCOutputTemplate: Certificate get revoked.");
+                    CMS.debug(method + " Certificate revoked.");
                     SEQUENCE success_bpids = new SEQUENCE();
                     success_bpids.addElement(attrbpid);
                     cmcStatusInfo = new CMCStatusInfo(CMCStatusInfo.SUCCESS,
@@ -1159,6 +1262,16 @@ public class CMCOutputTemplate {
                             new INTEGER(bpid++),
                             OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo);
                     controlSeq.addElement(tagattr);
+
+                    auditApprovalStatus = RequestStatus.COMPLETE;
+                    audit(new CertStatusChangeRequestProcessedEvent(
+                            auditSubjectID,
+                            ILogger.SUCCESS,
+                            auditRequesterID,
+                            auditSerialNumber,
+                            auditRequestType,
+                            auditReasonNum,
+                            auditApprovalStatus));
                     return bpid;
                 } else {
                     OtherInfo otherInfo = new OtherInfo(OtherInfo.FAIL, new INTEGER(OtherInfo.BAD_MESSAGE_CHECK), null);
@@ -1169,6 +1282,16 @@ public class CMCOutputTemplate {
                             new INTEGER(bpid++),
                             OBJECT_IDENTIFIER.id_cmc_cMCStatusInfo, cmcStatusInfo);
                     controlSeq.addElement(tagattr);
+
+                    audit(new CertStatusChangeRequestProcessedEvent(
+                            auditSubjectID,
+                            ILogger.FAILURE,
+                            auditRequesterID,
+                            auditSerialNumber,
+                            auditRequestType,
+                            auditReasonNum,
+                            auditApprovalStatus));
+
                     return bpid;
                 }
             }
@@ -1177,54 +1300,81 @@ public class CMCOutputTemplate {
         return bpid;
     }
 
+    protected void audit(AuditEvent event) {
+
+        String template = event.getMessage();
+        Object[] params = event.getParameters();
+
+        String message = CMS.getLogMessage(template, params);
+
+        audit(message);
+    }
+
+    protected void audit(String msg) {
+        // in this case, do NOT strip preceding/trailing whitespace
+        // from passed-in String parameters
+
+        if (mSignedAuditLogger == null) {
+            return;
+        }
+
+        mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+                null,
+                ILogger.S_SIGNED_AUDIT,
+                ILogger.LL_SECURITY,
+                msg);
+    }
+
     private RevocationReason toRevocationReason(ENUMERATED n) {
         long code = n.getValue();
-        if (code == RevRequest.aACompromise.getValue())
+        if (code == RevokeRequest.aACompromise.getValue())
             return RevocationReason.UNSPECIFIED;
-        else if (code == RevRequest.affiliationChanged.getValue())
+        else if (code == RevokeRequest.affiliationChanged.getValue())
             return RevocationReason.AFFILIATION_CHANGED;
-        else if (code == RevRequest.cACompromise.getValue())
+        else if (code == RevokeRequest.cACompromise.getValue())
             return RevocationReason.CA_COMPROMISE;
-        else if (code == RevRequest.certificateHold.getValue())
+        else if (code == RevokeRequest.certificateHold.getValue())
             return RevocationReason.CERTIFICATE_HOLD;
-        else if (code == RevRequest.cessationOfOperation.getValue())
+        else if (code == RevokeRequest.cessationOfOperation.getValue())
             return RevocationReason.CESSATION_OF_OPERATION;
-        else if (code == RevRequest.keyCompromise.getValue())
+        else if (code == RevokeRequest.keyCompromise.getValue())
             return RevocationReason.KEY_COMPROMISE;
-        else if (code == RevRequest.privilegeWithdrawn.getValue())
+        else if (code == RevokeRequest.privilegeWithdrawn.getValue())
             return RevocationReason.UNSPECIFIED;
-        else if (code == RevRequest.removeFromCRL.getValue())
+        else if (code == RevokeRequest.removeFromCRL.getValue())
             return RevocationReason.REMOVE_FROM_CRL;
-        else if (code == RevRequest.superseded.getValue())
+        else if (code == RevokeRequest.superseded.getValue())
             return RevocationReason.SUPERSEDED;
-        else if (code == RevRequest.unspecified.getValue())
+        else if (code == RevokeRequest.unspecified.getValue())
             return RevocationReason.UNSPECIFIED;
         return RevocationReason.UNSPECIFIED;
     }
 
     private boolean verifyRevRequestSignature(SignedData msgData) {
+        String method = "CMCOutputTemplate: verifyRevRequestSignature: ";
+        CMS.debug(method + "begins");
         try {
             EncapsulatedContentInfo ci = msgData.getContentInfo();
             OCTET_STRING content = ci.getContent();
             ByteArrayInputStream s = new ByteArrayInputStream(content.toByteArray());
             TaggedAttribute tattr = (TaggedAttribute) (new TaggedAttribute.Template()).decode(s);
             SET values = tattr.getValues();
-            RevRequest revRequest = null;
-            if (values != null && values.size() > 0)
-                revRequest =
-                        (RevRequest) (ASN1Util.decode(new RevRequest.Template(),
-                                ASN1Util.encode(values.elementAt(0))));
+            RevokeRequest revRequest = null;
+            if (values != null && values.size() > 0) {
+                revRequest = (RevokeRequest) (ASN1Util.decode(new RevokeRequest.Template(),
+                        ASN1Util.encode(values.elementAt(0))));
+            } else {
+                CMS.debug(method + "attribute null");
+                return false;
+            }
 
             SET dias = msgData.getDigestAlgorithmIdentifiers();
             int numDig = dias.size();
             Hashtable<String, byte[]> digs = new Hashtable<String, byte[]>();
             for (int i = 0; i < numDig; i++) {
-                AlgorithmIdentifier dai =
-                        (AlgorithmIdentifier) dias.elementAt(i);
-                String name =
-                        DigestAlgorithm.fromOID(dai.getOID()).toString();
-                MessageDigest md =
-                        MessageDigest.getInstance(name);
+                AlgorithmIdentifier dai = (AlgorithmIdentifier) dias.elementAt(i);
+                String name = DigestAlgorithm.fromOID(dai.getOID()).toString();
+                MessageDigest md = MessageDigest.getInstance(name);
                 byte[] digest = md.digest(content.toByteArray());
                 digs.put(name, digest);
             }
@@ -1232,8 +1382,7 @@ public class CMCOutputTemplate {
             SET sis = msgData.getSignerInfos();
             int numSis = sis.size();
             for (int i = 0; i < numSis; i++) {
-                org.mozilla.jss.pkix.cms.SignerInfo si =
-                        (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(i);
+                org.mozilla.jss.pkix.cms.SignerInfo si = (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(i);
                 String name = si.getDigestAlgorithm().toString();
                 byte[] digest = digs.get(name);
                 if (digest == null) {
@@ -1244,17 +1393,15 @@ public class CMCOutputTemplate {
                 }
                 SignerIdentifier sid = si.getSignerIdentifier();
                 if (sid.getType().equals(SignerIdentifier.ISSUER_AND_SERIALNUMBER)) {
-                    org.mozilla.jss.pkix.cms.IssuerAndSerialNumber issuerAndSerialNumber =
-                            sid.getIssuerAndSerialNumber();
+                    org.mozilla.jss.pkix.cms.IssuerAndSerialNumber issuerAndSerialNumber = sid
+                            .getIssuerAndSerialNumber();
                     java.security.cert.X509Certificate cert = null;
                     if (msgData.hasCertificates()) {
                         SET certs = msgData.getCertificates();
                         int numCerts = certs.size();
                         for (int j = 0; j < numCerts; j++) {
-                            org.mozilla.jss.pkix.cert.Certificate certJss =
-                                    (Certificate) certs.elementAt(j);
-                            org.mozilla.jss.pkix.cert.CertificateInfo certI =
-                                    certJss.getInfo();
+                            org.mozilla.jss.pkix.cert.Certificate certJss = (Certificate) certs.elementAt(j);
+                            org.mozilla.jss.pkix.cert.CertificateInfo certI = certJss.getInfo();
                             Name issuer = certI.getIssuer();
                             byte[] issuerB = ASN1Util.encode(issuer);
                             INTEGER sn = certI.getSerialNumber();
@@ -1270,11 +1417,33 @@ public class CMCOutputTemplate {
                     }
 
                     if (cert != null) {
+                        CMS.debug(method + "found cert");
                         PublicKey pbKey = cert.getPublicKey();
                         PK11PubKey pubK = PK11PubKey.fromSPKI(((X509Key) pbKey).getKey());
                         si.verify(digest, ci.getContentType(), pubK);
+
+                        // now check validity of the cert
+                        java.security.cert.X509Certificate[] x509Certs = new java.security.cert.X509Certificate[1];
+                        x509Certs[0] = cert;
+                        if (CMS.isRevoked(x509Certs)) {
+                            CMS.debug(method + "CMC signing cert is a revoked certificate");
+                            return false;
+                        }
+                        try {
+                            cert.checkValidity();
+                        } catch (CertificateExpiredException e) {
+                            CMS.debug(method + "CMC signing cert is an expired certificate");
+                            return false;
+                        } catch (Exception e) {
+                            return false;
+                        }
+
                         return true;
+                    } else {
+                        CMS.debug(method + "cert not found");
                     }
+                } else {
+                    CMS.debug(method + "unsupported SignerIdentifier for CMC revocation");
                 }
             }
 
diff --git a/base/server/cms/src/com/netscape/cms/servlet/common/GenPendingTemplateFiller.java b/base/server/cms/src/com/netscape/cms/servlet/common/GenPendingTemplateFiller.java
index 83a2d8c..4578a98 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/common/GenPendingTemplateFiller.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/common/GenPendingTemplateFiller.java
@@ -158,9 +158,9 @@ public class GenPendingTemplateFiller implements ICMSTemplateFiller {
                 byte[] dig;
 
                 try {
-                    MessageDigest SHA1Digest = MessageDigest.getInstance("SHA1");
+                    MessageDigest SHA2Digest = MessageDigest.getInstance("SHA256");
 
-                    dig = SHA1Digest.digest(salt.getBytes());
+                    dig = SHA2Digest.digest(salt.getBytes());
                 } catch (NoSuchAlgorithmException ex) {
                     dig = salt.getBytes();
                 }
@@ -199,16 +199,15 @@ public class GenPendingTemplateFiller implements ICMSTemplateFiller {
                     SignerIdentifier si = new
                             SignerIdentifier(SignerIdentifier.ISSUER_AND_SERIALNUMBER, ias, null);
 
-                    // SHA1 is the default digest Alg for now.
                     DigestAlgorithm digestAlg = null;
                     SignatureAlgorithm signAlg = null;
                     org.mozilla.jss.crypto.PrivateKey privKey = CryptoManager.getInstance().findPrivKeyByCert(x509cert);
                     org.mozilla.jss.crypto.PrivateKey.Type keyType = privKey.getType();
 
                     if (keyType.equals(org.mozilla.jss.crypto.PrivateKey.RSA)) {
-                        signAlg = SignatureAlgorithm.RSASignatureWithSHA1Digest;
-                    } else if (keyType.equals(org.mozilla.jss.crypto.PrivateKey.DSA)) {
-                        signAlg = SignatureAlgorithm.DSASignatureWithSHA1Digest;
+                        signAlg = SignatureAlgorithm.RSASignatureWithSHA256Digest;
+                    } else if (keyType.equals(org.mozilla.jss.crypto.PrivateKey.EC)) {
+                        signAlg = SignatureAlgorithm.ECSignatureWithSHA256Digest;
                     } else {
                         CMS.debug("GenPendingTemplateFiller::getTemplateParams() - "
                                  + "keyType " + keyType.toString()
@@ -220,8 +219,8 @@ public class GenPendingTemplateFiller implements ICMSTemplateFiller {
                     byte[] digest = null;
 
                     try {
-                        SHADigest = MessageDigest.getInstance("SHA1");
-                        digestAlg = DigestAlgorithm.SHA1;
+                        SHADigest = MessageDigest.getInstance("SHA256");
+                        digestAlg = DigestAlgorithm.SHA256;
 
                         ByteArrayOutputStream ostream = new ByteArrayOutputStream();
 
diff --git a/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileSubmitCMCServlet.java b/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileSubmitCMCServlet.java
index 93039a4..330b5ff 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileSubmitCMCServlet.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/profile/ProfileSubmitCMCServlet.java
@@ -413,7 +413,7 @@ public class ProfileSubmitCMCServlet extends ProfileServlet {
         }
 
         setInputsIntoContext(request, profile, ctx);
-        CMS.debug("ProfileSubmistServlet: set Inputs into Context");
+        CMS.debug("ProfileSubmitCMCServlet: set Inputs into Context");
 
         // before creating the request, authenticate the request
 
@@ -560,9 +560,14 @@ public class ProfileSubmitCMCServlet extends ProfileServlet {
         // In case of decryptedPOP, request already exists, find it and
         // put in provedReq.
         IRequest provedReq = null;
+        boolean isRevoke = false;
         if (reqs == null) {
             // handling DecryptedPOP request here
             Integer reqID = (Integer) context.get("cmcDecryptedPopReqId");
+            if (reqID == null) {
+                CMS.debug("ProfileSubmitCMCServlet: revocation request");
+                isRevoke = true;
+            } else {
             provedReq = profile.getRequestQueue().findRequest(new RequestId(reqID.toString()));
             if (provedReq == null) {
 
@@ -584,6 +589,7 @@ public class ProfileSubmitCMCServlet extends ProfileServlet {
             } else {
                 CMS.debug("ProfileSubmitCMCServlet: provedReq not null");
             }
+            }
         }
 
         String errorCode = null;
@@ -592,7 +598,7 @@ public class ProfileSubmitCMCServlet extends ProfileServlet {
         ///////////////////////////////////////////////
         // populate request
         ///////////////////////////////////////////////
-        for (int k = 0; (provedReq == null) &&(k < reqs.length); k++) {
+        for (int k = 0; (!isRevoke) && (provedReq == null) &&(k < reqs.length); k++) {
             // adding parameters to request
             setInputsIntoRequest(request, profile, reqs[k]);
 
@@ -712,7 +718,7 @@ public class ProfileSubmitCMCServlet extends ProfileServlet {
             if (reqs != null && reqs.length > 0)
                 error_codes = new int[reqs.length];
 
-            for (int k = 0; (provedReq == null) && (k < reqs.length); k++) {
+            for (int k = 0; (!isRevoke) && (provedReq == null) && (k < reqs.length); k++) {
                 try {
                     // reset the "auditRequesterID"
                     auditRequesterID = auditRequesterID(reqs[k]);
diff --git a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
index 94a0783..b111f71 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
@@ -62,6 +62,7 @@ import org.mozilla.jss.util.PasswordCallback;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
+import com.netscape.certsrv.authentication.ISharedToken;
 import com.netscape.certsrv.acls.ACL;
 import com.netscape.certsrv.acls.ACLEntry;
 import com.netscape.certsrv.acls.EACLsException;
@@ -1912,6 +1913,38 @@ public class CMSEngine implements ICMSEngine {
         }
     }
 
+    public ISharedToken getSharedTokenClass(String configName) {
+        String method = "CMSEngine: getSharedTokenClass: ";
+        ISharedToken tokenClass = null;
+
+        String name = null;
+        try {
+            CMS.debug(method + "getting :" + configName);
+            name = CMS.getConfigStore().getString(configName);
+            CMS.debug(method + "Shared Secret plugin class name retrieved:" +
+                    name);
+        } catch (Exception e) {
+            CMS.debug(method + " Failed to retrieve shared secret plugin class name");
+            return null;
+        }
+
+        try {
+            tokenClass = (ISharedToken) Class.forName(name).newInstance();
+            CMS.debug(method + "Shared Secret plugin class retrieved");
+        } catch (ClassNotFoundException e) {
+            CMS.debug(method + " Failed to find class name: " + name);
+            return null;
+        } catch (InstantiationException e) {
+            CMS.debug("EnrollProfile: Failed to instantiate class: " + name);
+            return null;
+        } catch (IllegalAccessException e) {
+            CMS.debug(method + " Illegal access: " + name);
+            return null;
+        }
+
+        return tokenClass;
+    }
+
     public ILogger getLogger() {
         return Logger.getLogger();
     }
diff --git a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java
index dd28adb..b314dac 100644
--- a/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java
+++ b/base/server/test/com/netscape/cmscore/app/CMSEngineDefaultStub.java
@@ -23,6 +23,7 @@ import com.netscape.certsrv.acls.EACLsException;
 import com.netscape.certsrv.acls.IACL;
 import com.netscape.certsrv.apps.ICMSEngine;
 import com.netscape.certsrv.apps.ICommandQueue;
+import com.netscape.certsrv.authentication.ISharedToken;
 import com.netscape.certsrv.authority.IAuthority;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IArgBlock;
@@ -370,6 +371,10 @@ public class CMSEngineDefaultStub implements ICMSEngine {
         return null;
     }
 
+    public ISharedToken getSharedTokenClass(String configName) {
+        return null;
+    }
+
     public void putPasswordCache(String tag, String pw) {
     }
 
diff --git a/base/util/src/com/netscape/cmsutil/util/Utils.java b/base/util/src/com/netscape/cmsutil/util/Utils.java
index 98becdc..933432d 100644
--- a/base/util/src/com/netscape/cmsutil/util/Utils.java
+++ b/base/util/src/com/netscape/cmsutil/util/Utils.java
@@ -285,6 +285,11 @@ public class Utils {
         return string;
     }
 
+    public static String base64encodeSingleLine(byte[] bytes) {
+        String string = new Base64().encodeToString(bytes);
+        return string;
+    }
+ 
     public static byte[] base64decode(String string) {
         byte[] bytes = Base64.decodeBase64(string);
         return bytes;
-- 
2.7.4

