Blob Blame History Raw
From aa39354dbbf9df404f6ad374c837db0c421f2705 Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu@redhat.com>
Date: Mon, 5 Jun 2017 08:50:25 -0700
Subject: [PATCH 01/14] Ticket #2617 part2: add revocation check to signing
 cert

---
 .../cms/authentication/CMCUserSignedAuth.java         | 19 +++++++++++++++++++
 .../authentication/CertUserDBAuthentication.java      |  2 +-
 2 files changed, 20 insertions(+), 1 deletion(-)

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 2128c1e..a18c25e 100644
--- a/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
+++ b/base/server/cms/src/com/netscape/cms/authentication/CMCUserSignedAuth.java
@@ -29,6 +29,7 @@ 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.util.Enumeration;
@@ -1076,7 +1077,10 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                             si.verify(digest, id, pubK);
                         }
                         CMS.debug(method + "finished checking signature");
+
                         // verify signer's certificate using the revocator
+                        // ...or not;  I think it just checks usage and
+                        // validity, but not revocation status
                         if (!cm.isCertValid(certByteArray, true, CryptoManager.CertUsage.SSLClient)) {
                             CMS.debug(method + "CMC signature failed to be verified");
                             s.close();
@@ -1086,6 +1090,21 @@ public class CMCUserSignedAuth implements IAuthManager, IExtendedPluginInfo,
                         }
                         // At this point, the signature has been verified;
 
+                        // now check revocation status of the cert
+                        if (CMS.isRevoked(x509Certs)) {
+                            CMS.debug(method + "CMC signing cert is a revoked certificate");
+                            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");
+                            throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+                        } catch (Exception e) {
+                            CMS.debug(method + e.toString());
+                            throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+                        }
+
                         IAuthToken tempToken = new AuthToken(null);
 /*
                         netscape.security.x509.X500Name tempPrincipal = (X500Name) x509Certs[0].getSubjectDN();
diff --git a/base/server/cmscore/src/com/netscape/cmscore/authentication/CertUserDBAuthentication.java b/base/server/cmscore/src/com/netscape/cmscore/authentication/CertUserDBAuthentication.java
index 998d7e2..ae450fa 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/authentication/CertUserDBAuthentication.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/authentication/CertUserDBAuthentication.java
@@ -168,7 +168,7 @@ public class CertUserDBAuthentication implements IAuthManager, ICertUserDBAuthen
         try {
             user = (User) mCULocator.locateUser(certs);
         } catch (EUsrGrpException e) {
-            CMS.debug("CertUserDBAuthentication: cannot map certificate to any user");
+            CMS.debug("CertUserDBAuthentication: cannot map certificate to any user" + e);
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_AUTH_AGENT_AUTH_FAILED", x509Certs[0].getSerialNumber()
                     .toString(16), x509Certs[0].getSubjectDN().toString(), e.toString()));
             throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
-- 
1.8.3.1


From 30fb7bf49ce0f4c726f937b3984a4e27abb39959 Mon Sep 17 00:00:00 2001
From: Jack Magne <jmagne@dhcp-16-206.sjc.redhat.com>
Date: Tue, 6 Jun 2017 16:16:32 -0700
Subject: [PATCH 04/14] Minor fix to already fixed issue:

The problem was that a tiny piece of the original patch didn't get checked in. This resolves this issue.
---
 base/native-tools/src/tkstool/key.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/base/native-tools/src/tkstool/key.c b/base/native-tools/src/tkstool/key.c
index e63da93..f208cbd 100644
--- a/base/native-tools/src/tkstool/key.c
+++ b/base/native-tools/src/tkstool/key.c
@@ -1219,13 +1219,14 @@ TKS_StoreSymmetricKeyAndNameIt( char              *symmetricKeyName,
     rvExtractSymmetricKey = PK11_ExtractKeyValue( /* symmetric key */ symKey );
     if( rvExtractSymmetricKey != SECSuccess ) {
         PR_fprintf( PR_STDERR,
-                    "ERROR:  Failed to extract the %s key!\n\n",
+                    "ERROR:  Failed to extract the %s key for final display, OK if in FIPs mode!\n\n",
                     symmetricKeyName );
-        goto destroyHexSymmetricKey;
-    }
+        symmetricKey = NULL;
+    } else {
 
-    /* If present, retrieve the raw key data */
-    symmetricKey = PK11_GetKeyData( /* symmetric key */  symKey );
+        /* If present, retrieve the raw key data */
+        symmetricKey = PK11_GetKeyData( /* symmetric key */  symKey );
+    }
 
 #if defined(DEBUG)
     /* For convenience, display the final symmetric key and */
-- 
1.8.3.1


From 38df4274214938ceece85627abb6d4fe77b960ff Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Fri, 26 May 2017 13:06:18 -0400
Subject: [PATCH 06/14] Refactor client to not use keysets

It is simpler to simply tell the client which
algorithm to use for key wrapping and encryption, rather
than use key sets.  Therefore:

* KRAInfo and CAInfo are refactored to provide the
  algorithms required for key wrapping and encryption.

* Client is modified to use these parameters to determine
  which algorithms to use.

* We specify the OIDs that will be used in the PKIARchiveOptions
  more correctly.  The options are basically:
  AES-128-CBC, DES3-CBC, AES KeyWrap/Pad

Change-Id: Ic3fca902bbc45f7f72bcd4676c994f8a89c3a409
---
 base/common/src/org/dogtagpki/common/CAInfo.java   |  34 +++--
 base/common/src/org/dogtagpki/common/KRAInfo.java  |  34 +++++
 .../src/com/netscape/cmstools/CRMFPopClient.java   | 153 ++++++++++-----------
 .../cmstools/client/ClientCertRequestCLI.java      |  34 +----
 .../org/dogtagpki/server/rest/CAInfoService.java   |  18 +--
 .../org/dogtagpki/server/rest/KRAInfoService.java  |  40 +++++-
 .../com/netscape/cmsutil/crypto/CryptoUtil.java    |  22 +++
 7 files changed, 206 insertions(+), 129 deletions(-)

diff --git a/base/common/src/org/dogtagpki/common/CAInfo.java b/base/common/src/org/dogtagpki/common/CAInfo.java
index f21dcd0..0f68c7a 100644
--- a/base/common/src/org/dogtagpki/common/CAInfo.java
+++ b/base/common/src/org/dogtagpki/common/CAInfo.java
@@ -54,7 +54,8 @@ public class CAInfo extends ResourceMessage {
     }
 
     String archivalMechanism;
-    String wrappingKeySet;
+    String encryptAlgorithm;
+    String keyWrapAlgorithm;
 
     @XmlElement(name="ArchivalMechanism")
     public String getArchivalMechanism() {
@@ -65,13 +66,20 @@ public class CAInfo extends ResourceMessage {
         this.archivalMechanism = archivalMechanism;
     }
 
-    @XmlElement(name="WrappingKeySet")
-    public String getWrappingKeySet() {
-        return wrappingKeySet;
+    public String getEncryptAlgorithm() {
+        return encryptAlgorithm;
     }
 
-    public void setWrappingKeySet(String wrappingKeySet) {
-        this.wrappingKeySet = wrappingKeySet;
+    public void setEncryptAlgorithm(String encryptAlgorithm) {
+        this.encryptAlgorithm = encryptAlgorithm;
+    }
+
+    public String getKeyWrapAlgorithm() {
+        return keyWrapAlgorithm;
+    }
+
+    public void setKeyWrapAlgorithm(String keyWrapAlgorithm) {
+        this.keyWrapAlgorithm = keyWrapAlgorithm;
     }
 
     @Override
@@ -79,7 +87,8 @@ public class CAInfo extends ResourceMessage {
         final int prime = 31;
         int result = super.hashCode();
         result = prime * result + ((archivalMechanism == null) ? 0 : archivalMechanism.hashCode());
-        result = prime * result + ((wrappingKeySet == null) ? 0 : wrappingKeySet.hashCode());
+        result = prime * result + ((encryptAlgorithm == null) ? 0 : encryptAlgorithm.hashCode());
+        result = prime * result + ((keyWrapAlgorithm == null) ? 0 : keyWrapAlgorithm.hashCode());
         return result;
     }
 
@@ -97,10 +106,15 @@ public class CAInfo extends ResourceMessage {
                 return false;
         } else if (!archivalMechanism.equals(other.archivalMechanism))
             return false;
-        if (wrappingKeySet == null) {
-            if (other.wrappingKeySet != null)
+        if (encryptAlgorithm == null) {
+            if (other.encryptAlgorithm != null)
+                return false;
+        } else if (!encryptAlgorithm.equals(other.encryptAlgorithm))
+            return false;
+        if (keyWrapAlgorithm == null) {
+            if (other.keyWrapAlgorithm != null)
                 return false;
-        } else if (!wrappingKeySet.equals(other.wrappingKeySet))
+        } else if (!keyWrapAlgorithm.equals(other.keyWrapAlgorithm))
             return false;
         return true;
     }
diff --git a/base/common/src/org/dogtagpki/common/KRAInfo.java b/base/common/src/org/dogtagpki/common/KRAInfo.java
index e17bd64..66fb992 100644
--- a/base/common/src/org/dogtagpki/common/KRAInfo.java
+++ b/base/common/src/org/dogtagpki/common/KRAInfo.java
@@ -55,6 +55,8 @@ public class KRAInfo extends ResourceMessage {
 
     String archivalMechanism;
     String recoveryMechanism;
+    String encryptAlgorithm;
+    String wrapAlgorithm;
 
     @XmlElement(name="ArchivalMechanism")
     public String getArchivalMechanism() {
@@ -74,12 +76,32 @@ public class KRAInfo extends ResourceMessage {
         this.recoveryMechanism = recoveryMechanism;
     }
 
+    @XmlElement(name="EncryptAlgorithm")
+    public String getEncryptAlgorithm() {
+        return encryptAlgorithm;
+    }
+
+    public void setEncryptAlgorithm(String encryptAlgorithm) {
+        this.encryptAlgorithm = encryptAlgorithm;
+    }
+
+    @XmlElement(name="WrapAlgorithm")
+    public String getWrapAlgorithm() {
+        return wrapAlgorithm;
+    }
+
+    public void setWrapAlgorithm(String wrapAlgorithm) {
+        this.wrapAlgorithm = wrapAlgorithm;
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = super.hashCode();
         result = prime * result + ((archivalMechanism == null) ? 0 : archivalMechanism.hashCode());
+        result = prime * result + ((encryptAlgorithm == null) ? 0 : encryptAlgorithm.hashCode());
         result = prime * result + ((recoveryMechanism == null) ? 0 : recoveryMechanism.hashCode());
+        result = prime * result + ((wrapAlgorithm == null) ? 0 : wrapAlgorithm.hashCode());
         return result;
     }
 
@@ -97,11 +119,21 @@ public class KRAInfo extends ResourceMessage {
                 return false;
         } else if (!archivalMechanism.equals(other.archivalMechanism))
             return false;
+        if (encryptAlgorithm == null) {
+            if (other.encryptAlgorithm != null)
+                return false;
+        } else if (!encryptAlgorithm.equals(other.encryptAlgorithm))
+            return false;
         if (recoveryMechanism == null) {
             if (other.recoveryMechanism != null)
                 return false;
         } else if (!recoveryMechanism.equals(other.recoveryMechanism))
             return false;
+        if (wrapAlgorithm == null) {
+            if (other.wrapAlgorithm != null)
+                return false;
+        } else if (!wrapAlgorithm.equals(other.wrapAlgorithm))
+            return false;
         return true;
     }
 
@@ -125,6 +157,8 @@ public class KRAInfo extends ResourceMessage {
         KRAInfo before = new KRAInfo();
         before.setArchivalMechanism("encrypt");
         before.setRecoveryMechanism("keywrap");
+        before.setEncryptAlgorithm("AES/CBC/Pad");
+        before.setWrapAlgorithm("AES KeyWrap/Padding");
 
         String string = before.toString();
         System.out.println(string);
diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
index 0057a1d..b06faa6 100644
--- a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
+++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
@@ -190,11 +190,7 @@ public class CRMFPopClient {
         option.setArgName("extractable");
         options.addOption(option);
 
-        option = new Option("g", true, "KeyWrap");
-        option.setArgName("keyWrap");
-        options.addOption(option);
-
-        option = new Option("w", true, "Wrapping Keyset");
+        option = new Option("w", true, "Algorithm to be used for key wrapping");
         option.setArgName("keySet");
         options.addOption(option);
 
@@ -231,10 +227,7 @@ public class CRMFPopClient {
         System.out.println("                               - POP_NONE: without POP");
         System.out.println("                               - POP_SUCCESS: with valid POP");
         System.out.println("                               - POP_FAIL: with invalid POP (for testing)");
-        System.out.println("  -g <true|false>              Use KeyWrapping to wrap private key (default: true)");
-        System.out.println("                               - true: use a key wrapping algorithm");
-        System.out.println("                               - false: use an encryption algorithm");
-        System.out.println("  -w <keyset_id>               Key set ID to use when wrapping the private key");
+        System.out.println("  -w <keywrap algorithm>       Algorithm to use for key wrapping");
         System.out.println("  -b <transport cert>          PEM transport certificate (default: transport.txt)");
         System.out.println("  -v, --verbose                Run in verbose mode.");
         System.out.println("      --help                   Show help message.");
@@ -329,20 +322,17 @@ public class CRMFPopClient {
 
         boolean self_sign = cmd.hasOption("y");
 
-        // get the key wrapping mechanism
-        boolean keyWrap = true;
-        if (cmd.hasOption("g")) {
-            keyWrap = Boolean.parseBoolean(cmd.getOptionValue("g"));
+        // get the keywrap algorithm
+        KeyWrapAlgorithm keyWrapAlgorithm = null;
+        String kwAlg = KeyWrapAlgorithm.AES_KEY_WRAP_PAD.toString();
+        if (cmd.hasOption("w")) {
+            kwAlg = cmd.getOptionValue("w");
         } else {
-            String useKeyWrap = System.getenv("KEY_ARCHIVAL_USE_KEY_WRAPPING");
-            if (useKeyWrap != null) {
-                keyWrap = Boolean.parseBoolean(useKeyWrap);
+            String alg = System.getenv("KEY_ARCHIVAL_KEYWRAP_ALGORITHM");
+            if (alg != null) {
+                kwAlg = alg;
             }
         }
-        String archivalMechanism = keyWrap ? KRAInfoResource.KEYWRAP_MECHANISM :
-            KRAInfoResource.ENCRYPT_MECHANISM;
-
-        String wrappingKeySet = cmd.getOptionValue("w");
 
         String output = cmd.getOptionValue("o");
 
@@ -351,12 +341,11 @@ public class CRMFPopClient {
         String requestor = cmd.getOptionValue("r");
 
         if (hostPort != null) {
-            if (cmd.hasOption("g") || cmd.hasOption("w")) {
-                printError("Wrapping Key Set (-g) and keywrap (-w) options should " +
-                        "not be specified when hostport is specified.  " +
-                        "CRMFPopClient will contact the server to " +
-                        "determine the correct values for these parameters");
-                System.exit(1);
+            if (cmd.hasOption("w")) {
+                printError("Any value specified for the key wrap parameter (-w) " +
+                        "will be overriden.  CRMFPopClient will contact the " +
+                        "CA to determine the supported algorithm when " +
+                        "hostport is specified");
             }
         }
 
@@ -493,9 +482,9 @@ public class CRMFPopClient {
             System.out.println("Keypair private key id: " + kid);
 
             if (hostPort != null) {
-                // check the CA for the required keyset and archival mechanism
+                // check the CA for the required key wrap algorithm
                 // if found, override whatever has been set by the command line
-                // options or environment for archivalMechanism and wrappingKeySet
+                // options for the key wrap algorithm
 
                 ClientConfig config = new ClientConfig();
                 String host = hostPort.substring(0, hostPort.indexOf(':'));
@@ -503,31 +492,17 @@ public class CRMFPopClient {
                 config.setServerURL("http", host, port);
 
                 PKIClient pkiclient = new PKIClient(config);
-
-                // get archival mechanism
-                CAInfoClient infoClient = new CAInfoClient(pkiclient, "ca");
-                try {
-                    CAInfo info = infoClient.getInfo();
-                    archivalMechanism = info.getArchivalMechanism();
-                    wrappingKeySet = info.getWrappingKeySet();
-                } catch (PKIException e) {
-                    if (e.getCode() == 404) {
-                        // assume this is an older server,
-                        archivalMechanism = KRAInfoResource.KEYWRAP_MECHANISM;
-                        wrappingKeySet = "0";
-                    } else {
-                        throw new Exception("Failed to retrieve archive wrapping information from the CA: " + e, e);
-                    }
-                } catch (Exception e) {
-                    throw new Exception("Failed to retrieve archive wrapping information from the CA: " + e, e);
-                }
+                kwAlg = getKeyWrapAlgotihm(pkiclient);
             }
 
+            if (verbose) System.out.println("Using key wrap algorithm: " + kwAlg);
+            keyWrapAlgorithm = KeyWrapAlgorithm.fromString(kwAlg);
+
             if (verbose) System.out.println("Creating certificate request");
             CertRequest certRequest = client.createCertRequest(
                     self_sign,
                     token, transportCert, algorithm, keyPair,
-                    subject, archivalMechanism, wrappingKeySet);
+                    subject, keyWrapAlgorithm);
 
             ProofOfPossession pop = null;
 
@@ -592,6 +567,36 @@ public class CRMFPopClient {
         }
     }
 
+    public static String getKeyWrapAlgotihm(PKIClient pkiclient)
+            throws Exception {
+        String kwAlg = null;
+        CAInfoClient infoClient = new CAInfoClient(pkiclient, "ca");
+        String archivalMechanism = KRAInfoResource.KEYWRAP_MECHANISM;
+
+        try {
+            CAInfo info = infoClient.getInfo();
+            archivalMechanism = info.getArchivalMechanism();
+            kwAlg = info.getKeyWrapAlgorithm();
+        } catch (PKIException e) {
+            if (e.getCode() == 404) {
+                // assume this is an older server,
+                archivalMechanism = KRAInfoResource.KEYWRAP_MECHANISM;
+                kwAlg = KeyWrapAlgorithm.DES3_CBC_PAD.toString();
+            } else {
+                throw new Exception("Failed to retrieve archive wrapping information from the CA: " + e, e);
+            }
+        } catch (Exception e) {
+            throw new Exception("Failed to retrieve archive wrapping information from the CA: " + e, e);
+        }
+
+        if (!archivalMechanism.equals(KRAInfoResource.KEYWRAP_MECHANISM)) {
+            // new server with encryption set.  Use something we know will
+            // work.  AES-128-CBC
+            kwAlg = KeyWrapAlgorithm.AES_CBC_PAD.toString();
+        }
+        return kwAlg;
+    }
+
     public void setVerbose(boolean verbose) {
         this.verbose = verbose;
     }
@@ -637,10 +642,9 @@ public class CRMFPopClient {
             String algorithm,
             KeyPair keyPair,
             Name subject,
-            String archivalMechanism,
-            String wrappingKeySet) throws Exception {
+            KeyWrapAlgorithm keyWrapAlgorithm) throws Exception {
         return createCertRequest(false, token, transportCert, algorithm, keyPair,
-            subject, archivalMechanism, wrappingKeySet);
+            subject, keyWrapAlgorithm);
     }
 
     public CertRequest createCertRequest(
@@ -650,24 +654,15 @@ public class CRMFPopClient {
             String algorithm,
             KeyPair keyPair,
             Name subject,
-            String archivalMechanism,
-            String wrappingKeySet) throws Exception {
-        EncryptionAlgorithm encryptAlg = null;
-
-        if (wrappingKeySet == null) {
-            wrappingKeySet = System.getenv("KEY_WRAP_PARAMETER_SET");
+            KeyWrapAlgorithm keyWrapAlgorithm) throws Exception {
+        byte[] iv = null;
+        if (keyWrapAlgorithm.getParameterClasses() != null) {
+            iv = CryptoUtil.getNonceData(keyWrapAlgorithm.getBlockSize());
         }
+        OBJECT_IDENTIFIER kwOID = CryptoUtil.getOID(keyWrapAlgorithm);
 
-        if (wrappingKeySet != null && wrappingKeySet.equalsIgnoreCase("0")) {
-            // talking to an old server?
-            encryptAlg = EncryptionAlgorithm.DES3_CBC;
-        } else {
-            encryptAlg = EncryptionAlgorithm.AES_128_CBC;
-        }
-
-        byte[] iv = CryptoUtil.getNonceData(encryptAlg.getIVLength());
-        AlgorithmIdentifier aid = new AlgorithmIdentifier(encryptAlg.toOID(), new OCTET_STRING(iv));
-        WrappingParams params = getWrappingParams(encryptAlg, iv, archivalMechanism);
+        AlgorithmIdentifier aid = new AlgorithmIdentifier(kwOID, new OCTET_STRING(iv));
+        WrappingParams params = getWrappingParams(keyWrapAlgorithm, iv);
 
         PKIArchiveOptions opts = CryptoUtil.createPKIArchiveOptions(
                 token,
@@ -698,29 +693,21 @@ public class CRMFPopClient {
         return new CertRequest(new INTEGER(1), certTemplate, seq);
     }
 
-    private WrappingParams getWrappingParams(EncryptionAlgorithm encryptAlg, byte[] wrapIV,
-            String archivalMechanism) throws Exception {
-        if (encryptAlg.getAlg().toString().equalsIgnoreCase("AES")) {
-            KeyWrapAlgorithm wrapAlg = null;
-            IVParameterSpec wrapIVS = null;
-            if (archivalMechanism.equals(KRAInfoResource.ENCRYPT_MECHANISM)) {
-                // We will use AES_CBC_PAD as the a key wrap mechanism.  This
-                // can be decrypted using the same mechanism on the server.
-                wrapAlg = KeyWrapAlgorithm.AES_CBC_PAD;
-                wrapIVS = new IVParameterSpec(wrapIV);
-            } else {
-                wrapAlg = KeyWrapAlgorithm.AES_KEY_WRAP_PAD;
-            }
+    private WrappingParams getWrappingParams(KeyWrapAlgorithm kwAlg, byte[] iv) throws Exception {
+        IVParameterSpec ivps = iv != null ? new IVParameterSpec(iv): null;
+
+        if (kwAlg == KeyWrapAlgorithm.AES_KEY_WRAP_PAD ||
+            kwAlg == KeyWrapAlgorithm.AES_CBC_PAD) {
             return new WrappingParams(
                 SymmetricKey.AES, KeyGenAlgorithm.AES, 128,
-                KeyWrapAlgorithm.RSA, encryptAlg,
-                wrapAlg, wrapIVS, wrapIVS);
-        } else if (encryptAlg.getAlg().toString().equalsIgnoreCase("DESede")) {
+                KeyWrapAlgorithm.RSA, EncryptionAlgorithm.AES_128_CBC_PAD,
+                kwAlg, ivps, ivps);
+        } else if (kwAlg == KeyWrapAlgorithm.DES3_CBC_PAD) {
             return new WrappingParams(
                     SymmetricKey.DES3, KeyGenAlgorithm.DES3, 168,
                     KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD,
                     KeyWrapAlgorithm.DES3_CBC_PAD,
-                    new IVParameterSpec(wrapIV), new IVParameterSpec(wrapIV));
+                    ivps, ivps);
         } else {
             throw new Exception("Invalid encryption algorithm");
         }
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCertRequestCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCertRequestCLI.java
index a14bb24..9a0cfcc 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientCertRequestCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCertRequestCLI.java
@@ -29,18 +29,15 @@ import java.util.Vector;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.io.FileUtils;
-import org.dogtagpki.common.CAInfo;
-import org.dogtagpki.common.CAInfoClient;
-import org.dogtagpki.common.KRAInfoResource;
 import org.mozilla.jss.CryptoManager;
 import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
 import org.mozilla.jss.crypto.Signature;
 import org.mozilla.jss.crypto.X509Certificate;
 import org.mozilla.jss.pkix.crmf.CertRequest;
 import org.mozilla.jss.pkix.crmf.ProofOfPossession;
 import org.mozilla.jss.pkix.primitive.Name;
 
-import com.netscape.certsrv.base.PKIException;
 import com.netscape.certsrv.cert.CertClient;
 import com.netscape.certsrv.cert.CertEnrollmentRequest;
 import com.netscape.certsrv.cert.CertRequestInfos;
@@ -249,29 +246,13 @@ public class ClientCertRequestCLI extends CLI {
             CryptoManager manager = CryptoManager.getInstance();
             X509Certificate transportCert = manager.importCACertPackage(transportCertData);
 
-            // get archival mechanism
-            CAInfoClient infoClient = new CAInfoClient(client, "ca");
-            String archivalMechanism = KRAInfoResource.KEYWRAP_MECHANISM;
-            String wrappingKeySet = "1";
-            try {
-                CAInfo info = infoClient.getInfo();
-                archivalMechanism = info.getArchivalMechanism();
-                wrappingKeySet = info.getWrappingKeySet();
-            } catch (PKIException e) {
-                if (e.getCode() == 404) {
-                    // assume this is an older server,
-                    archivalMechanism = KRAInfoResource.KEYWRAP_MECHANISM;
-                    wrappingKeySet = "0";
-                } else {
-                    throw new Exception("Failed to retrieve archive wrapping information from the CA: " + e, e);
-                }
-            } catch (Exception e) {
-                throw new Exception("Failed to retrieve archive wrapping information from the CA: " + e, e);
-            }
+            // get archival and key wrap mechanisms from CA
+            String kwAlg = CRMFPopClient.getKeyWrapAlgotihm(client);
+            KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithm.fromString(kwAlg);
 
             csr = generateCrmfRequest(transportCert, subjectDN, attributeEncoding,
                     algorithm, length, curve, sslECDH, temporary, sensitive, extractable, withPop,
-                    archivalMechanism, wrappingKeySet);
+                    keyWrapAlgorithm);
 
         } else {
             throw new Exception("Unknown request type: " + requestType);
@@ -411,8 +392,7 @@ public class ClientCertRequestCLI extends CLI {
             int sensitive,
             int extractable,
             boolean withPop,
-            String archivalMechanism,
-            String wrappingKeySet
+            KeyWrapAlgorithm keyWrapAlgorithm
             ) throws Exception {
 
         CryptoManager manager = CryptoManager.getInstance();
@@ -434,7 +414,7 @@ public class ClientCertRequestCLI extends CLI {
         }
 
         CertRequest certRequest = client.createCertRequest(
-                token, transportCert, algorithm, keyPair, subject, archivalMechanism, wrappingKeySet);
+                token, transportCert, algorithm, keyPair, subject, keyWrapAlgorithm);
 
         ProofOfPossession pop = null;
         if (withPop) {
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/CAInfoService.java b/base/server/cms/src/org/dogtagpki/server/rest/CAInfoService.java
index 398f499..52c9ca0 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/CAInfoService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/CAInfoService.java
@@ -28,6 +28,8 @@ import org.dogtagpki.common.CAInfo;
 import org.dogtagpki.common.CAInfoResource;
 import org.dogtagpki.common.KRAInfo;
 import org.dogtagpki.common.KRAInfoClient;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -73,7 +75,8 @@ public class CAInfoService extends PKIService implements CAInfoResource {
     // KRA-related fields (the initial values are only used if we
     // did not yet receive authoritative info from KRA)
     private static String archivalMechanism = KRAInfoService.KEYWRAP_MECHANISM;
-    private static String wrappingKeySet = "0";
+    private static String encryptAlgorithm;
+    private static String keyWrapAlgorithm;
 
     @Override
     public Response getInfo() throws Exception {
@@ -116,7 +119,8 @@ public class CAInfoService extends PKIService implements CAInfoResource {
             }
 
             info.setArchivalMechanism(archivalMechanism);
-            info.setWrappingKeySet(wrappingKeySet);
+            info.setEncryptAlgorithm(encryptAlgorithm);
+            info.setKeyWrapAlgorithm(keyWrapAlgorithm);
         }
     }
 
@@ -125,10 +129,8 @@ public class CAInfoService extends PKIService implements CAInfoResource {
             KRAInfo kraInfo = getKRAInfoClient(connInfo).getInfo();
 
             archivalMechanism = kraInfo.getArchivalMechanism();
-
-            // request succeeded; the KRA is 10.4 or higher,
-            // therefore supports key set v1
-            wrappingKeySet = "1";
+            encryptAlgorithm = kraInfo.getEncryptAlgorithm();
+            keyWrapAlgorithm = kraInfo.getWrapAlgorithm();
 
             // mark info as authoritative
             kraInfoAuthoritative = true;
@@ -137,8 +139,8 @@ public class CAInfoService extends PKIService implements CAInfoResource {
                 // The KRAInfoResource was added in 10.4,
                 // so we are talking to a pre-10.4 KRA
 
-                // pre-10.4 only supports key set v0
-                wrappingKeySet = "0";
+                encryptAlgorithm = EncryptionAlgorithm.DES3_CBC_PAD.toString();
+                keyWrapAlgorithm = KeyWrapAlgorithm.DES3_CBC_PAD.toString();
 
                 // pre-10.4 KRA does not advertise the archival
                 // mechanism; look for the old knob in CA's config
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/KRAInfoService.java b/base/server/cms/src/org/dogtagpki/server/rest/KRAInfoService.java
index c4b3252..a9c3cdf 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/KRAInfoService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/KRAInfoService.java
@@ -29,14 +29,25 @@ import org.slf4j.LoggerFactory;
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
+import com.netscape.certsrv.security.IStorageKeyUnit;
 import com.netscape.cms.servlet.base.PKIService;
 
+import netscape.security.util.WrappingParams;
+
 /**
  * @author Ade Lee
  */
 public class KRAInfoService extends PKIService implements KRAInfoResource {
 
     private static Logger logger = LoggerFactory.getLogger(InfoService.class);
+    private IKeyRecoveryAuthority kra;
+    private IStorageKeyUnit storageUnit;
+
+    public KRAInfoService() {
+        kra = (IKeyRecoveryAuthority) CMS.getSubsystem("kra");
+        storageUnit = kra.getStorageKeyUnit();
+    }
 
     @Override
     public Response getInfo() throws Exception {
@@ -47,7 +58,8 @@ public class KRAInfoService extends PKIService implements KRAInfoResource {
         KRAInfo info = new KRAInfo();
         info.setArchivalMechanism(getArchivalMechanism());
         info.setRecoveryMechanism(getRecoveryMechanism());
-
+        info.setEncryptAlgorithm(getEncryptAlgorithm());
+        info.setArchivalMechanism(getWrapAlgorithm());
 
         return createOKResponse(info);
     }
@@ -63,5 +75,31 @@ public class KRAInfoService extends PKIService implements KRAInfoResource {
         boolean encrypt_recovery = cs.getBoolean("kra.allowEncDecrypt.recovery", false);
         return encrypt_recovery ? KRAInfoResource.ENCRYPT_MECHANISM : KRAInfoResource.KEYWRAP_MECHANISM;
     }
+
+    String getWrapAlgorithm() throws EBaseException {
+        IConfigStore cs = CMS.getConfigStore();
+        boolean encrypt_archival = cs.getBoolean("kra.allowEncDecrypt.archival", false);
+        WrappingParams params = null;
+        try {
+            params = storageUnit.getWrappingParams(encrypt_archival);
+        } catch (Exception e) {
+            // return something that should always work
+            return "AES/CBC/Padding";
+        }
+        return params.getPayloadWrapAlgorithm().toString();
+    }
+
+    String getEncryptAlgorithm() throws EBaseException {
+        IConfigStore cs = CMS.getConfigStore();
+        boolean encrypt_archival = cs.getBoolean("kra.allowEncDecrypt.archival", false);
+        WrappingParams params = null;
+        try {
+            params = storageUnit.getWrappingParams(encrypt_archival);
+        } catch (Exception e) {
+            // return something that should always work
+            return "AES/CBC/Padding";
+        }
+        return params.getPayloadEncryptionAlgorithm().toString();
+    }
 }
 
diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
index 95b8f81..84e4a65 100644
--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -2713,6 +2713,28 @@ public class CryptoUtil {
         throw new NoSuchAlgorithmException();
     }
 
+    /*
+     * Useful method to map KeyWrap algorithms to an OID.
+     * This is not yet defined within JSS, although it will be valuable to do
+     * so.  The hard thing though is that the KeyWrapAlgorithms in JSS do not take
+     * KEK key size into account for algorithms like AES.  We assume 128 bits in
+     * this case.
+     *
+     * This is used in the generation of CRMF requests, and will be correlated to
+     * the subsequent reverse mapping method below.
+     */
+    public static OBJECT_IDENTIFIER getOID(KeyWrapAlgorithm kwAlg) throws NoSuchAlgorithmException {
+        if (kwAlg == KeyWrapAlgorithm.AES_KEY_WRAP_PAD)
+            return new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.1.8");
+        if (kwAlg == KeyWrapAlgorithm.AES_CBC_PAD)
+            return new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.1.2");
+        if ((kwAlg == KeyWrapAlgorithm.DES3_CBC_PAD) ||
+            (kwAlg == KeyWrapAlgorithm.DES_CBC_PAD))
+            return new OBJECT_IDENTIFIER("1.2.840.113549.3.7");
+
+        throw new NoSuchAlgorithmException();
+    }
+
 }
 
 // START ENABLE_ECC
-- 
1.8.3.1


From d5c331a42955365b76a1549aec047e613d3185dc Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Tue, 6 Jun 2017 16:16:40 -0400
Subject: [PATCH 07/14] Server side changes to correctly parse the new
 PKIArchiveOptions

The server is modified to read the new OIDs in the PKIArchiveOptions
and handle them correctly.

Change-Id: I328df4d6588b3c2c26a387ab2e9ed742d36824d4
---
 base/common/src/org/dogtagpki/common/CAInfo.java   |  2 +
 .../src/com/netscape/cmstools/CRMFPopClient.java   | 20 ++++++--
 .../kra/src/com/netscape/kra/TransportKeyUnit.java | 21 ++++-----
 .../org/dogtagpki/server/rest/KRAInfoService.java  |  2 +-
 .../com/netscape/cmsutil/crypto/CryptoUtil.java    | 34 ++++++++++---
 .../src/netscape/security/util/WrappingParams.java | 55 ++++++++++++++++++++++
 6 files changed, 109 insertions(+), 25 deletions(-)

diff --git a/base/common/src/org/dogtagpki/common/CAInfo.java b/base/common/src/org/dogtagpki/common/CAInfo.java
index 0f68c7a..ada8098 100644
--- a/base/common/src/org/dogtagpki/common/CAInfo.java
+++ b/base/common/src/org/dogtagpki/common/CAInfo.java
@@ -66,6 +66,7 @@ public class CAInfo extends ResourceMessage {
         this.archivalMechanism = archivalMechanism;
     }
 
+    @XmlElement(name="EncryptAlgorithm")
     public String getEncryptAlgorithm() {
         return encryptAlgorithm;
     }
@@ -74,6 +75,7 @@ public class CAInfo extends ResourceMessage {
         this.encryptAlgorithm = encryptAlgorithm;
     }
 
+    @XmlElement(name="WrapAlgorithm")
     public String getKeyWrapAlgorithm() {
         return keyWrapAlgorithm;
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
index b06faa6..25de2dd 100644
--- a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
+++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
@@ -191,7 +191,7 @@ public class CRMFPopClient {
         options.addOption(option);
 
         option = new Option("w", true, "Algorithm to be used for key wrapping");
-        option.setArgName("keySet");
+        option.setArgName("keywrap algorithm");
         options.addOption(option);
 
         options.addOption("y", false, "for Self-signed cmc.");
@@ -655,13 +655,23 @@ public class CRMFPopClient {
             KeyPair keyPair,
             Name subject,
             KeyWrapAlgorithm keyWrapAlgorithm) throws Exception {
-        byte[] iv = null;
-        if (keyWrapAlgorithm.getParameterClasses() != null) {
-            iv = CryptoUtil.getNonceData(keyWrapAlgorithm.getBlockSize());
-        }
+        byte[] iv = CryptoUtil.getNonceData(keyWrapAlgorithm.getBlockSize());
         OBJECT_IDENTIFIER kwOID = CryptoUtil.getOID(keyWrapAlgorithm);
 
+        /* TODO(alee)
+         *
+         * HACK HACK!
+         * algorithms like AES KeyWrap do not require an IV, but we need to include one
+         * in the AlgorithmIdentifier above, or the creation and parsing of the
+         * PKIArchiveOptions options will fail.  So we include an IV in aid, but null it
+         * later to correctly encrypt the data
+         */
         AlgorithmIdentifier aid = new AlgorithmIdentifier(kwOID, new OCTET_STRING(iv));
+
+        Class[] iv_classes = keyWrapAlgorithm.getParameterClasses();
+        if (iv_classes == null || iv_classes.length == 0)
+            iv = null;
+
         WrappingParams params = getWrappingParams(keyWrapAlgorithm, iv);
 
         PKIArchiveOptions opts = CryptoUtil.createPKIArchiveOptions(
diff --git a/base/kra/src/com/netscape/kra/TransportKeyUnit.java b/base/kra/src/com/netscape/kra/TransportKeyUnit.java
index d0ad8b3..91af7cf 100644
--- a/base/kra/src/com/netscape/kra/TransportKeyUnit.java
+++ b/base/kra/src/com/netscape/kra/TransportKeyUnit.java
@@ -267,7 +267,7 @@ public class TransportKeyUnit extends EncryptionUnit implements
      * Decrypts the user private key.  This is called on the transport unit.
      */
     public byte[] decryptExternalPrivate(byte encSymmKey[],
-            String symmAlgOID, byte symmAlgParams[], byte encValue[],
+            String wrapOID, byte wrapIV[], byte encValue[],
             org.mozilla.jss.crypto.X509Certificate transCert)
             throws Exception {
 
@@ -279,12 +279,10 @@ public class TransportKeyUnit extends EncryptionUnit implements
         CryptoToken token = getToken(transCert);
         PrivateKey wrappingKey = getPrivateKey(transCert);
         String priKeyAlgo = wrappingKey.getAlgorithm();
-        WrappingParams params = new WrappingParams(
-                symmAlgOID,
-                null,
+        WrappingParams params = WrappingParams.getWrappingParamsFromArchiveOptions(
+                wrapOID,
                 priKeyAlgo,
-                new IVParameterSpec(symmAlgParams),
-                null);
+                new IVParameterSpec(wrapIV));
 
         SymmetricKey sk = CryptoUtil.unwrap(
                 token,
@@ -303,6 +301,7 @@ public class TransportKeyUnit extends EncryptionUnit implements
                 params.getPayloadEncryptionAlgorithm());
     }
 
+
     /**
      * External unwrapping. Unwraps the symmetric key using
      * the transport private key.
@@ -342,19 +341,17 @@ public class TransportKeyUnit extends EncryptionUnit implements
      * the transport private key.
      */
     public PrivateKey unwrap(byte encSymmKey[],
-            String symmAlgOID, byte symmAlgParams[],
+            String wrapOID, byte wrapIV[],
             byte encValue[], PublicKey pubKey,
             org.mozilla.jss.crypto.X509Certificate transCert)
             throws Exception {
         CryptoToken token = getToken(transCert);
         PrivateKey wrappingKey = getPrivateKey(transCert);
         String priKeyAlgo = wrappingKey.getAlgorithm();
-        WrappingParams params = new WrappingParams(
-                symmAlgOID,
-                null,
+        WrappingParams params = WrappingParams.getWrappingParamsFromArchiveOptions(
+                wrapOID,
                 priKeyAlgo,
-                new IVParameterSpec(symmAlgParams),
-                new IVParameterSpec(symmAlgParams));
+                new IVParameterSpec(wrapIV));
 
         // (1) unwrap the session key
         SymmetricKey sk = CryptoUtil.unwrap(
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/KRAInfoService.java b/base/server/cms/src/org/dogtagpki/server/rest/KRAInfoService.java
index a9c3cdf..c855b22 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/KRAInfoService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/KRAInfoService.java
@@ -59,7 +59,7 @@ public class KRAInfoService extends PKIService implements KRAInfoResource {
         info.setArchivalMechanism(getArchivalMechanism());
         info.setRecoveryMechanism(getRecoveryMechanism());
         info.setEncryptAlgorithm(getEncryptAlgorithm());
-        info.setArchivalMechanism(getWrapAlgorithm());
+        info.setWrapAlgorithm(getWrapAlgorithm());
 
         return createOKResponse(info);
     }
diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
index 84e4a65..eca8ddd 100644
--- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
+++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -2713,6 +2713,10 @@ public class CryptoUtil {
         throw new NoSuchAlgorithmException();
     }
 
+    public static final OBJECT_IDENTIFIER KW_AES_KEY_WRAP_PAD = new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.1.8");
+    public static final OBJECT_IDENTIFIER KW_AES_CBC_PAD = new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.1.2");
+    public static final OBJECT_IDENTIFIER KW_DES_CBC_PAD = new OBJECT_IDENTIFIER("1.2.840.113549.3.7");
+
     /*
      * Useful method to map KeyWrap algorithms to an OID.
      * This is not yet defined within JSS, although it will be valuable to do
@@ -2724,13 +2728,29 @@ public class CryptoUtil {
      * the subsequent reverse mapping method below.
      */
     public static OBJECT_IDENTIFIER getOID(KeyWrapAlgorithm kwAlg) throws NoSuchAlgorithmException {
-        if (kwAlg == KeyWrapAlgorithm.AES_KEY_WRAP_PAD)
-            return new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.1.8");
-        if (kwAlg == KeyWrapAlgorithm.AES_CBC_PAD)
-            return new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.1.2");
-        if ((kwAlg == KeyWrapAlgorithm.DES3_CBC_PAD) ||
-            (kwAlg == KeyWrapAlgorithm.DES_CBC_PAD))
-            return new OBJECT_IDENTIFIER("1.2.840.113549.3.7");
+        String name = kwAlg.toString();
+        if (name.equals(KeyWrapAlgorithm.AES_KEY_WRAP_PAD.toString()))
+            return KW_AES_KEY_WRAP_PAD;
+        if (name.equals(KeyWrapAlgorithm.AES_CBC_PAD.toString()))
+            return KW_AES_CBC_PAD;
+        if (name.equals(KeyWrapAlgorithm.DES3_CBC_PAD.toString()))
+            return KW_DES_CBC_PAD;
+        if (name.equals(KeyWrapAlgorithm.DES_CBC_PAD.toString()))
+            return KW_DES_CBC_PAD;
+
+        throw new NoSuchAlgorithmException();
+    }
+
+    public static KeyWrapAlgorithm getKeyWrapAlgorithmFromOID(String wrapOID) throws NoSuchAlgorithmException {
+        OBJECT_IDENTIFIER oid = new OBJECT_IDENTIFIER(wrapOID);
+        if (oid.equals(KW_AES_KEY_WRAP_PAD))
+            return KeyWrapAlgorithm.AES_KEY_WRAP_PAD;
+
+        if (oid.equals(KW_AES_CBC_PAD))
+            return KeyWrapAlgorithm.AES_CBC_PAD;
+
+        if (oid.equals(KW_DES_CBC_PAD))
+            return KeyWrapAlgorithm.DES3_CBC_PAD;
 
         throw new NoSuchAlgorithmException();
     }
diff --git a/base/util/src/netscape/security/util/WrappingParams.java b/base/util/src/netscape/security/util/WrappingParams.java
index 8fe5df6..cda8870 100644
--- a/base/util/src/netscape/security/util/WrappingParams.java
+++ b/base/util/src/netscape/security/util/WrappingParams.java
@@ -10,6 +10,8 @@ import org.mozilla.jss.crypto.KeyWrapAlgorithm;
 import org.mozilla.jss.crypto.SymmetricKey;
 import org.mozilla.jss.crypto.SymmetricKey.Type;
 
+import com.netscape.cmsutil.crypto.CryptoUtil;
+
 public class WrappingParams {
     // session key attributes
     SymmetricKey.Type skType;
@@ -123,6 +125,59 @@ public class WrappingParams {
         }
     }
 
+    private WrappingParams(String wrapOID, String priKeyAlgo, IVParameterSpec wrapIV)
+            throws NumberFormatException, NoSuchAlgorithmException {
+        KeyWrapAlgorithm kwAlg = CryptoUtil.getKeyWrapAlgorithmFromOID(wrapOID);
+
+        if (kwAlg == KeyWrapAlgorithm.AES_KEY_WRAP_PAD) {
+            skType = SymmetricKey.AES;
+            skKeyGenAlgorithm = KeyGenAlgorithm.AES;
+            payloadWrapAlgorithm = KeyWrapAlgorithm.AES_KEY_WRAP_PAD;
+            payloadEncryptionAlgorithm = EncryptionAlgorithm.AES_128_CBC_PAD;
+            skLength = 128;
+        }
+
+        if (kwAlg == KeyWrapAlgorithm.AES_CBC_PAD) {
+            skType = SymmetricKey.AES;
+            skKeyGenAlgorithm = KeyGenAlgorithm.AES;
+            payloadWrapAlgorithm = KeyWrapAlgorithm.AES_CBC_PAD;
+            payloadEncryptionAlgorithm = EncryptionAlgorithm.AES_128_CBC_PAD;
+            skLength = 128;
+        }
+
+        if (kwAlg == KeyWrapAlgorithm.DES3_CBC_PAD || kwAlg == KeyWrapAlgorithm.DES_CBC_PAD) {
+            skType = SymmetricKey.DES;
+            skKeyGenAlgorithm = KeyGenAlgorithm.DES;
+            skWrapAlgorithm = KeyWrapAlgorithm.DES3_CBC_PAD;
+            payloadWrapAlgorithm = KeyWrapAlgorithm.DES3_CBC_PAD;
+            payloadEncryptionAlgorithm = EncryptionAlgorithm.DES3_CBC_PAD;
+            skLength = 0;
+        }
+
+        if (priKeyAlgo.equals("EC")) {
+            skWrapAlgorithm = KeyWrapAlgorithm.AES_ECB;
+        } else {
+            skWrapAlgorithm = KeyWrapAlgorithm.RSA;
+        }
+
+        // set the IVs
+        payloadEncryptionIV = wrapIV;
+
+        if (payloadWrapAlgorithm == KeyWrapAlgorithm.AES_KEY_WRAP_PAD) {
+            // TODO(alee) Hack -- if we pass in null for the iv in the
+            // PKIArchiveOptions, we fail to decode correctly when parsing a
+            // CRMFPopClient request.
+            payloadWrappingIV = null;
+        } else {
+            payloadWrappingIV = wrapIV;
+        }
+    }
+
+    public static WrappingParams getWrappingParamsFromArchiveOptions(String wrapOID, String priKeyAlgo, IVParameterSpec wrapIV)
+            throws NumberFormatException, NoSuchAlgorithmException {
+        return new WrappingParams(wrapOID, priKeyAlgo, wrapIV);
+    }
+
     public SymmetricKey.Type getSkType() {
         return skType;
     }
-- 
1.8.3.1


From 5bf30f2f6a52b7164ba31ab12ed2317b2c572610 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Thu, 8 Jun 2017 16:08:30 -0400
Subject: [PATCH 10/14] Stop using hardcoded IV in CMC

Bugzilla #BZ 1458055

Change-Id: I229d7f18c46f0b55ec83f051614de1b59e125b82
---
 base/java-tools/src/com/netscape/cmstools/CMCRequest.java   | 13 ++++++++-----
 .../src/com/netscape/cms/profile/common/EnrollProfile.java  | 13 ++++++-------
 .../com/netscape/cms/servlet/common/CMCOutputTemplate.java  |  8 +++-----
 3 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
index 8d49b20..4adf22b 100644
--- a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
+++ b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
@@ -40,6 +40,7 @@ import java.util.StringTokenizer;
 import org.mozilla.jss.CryptoManager;
 import org.mozilla.jss.asn1.ANY;
 import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.ASN1Value;
 import org.mozilla.jss.asn1.BIT_STRING;
 import org.mozilla.jss.asn1.ENUMERATED;
 import org.mozilla.jss.asn1.GeneralizedTime;
@@ -1708,6 +1709,12 @@ public class CMCRequest {
         try {
             TaggedRequest request = encryptedPop.getRequest();
             AlgorithmIdentifier thePOPAlgID = encryptedPop.getThePOPAlgID();
+
+            ASN1Value v = thePOPAlgID.getParameters();
+            v = ((ANY) v).decodeWith(new OCTET_STRING.Template());
+            byte iv[] = ((OCTET_STRING) v).toByteArray();
+            IVParameterSpec ivps = new IVParameterSpec(iv);
+
             AlgorithmIdentifier witnessAlgID = encryptedPop.getWitnessAlgID();
             OCTET_STRING witness = encryptedPop.getWitness();
             ContentInfo cms = encryptedPop.getContentInfo();
@@ -1734,13 +1741,9 @@ public class CMCRequest {
             }
             System.out.println(method + "symKey unwrapped.");
 
-            // TODO(alee) The code below should be replaced by code that generates a random IV
-            byte[] iv = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
-            IVParameterSpec default_iv = new IVParameterSpec(iv);
-
             byte challenge[] = CryptoUtil.decryptUsingSymmetricKey(
                     token,
-                    default_iv,
+                    ivps,
                     encCI.getEncryptedContent().toByteArray(),
                     symKey,
                     EncryptionAlgorithm.AES_128_CBC);
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..2591ace 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
@@ -403,8 +403,7 @@ public abstract class EnrollProfile extends BasicProfile
                 String tokenName = CMS.getConfigStore().getString("cmc.token", CryptoUtil.INTERNAL_TOKEN_NAME);
                 token = CryptoUtil.getCryptoToken(tokenName);
 
-                // TODO(alee) Replace the IV definition with a call that generates a random IV of  the correct length
-                byte[] iv = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+                byte[] iv = CryptoUtil.getNonceData(EncryptionAlgorithm.AES_128_CBC.getIVLength());
                 IVParameterSpec ivps = new IVParameterSpec(iv);
 
                 PublicKey userPubKey = X509Key.parsePublicKey(new DerValue(req_key_data));
@@ -466,6 +465,8 @@ public abstract class EnrollProfile extends BasicProfile
 
                 req.setExtData("pop_userPubEncryptedSession", pop_userPubEncryptedSession);
 
+                req.setExtData("pop_encryptedDataIV", iv);
+
                 // now compute and set witness
                 CMS.debug(method + "now compute and set witness");
                 String hashName = CryptoUtil.getDefaultHashAlgName();
@@ -1123,14 +1124,12 @@ public abstract class EnrollProfile extends BasicProfile
                 return null;
             }
 
-            // TODO(alee) The code below should be replaced by code that gets the IV from the Pop request
-            // This IV is supposed to be random
-            byte[] iv = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
-            IVParameterSpec default_iv = new IVParameterSpec(iv);
+            byte[] iv = req.getExtDataInByteArray("pop_encryptedDataIV");
+            IVParameterSpec ivps = new IVParameterSpec(iv);
 
             byte[] challenge_b = CryptoUtil.decryptUsingSymmetricKey(
                     token,
-                    default_iv,
+                    ivps,
                     pop_encryptedData,
                     symKey,
                     EncryptionAlgorithm.AES_128_CBC);
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..8d6c37f 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
@@ -491,6 +491,7 @@ public class CMCOutputTemplate {
         //don't need this for encryptedPOP, but need to check for existence anyway
         byte[] pop_sysPubEncryptedSession = req.getExtDataInByteArray("pop_sysPubEncryptedSession");
         byte[] pop_userPubEncryptedSession = req.getExtDataInByteArray("pop_userPubEncryptedSession");
+        byte[] iv = req.getExtDataInByteArray("pop_encryptedDataIV");
         if ((pop_encryptedData != null) &&
                 (pop_sysPubEncryptedSession != null) &&
                 (pop_userPubEncryptedSession != null)) {
@@ -517,11 +518,8 @@ public class CMCOutputTemplate {
                     throw new EBaseException(method + msg);
                 }
 
-                // TODO(alee) The code below should be replaced by code that generates a random IV
-                byte[] default_iv = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
-
                 OBJECT_IDENTIFIER oid = EncryptionAlgorithm.AES_128_CBC.toOID();
-                AlgorithmIdentifier aid = new AlgorithmIdentifier(oid, new OCTET_STRING(default_iv));
+                AlgorithmIdentifier aid = new AlgorithmIdentifier(oid, new OCTET_STRING(iv));
 
                 encPop = new EncryptedPOP(
                         tReq,
@@ -532,7 +530,7 @@ public class CMCOutputTemplate {
 
             } catch (Exception e) {
                 CMS.debug(method + " excepton:" + e);
-                throw new EBaseException(method + " excepton:" + e);
+                throw new EBaseException(method + " exception:" + e);
             }
 
         } else {
-- 
1.8.3.1


From 698192f4f62c55142a557f6489ed2323e17401b0 Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu@redhat.com>
Date: Tue, 30 May 2017 14:12:06 -0700
Subject: [PATCH 11/14] 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      | 251 ++++++++-----
 .../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, 769 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 4adf22b..00e03a7 100644
--- a/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
+++ b/base/java-tools/src/com/netscape/cmstools/CMCRequest.java
@@ -72,15 +72,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;
@@ -374,14 +373,30 @@ 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 && data == null) {
+            System.out.println("getCMCBlob: generating signed data");
+            fullEnrollmentReq = new ContentInfo(signedData);
+        } else if (data != null && signedData == null) {
+            System.out.println("getCMCBlob: generating unsigned data");
+            fullEnrollmentReq = new ContentInfo(data);
+        } else if (signedData == null && data == null) {
+             System.out.println("getCMCBlob: both params are null");
+             System.exit(1);
+        } else {
+             System.out.println("getCMCBlob: both params are not null; only one of them can be used, the other must be null");
+             System.exit(1);
+        }
+
         try {
             ByteArrayOutputStream bs = new ByteArrayOutputStream();
             PrintStream ps = new PrintStream(bs);
@@ -768,29 +783,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");
@@ -844,13 +862,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");
@@ -861,9 +885,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("");
@@ -972,27 +993,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;
     }
 
     /**
@@ -1119,42 +1140,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);
@@ -1241,6 +1304,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);
@@ -1346,9 +1410,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();
             }
@@ -1825,7 +1889,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";
@@ -1941,8 +2004,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")) {
@@ -1985,7 +2046,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();
         }
@@ -2031,11 +2093,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());
                 }
             }
 
@@ -2065,6 +2128,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.");
@@ -2091,7 +2155,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();
                 }
@@ -2109,14 +2173,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);
+                        }
                     }
                 }
 
@@ -2126,11 +2193,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(
@@ -2222,20 +2290,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,
@@ -2248,6 +2316,7 @@ public class CMCRequest {
                         popLinkWitnessV2keyGenAlg, popLinkWitnessV2macAlg,
                         controlSeq, otherMsgSeq, bpid,
                         token, privk);
+                }
 
                 if (pkidata == null) {
                     System.out.println("pkidata null after createPKIData(). Exiting with error");
@@ -2255,22 +2324,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 2591ace..74da8e7 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
@@ -588,16 +588,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)
@@ -708,6 +717,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) {
@@ -735,7 +746,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();
@@ -766,6 +783,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";
@@ -801,7 +822,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
@@ -921,6 +942,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(),
@@ -959,6 +981,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")) {
@@ -1271,7 +1295,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;
@@ -1498,40 +1522,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
      *
@@ -1577,7 +1567,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";
@@ -1681,7 +1671,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 8d6c37f..067dce7 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,
@@ -880,8 +883,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();
                 }
@@ -920,22 +923,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);
@@ -943,67 +983,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);
@@ -1014,15 +1062,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);
@@ -1033,15 +1079,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);
@@ -1049,6 +1097,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;
                     }
                 }
@@ -1060,11 +1118,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);
@@ -1088,11 +1146,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();
@@ -1105,8 +1198,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();
@@ -1122,20 +1215,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;
                         }
                     }
@@ -1148,7 +1251,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,
@@ -1157,6 +1260,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);
@@ -1167,6 +1280,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;
                 }
             }
@@ -1175,54 +1298,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);
             }
@@ -1230,8 +1380,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) {
@@ -1242,17 +1391,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();
@@ -1268,11 +1415,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;
-- 
1.8.3.1


From 4328b770f8cbbb4c85919bc50201dff2e230dcc3 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Thu, 8 Jun 2017 21:14:00 -0400
Subject: [PATCH 12/14] Add possible keywrap algorithms to usage

Added possible key wrap algorithms to the CRMFPopClient
usage statement to make it clear what options are available.

Part of BZ #1458047

Change-Id: Ie49ec9cd9bbb5c112668469f701363b967695ef3
---
 base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
index 25de2dd..0aaec28 100644
--- a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
+++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
@@ -228,6 +228,8 @@ public class CRMFPopClient {
         System.out.println("                               - POP_SUCCESS: with valid POP");
         System.out.println("                               - POP_FAIL: with invalid POP (for testing)");
         System.out.println("  -w <keywrap algorithm>       Algorithm to use for key wrapping");
+        System.out.println("                               - default: \"AES KeyWrap/Padding\"");
+        System.out.println("                               - \"AES/CBC/PKCS5Padding\"");
         System.out.println("  -b <transport cert>          PEM transport certificate (default: transport.txt)");
         System.out.println("  -v, --verbose                Run in verbose mode.");
         System.out.println("      --help                   Show help message.");
-- 
1.8.3.1


From 9edd684fef78845acee95a766f34a9c57a1ab604 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Thu, 8 Jun 2017 22:08:01 -0400
Subject: [PATCH 13/14] Add one more possible keywrap algorithm to usage

Added one more key wrap algorithms to the CRMFPopClient
usage statement.

Part of BZ #1458047

Change-Id: Ic52410a6a23f850944a6b96385b26a9bba12b51a
---
 base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
index 0aaec28..66453c3 100644
--- a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
+++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java
@@ -230,6 +230,7 @@ public class CRMFPopClient {
         System.out.println("  -w <keywrap algorithm>       Algorithm to use for key wrapping");
         System.out.println("                               - default: \"AES KeyWrap/Padding\"");
         System.out.println("                               - \"AES/CBC/PKCS5Padding\"");
+        System.out.println("                               - \"DES3/CBC/Pad\"");
         System.out.println("  -b <transport cert>          PEM transport certificate (default: transport.txt)");
         System.out.println("  -v, --verbose                Run in verbose mode.");
         System.out.println("      --help                   Show help message.");
-- 
1.8.3.1


From 53564487e46040a9115fba51c8403ecacb50187e Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal@redhat.com>
Date: Thu, 8 Jun 2017 14:25:23 +1000
Subject: [PATCH 14/14] KRA PKCS #12 export: add config to use 3DES PBE
 encryption

Restore the 3DES PKCS #12 key recovery code path, alongside the new
AES variant, which is broken on Thales nethsm.  Add the
'kra.legacyPKCS12' config for selecting which version to use, with
the default value of 'true' (i.e., use 3DES).

Part of: https://pagure.io/dogtagpki/issue/2728

Change-Id: Ic02fe8ba3a4c2c049913ff48d3f6dfdc830b4360
---
 base/kra/src/com/netscape/kra/RecoveryService.java | 43 ++++++++++++++++------
 1 file changed, 32 insertions(+), 11 deletions(-)

diff --git a/base/kra/src/com/netscape/kra/RecoveryService.java b/base/kra/src/com/netscape/kra/RecoveryService.java
index eee800a..023eb80 100644
--- a/base/kra/src/com/netscape/kra/RecoveryService.java
+++ b/base/kra/src/com/netscape/kra/RecoveryService.java
@@ -487,19 +487,40 @@ public class RecoveryService implements IService {
             PasswordConverter passConverter = new
                     PasswordConverter();
 
-            byte[] epkiBytes = ct.getCryptoStore().getEncryptedPrivateKeyInfo(
-                /* NSS has a bug that causes any AES CBC encryption
-                 * to use AES-256, but AlgorithmID contains chosen
-                 * alg.  To avoid mismatch, use AES_256_CBC. */
-                passConverter, pass, EncryptionAlgorithm.AES_256_CBC, 0, priKey);
-            CMS.debug("RecoverService: createPFX() getEncryptedPrivateKeyInfo() returned");
-            if (epkiBytes == null) {
-                CMS.debug("RecoverService: createPFX() epkiBytes null");
-                throw new EBaseException("getEncryptedPrivateKeyInfo returned null");
+            boolean legacyP12 =
+                CMS.getConfigStore().getBoolean("kra.legacyPKCS12", true);
+
+            ASN1Value key;
+            if (legacyP12) {
+                Random ran = new SecureRandom();
+                byte[] salt = new byte[20];
+                ran.nextBytes(salt);
+
+                key = EncryptedPrivateKeyInfo.createPBE(
+                        PBEAlgorithm.PBE_SHA1_DES3_CBC,
+                        pass, salt, 1, passConverter, priKey, ct);
+                CMS.debug("RecoverService: createPFX() EncryptedPrivateKeyInfo.createPBE() returned");
+                if (key == null) {
+                    CMS.debug("RecoverService: createPFX() key null");
+                    throw new EBaseException("EncryptedPrivateKeyInfo.createPBE() failed");
+                } else {
+                    CMS.debug("RecoverService: createPFX() key not null");
+                }
             } else {
-                CMS.debug("RecoverService: createPFX() epkiBytes not null");
+                byte[] epkiBytes = ct.getCryptoStore().getEncryptedPrivateKeyInfo(
+                    /* NSS has a bug that causes any AES CBC encryption
+                     * to use AES-256, but AlgorithmID contains chosen
+                     * alg.  To avoid mismatch, use AES_256_CBC. */
+                    passConverter, pass, EncryptionAlgorithm.AES_256_CBC, 0, priKey);
+                CMS.debug("RecoverService: createPFX() getEncryptedPrivateKeyInfo() returned");
+                if (epkiBytes == null) {
+                    CMS.debug("RecoverService: createPFX() epkiBytes null");
+                    throw new EBaseException("getEncryptedPrivateKeyInfo returned null");
+                } else {
+                    CMS.debug("RecoverService: createPFX() epkiBytes not null");
+                }
+                key = new ANY(epkiBytes);
             }
-            ASN1Value key = new ANY(epkiBytes);
 
             SET keyAttrs = createBagAttrs(
                     x509cert.getSubjectDN().toString(),
-- 
1.8.3.1