Blob Blame History Raw
From fca5fd053434d112998c814bc6d9424b6a5bac98 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal@redhat.com>
Date: Wed, 21 Sep 2016 20:18:37 +1000
Subject: [PATCH 01/14] Do not attempt LWCA key retrieval for host authority

During two-step installation of externally-signed CA, installation
can fail because host authority's private key cannot be located (a
temporary condition), causing LWCA key replication to fire, which
throws NullPointerException because the host authority's AuthorityID
has not been set yet.

Do not start key retrieval if the CA's AuthorityID is null (a
condition which implies that the CA is the host authority).

Fixes: https://fedorahosted.org/pki/ticket/2466
---
 base/ca/src/com/netscape/ca/CertificateAuthority.java | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java
index 1f77fd8..a4f1024 100644
--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
@@ -1569,7 +1569,12 @@ public class CertificateAuthority
                 CMS.debug("CA signing key and cert not (yet) present in NSSDB");
                 signingUnitException = e;
                 if (retrieveKeys == true) {
-                    if (!keyRetrieverThreads.containsKey(authorityID)) {
+                    if (authorityID == null) {
+                        // Only the host authority should ever see a
+                        // null authorityID, e.g. during two-step
+                        // installation of externally-signed CA.
+                        CMS.debug("null authorityID -> host authority; not starting KeyRetriever");
+                    } else if (!keyRetrieverThreads.containsKey(authorityID)) {
                         CMS.debug("Starting KeyRetrieverRunner thread");
                         Thread t = new Thread(
                             new KeyRetrieverRunner(authorityID, mNickname, authorityKeyHosts),
-- 
2.7.4


From 84606cc69390187b7f0f11fff41a372fd96f8f93 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal@redhat.com>
Date: Thu, 22 Sep 2016 12:00:35 +1000
Subject: [PATCH 02/14] Compare serialised DNs in host authority check

CA startup creates an LWCA entry for the host authority if it
determines that one has not already been created.  It determines if
an LWCA entry corresponds to the host CA by comparing the DN from
LDAP with the DN from the host authority's certificate.

If the DN from the host authority's certificate contains values
encoded as PrintableString, it will compare unequal to the DN from
LDAP, which parses to UTF8String AVA values.  This causes the
addition of a spurious host authority entry every time the server
starts.

Serialise DNs before comparing, to avoid these false negatives.

Fixes: https://fedorahosted.org/pki/ticket/2475
---
 base/ca/src/com/netscape/ca/CertificateAuthority.java | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java
index a4f1024..ae90d3a 100644
--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
@@ -3256,7 +3256,12 @@ public class CertificateAuthority
         if (descAttr != null)
             desc = (String) descAttr.getStringValues().nextElement();
 
-        if (dn.equals(mName)) {
+        /* Determine if it is the host authority's entry, by
+         * comparing DNs.  DNs must be serialised in case different
+         * encodings are used for AVA values, e.g. PrintableString
+         * from LDAP vs UTF8String in certificate.
+         */
+        if (dn.toString().equals(mName.toString())) {
             CMS.debug("Found host authority");
             foundHostAuthority = true;
             this.authorityID = aid;
-- 
2.7.4


From ffa336b5c82a08e8d92f4a569766e5f09c37931e Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Thu, 15 Sep 2016 18:05:05 +0200
Subject: [PATCH 03/14] Troubleshooting improvements for SigningUnit.

To help troubleshooting the SigningUnit for CA and OCSP have been
modified to chain the original exceptions.

https://fedorahosted.org/pki/ticket/2463
(cherry picked from commit 15e2524c612184116763e36d5b91128662cf8006)
---
 base/ca/src/com/netscape/ca/SigningUnit.java     | 24 ++++++-------
 base/ocsp/src/com/netscape/ocsp/SigningUnit.java | 44 ++++++++++++------------
 2 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/base/ca/src/com/netscape/ca/SigningUnit.java b/base/ca/src/com/netscape/ca/SigningUnit.java
index f708e55..ac73a47 100644
--- a/base/ca/src/com/netscape/ca/SigningUnit.java
+++ b/base/ca/src/com/netscape/ca/SigningUnit.java
@@ -257,16 +257,16 @@ public final class SigningUnit implements ISigningUnit {
         } catch (NoSuchAlgorithmException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_ALG_NOT_SUPPORTED", algname, e.toString()));
             throw new ECAException(
-                    CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname));
+                    CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname), e);
         } catch (TokenException e) {
             // from get signature context or from initSign
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_ALG_NOT_SUPPORTED", algname, e.toString()));
             throw new ECAException(
-                    CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname));
+                    CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname), e);
         } catch (InvalidKeyException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_ALG_NOT_SUPPORTED", algname, e.toString()));
             throw new ECAException(
-                    CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED_FOR_KEY", algname));
+                    CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED_FOR_KEY", algname), e);
         }
     }
 
@@ -311,21 +311,21 @@ public final class SigningUnit implements ISigningUnit {
         } catch (NoSuchAlgorithmException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
             throw new ECAException(
-                    CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname));
+                    CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname), e);
         } catch (TokenException e) {
             // from get signature context or from initSign
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
             // XXX fix this exception later.
-            throw new EBaseException(e.toString());
+            throw new EBaseException(e);
         } catch (InvalidKeyException e) {
             // XXX fix this exception later.
-            throw new EBaseException(e.toString());
+            throw new EBaseException(e);
         } catch (SignatureException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
             CMS.debug("SigningUnit.sign: " + e.toString());
             CMS.checkForAndAutoShutdown();
             // XXX fix this exception later.
-            throw new EBaseException(e.toString());
+            throw new EBaseException(e);
         }
     }
 
@@ -351,21 +351,21 @@ public final class SigningUnit implements ISigningUnit {
         } catch (NoSuchAlgorithmException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
             // XXX fix this exception later.
-            throw new EBaseException(e.toString());
+            throw new EBaseException(e);
         } catch (TokenException e) {
             // from get signature context or from initSign
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
             // XXX fix this exception later.
-            throw new EBaseException(e.toString());
+            throw new EBaseException(e);
         } catch (InvalidKeyException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
             // XXX fix this exception later.
-            throw new EBaseException(e.toString());
+            throw new EBaseException(e);
         } catch (SignatureException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
             CMS.checkForAndAutoShutdown();
             // XXX fix this exception later.
-            throw new EBaseException(e.toString());
+            throw new EBaseException(e);
         }
     }
 
@@ -410,7 +410,7 @@ public final class SigningUnit implements ISigningUnit {
             String msg = "Invalid encoding in CA signing key.";
 
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", msg));
-            throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", msg));
+            throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", msg), e);
         }
 
         if (key.getAlgorithmId().getOID().equals(AlgorithmId.DSA_oid)) {
diff --git a/base/ocsp/src/com/netscape/ocsp/SigningUnit.java b/base/ocsp/src/com/netscape/ocsp/SigningUnit.java
index 5aff291..f1c4feb 100644
--- a/base/ocsp/src/com/netscape/ocsp/SigningUnit.java
+++ b/base/ocsp/src/com/netscape/ocsp/SigningUnit.java
@@ -22,10 +22,6 @@ import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
 import java.security.SignatureException;
 
-import netscape.security.x509.AlgorithmId;
-import netscape.security.x509.X509CertImpl;
-import netscape.security.x509.X509Key;
-
 import org.mozilla.jss.CryptoManager;
 import org.mozilla.jss.NoSuchTokenException;
 import org.mozilla.jss.crypto.CryptoToken;
@@ -48,6 +44,10 @@ import com.netscape.certsrv.security.ISigningUnit;
 import com.netscape.cmscore.security.JssSubsystem;
 import com.netscape.cmsutil.util.Cert;
 
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.X509Key;
+
 /**
  * OCSP signing unit based on JSS.
  *
@@ -175,24 +175,24 @@ public final class SigningUnit implements ISigningUnit {
         } catch (java.security.cert.CertificateException e) {
             log(ILogger.LL_FAILURE,
                     CMS.getLogMessage("CMSCORE_OCSP_CONVERT_X509", e.getMessage()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (CryptoManager.NotInitializedException e) {
             log(ILogger.LL_FAILURE,
                     CMS.getLogMessage("CMSCORE_OCSP_SIGNING", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (IncorrectPasswordException e) {
             log(ILogger.LL_FAILURE,
                     CMS.getLogMessage("CMSCORE_OCSP_INCORRECT_PWD", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (NoSuchTokenException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_OCSP_TOKEN_NOT_FOUND", tokenname, e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (ObjectNotFoundException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_OCSP_OBJECT_NOT_FOUND", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (TokenException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         }
     }
 
@@ -223,16 +223,16 @@ public final class SigningUnit implements ISigningUnit {
         } catch (NoSuchAlgorithmException e) {
             log(ILogger.LL_FAILURE,
                     CMS.getLogMessage("CMSCORE_OCSP_SIGN_ALG_NOT_SUPPORTED", algname));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (TokenException e) {
             // from get signature context or from initSign
             log(ILogger.LL_FAILURE,
                     CMS.getLogMessage("CMSCORE_OCSP_SIGN_ALG_NOT_SUPPORTED", algname));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (InvalidKeyException e) {
             log(ILogger.LL_FAILURE,
                     CMS.getLogMessage("CMSCORE_OCSP_SIGN_ALG_NOT_SUPPORTED", algname));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         }
     }
 
@@ -265,18 +265,18 @@ public final class SigningUnit implements ISigningUnit {
             return signer.sign();
         } catch (NoSuchAlgorithmException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (TokenException e) {
             // from get signature context or from initSign
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (InvalidKeyException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (SignatureException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
             CMS.checkForAndAutoShutdown();
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         }
     }
 
@@ -301,18 +301,18 @@ public final class SigningUnit implements ISigningUnit {
             return signer.verify(signature);
         } catch (NoSuchAlgorithmException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (TokenException e) {
             // from get signature context or from initSign
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (InvalidKeyException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         } catch (SignatureException e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
             CMS.checkForAndAutoShutdown();
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()), e);
         }
     }
 
@@ -357,7 +357,7 @@ public final class SigningUnit implements ISigningUnit {
             String msg = "Invalid encoding in OCSP signing key.";
 
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_OCSP_INVALID_ENCODING"));
-            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", msg));
+            throw new EOCSPException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", msg), e);
         }
 
         if (key.getAlgorithmId().getOID().equals(AlgorithmId.DSA_oid)) {
-- 
2.7.4


From 111a692379f76bdeb9d5c807bfb17dee381abab5 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Mon, 19 Sep 2016 22:54:51 +0200
Subject: [PATCH 04/14] Troubleshooting improvements for ConfigurationUtils.

To help troubleshooting the ConfigurationUtils has been modified
to chain the original exceptions and to show additional log
messages.

https://fedorahosted.org/pki/ticket/2463
(cherry picked from commit efc88b134f3f188c43b3bec978e9d19fd297df70)
---
 .../cms/servlet/csadmin/ConfigurationUtils.java         | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index cdb2844..92a9017 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -371,10 +371,15 @@ public class ConfigurationUtils {
 
         String body = post(sdhost, sdport, true, "/ca/admin/ca/getCookie",
                 content, null, null);
+        CMS.debug("ConfigurationUtils: response: " + body);
+
         return getContentValue(body, "header.session_id");
     }
 
     public static String getContentValue(String body, String header) {
+
+        CMS.debug("ConfigurationUtils: searching for " + header);
+
         StringTokenizer st = new StringTokenizer(body, "\n");
 
         while (st.hasMoreTokens()) {
@@ -994,7 +999,7 @@ public class ConfigurationUtils {
                 cm.findCertByNickname(nickname);
 
             } catch (ObjectNotFoundException e) {
-                throw new Exception("Missing system certificate: " + nickname);
+                throw new Exception("Missing system certificate: " + nickname, e);
             }
         }
     }
@@ -1679,7 +1684,7 @@ public class ConfigurationUtils {
             CMS.debug("checkParentExists: Parent entry " + parentDN + " exists.");
         } catch (LDAPException e) {
             if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
-                throw new EBaseException("Parent entry " + parentDN + "does not exist", e);
+                throw new EBaseException("Parent entry " + parentDN + " does not exist", e);
             } else {
                 CMS.debug("checkParentExists: " + e);
                 throw new EBaseException("Failed to determine if base DN exists: " + e, e);
@@ -2320,7 +2325,7 @@ public class ConfigurationUtils {
 
     public static KeyPair loadKeyPair(String nickname, String token) throws Exception {
 
-        CMS.debug("ConfigurationUtils: loadKeyPair(" + nickname + ")");
+        CMS.debug("ConfigurationUtils: loadKeyPair(" + nickname + ", " + token + ")");
 
         CryptoManager cm = CryptoManager.getInstance();
 
@@ -3376,12 +3381,12 @@ public class ConfigurationUtils {
         try {
             @SuppressWarnings("unused")
             boolean done = cs.getBoolean("preop.CertRequestPanel.done"); // check for errors
-        } catch (Exception ee) {
+        } catch (Exception e) {
             if (hardware) {
                 CMS.debug("ConfigurationUtils: findCertificate: The certificate with the same nickname: "
                         + fullnickname + " has been found on HSM. Please remove it before proceeding.");
                 throw new IOException("The certificate with the same nickname: "
-                        + fullnickname + " has been found on HSM. Please remove it before proceeding.");
+                        + fullnickname + " has been found on HSM. Please remove it before proceeding.", e);
             }
         }
         return true;
@@ -4510,7 +4515,7 @@ public class ConfigurationUtils {
 
         if (response == null || response.equals("")) {
             CMS.debug("exportTransportCert: response is empty or null.");
-            throw new IOException("The server " + targetURI + "is not available");
+            throw new IOException("The server " + targetURI + " is not available");
         } else {
             ByteArrayInputStream bis = new ByteArrayInputStream(response.getBytes());
             XMLObject parser = new XMLObject(bis);
-- 
2.7.4


From be04003e1f5fb1ee363cd46356c6623ccc9fa4f7 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Wed, 21 Sep 2016 06:52:02 +0200
Subject: [PATCH 05/14] Additional improvements for SigningUnit.

To help troubleshooting the SigningUnit for CA have been modified
to show additional log messages.

https://fedorahosted.org/pki/ticket/2463
(cherry picked from commit 78949dc38608fa839e96780c6458f6dea5db9898)
---
 base/ca/src/com/netscape/ca/SigningUnit.java | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/base/ca/src/com/netscape/ca/SigningUnit.java b/base/ca/src/com/netscape/ca/SigningUnit.java
index ac73a47..405f20c 100644
--- a/base/ca/src/com/netscape/ca/SigningUnit.java
+++ b/base/ca/src/com/netscape/ca/SigningUnit.java
@@ -171,6 +171,7 @@ public final class SigningUnit implements ISigningUnit {
                 mCert = mManager.findCertByNickname(mNickname);
                 CMS.debug("Found cert by nickname: '" + mNickname + "' with serial number: " + mCert.getSerialNumber());
             } catch (ObjectNotFoundException e) {
+                CMS.debug("Unable to find certificate " + mNickname);
                 throw new CAMissingCertException(CMS.getUserMessage("CMS_CA_CERT_OBJECT_NOT_FOUND"), e);
             }
 
@@ -181,6 +182,7 @@ public final class SigningUnit implements ISigningUnit {
                 mPrivk = mManager.findPrivKeyByCert(mCert);
                 CMS.debug("Got private key from cert");
             } catch (ObjectNotFoundException e) {
+                CMS.debug("Unable to find private key for " + mNickname);
                 throw new CAMissingKeyException(CMS.getUserMessage("CMS_CA_CERT_OBJECT_NOT_FOUND"), e);
             }
 
-- 
2.7.4


From 5c55a8f15708fb9af77b799516b9c0fda2d25116 Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu@dhcp-16-189.sjc.redhat.com>
Date: Mon, 3 Oct 2016 17:02:10 -0700
Subject: [PATCH 06/14] Ticket #1527 TPS Enrollment always goes to "ca1" (bug
 fix) This patch fixes the bug that after revocation ca discovery, the
 revokeCertificate call goes back to the default ca, the ca that the
 certificate is to be enrollmed with; This causes problem when the revocation
 ca is a different ca.

(cherry picked from commit 3b93a22c4ffa6e5e16cfd5c8ec02348c58b78422)
---
 .../server/tps/cms/CARemoteRequestHandler.java     | 48 +++++++++++++++++-----
 1 file changed, 38 insertions(+), 10 deletions(-)

diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java
index 8eafa36..35a82d5 100644
--- a/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/CARemoteRequestHandler.java
@@ -513,7 +513,21 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
             String serialno,
             RevocationReason reason)
             throws EBaseException {
+        return revokeCertificate(null, serialno, reason);
+    }
+    private CARevokeCertResponse revokeCertificate(
+            String caConn,
+            String serialno,
+            RevocationReason reason)
+            throws EBaseException {
 
+        String revCAid = connid;
+        if (caConn != null) {
+            CMS.debug("CARemoteRequestHandler: revokeCertificate(): passed in ca ID: " + caConn);
+            revCAid = caConn;
+        } else {
+            CMS.debug("CARemoteRequestHandler: revokeCertificate(): using default ca ID:" + connid);
+        }
         CMS.debug("CARemoteRequestHandler: revokeCertificate(): begins on serial#:" + serialno);
         if (serialno == null || reason == null) {
             throw new EBaseException("CARemoteRequestHandler: revokeCertificate(): input parameter null.");
@@ -524,9 +538,9 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
         TPSSubsystem subsystem =
                 (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
         HttpConnector conn =
-                (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+                (HttpConnector) subsystem.getConnectionManager().getConnector(revCAid);
         if (conn == null) {
-            throw new EBaseException("CARemoteRequestHandler: revokeCertificate() to connid: " + connid + ": HttpConnector conn null.");
+            throw new EBaseException("CARemoteRequestHandler: revokeCertificate() to connid: " + revCAid + ": HttpConnector conn null.");
         }
         CMS.debug("CARemoteRequestHandler: revokeCertificate(): sending request to CA");
         HttpResponse resp =
@@ -537,7 +551,7 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
                                 IRemoteRequest.CA_REVOKE_SERIAL + "=" + serialno + ")&" +
                                 IRemoteRequest.CA_REVOKE_COUNT + "=1");
         if (resp == null) {
-            throw new EBaseException("CARemoteRequestHandler: revokeCertificate() to connid: " + connid + ": response null.");
+            throw new EBaseException("CARemoteRequestHandler: revokeCertificate() to connid: " + revCAid + ": response null.");
         }
         String content = resp.getContent();
 
@@ -570,7 +584,7 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
             response.put(IRemoteRequest.RESPONSE_STATUS, ist);
 
             CMS.debug("CARemoteRequestHandler: revokeCertificate(): ends.");
-            return new CARevokeCertResponse(connid, response);
+            return new CARevokeCertResponse(revCAid, response);
         } else {
             CMS.debug("CARemoteRequestHandler: revokeCertificate(): no response content.");
             throw new EBaseException("CARemoteRequestHandler: revokeCertificate(): no response content.");
@@ -588,7 +602,20 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
     private CARevokeCertResponse unrevokeCertificate(
             String serialno)
             throws EBaseException {
+        return unrevokeCertificate(null, serialno);
+    }
+    private CARevokeCertResponse unrevokeCertificate(
+            String caConn,
+            String serialno)
+            throws EBaseException {
 
+        String unrevCAid = connid;
+        if (caConn != null) {
+            CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): passed in ca ID: " + caConn);
+            unrevCAid = caConn;
+        } else {
+            CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): using default ca ID:" + connid);
+        }
         CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): begins on serial#:" + serialno);
         if (serialno == null) {
             throw new EBaseException("CARemoteRequestHandler: unrevokeCertificate(): input parameter null.");
@@ -597,16 +624,16 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
         TPSSubsystem subsystem =
                 (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
         HttpConnector conn =
-                (HttpConnector) subsystem.getConnectionManager().getConnector(connid);
+                (HttpConnector) subsystem.getConnectionManager().getConnector(unrevCAid);
         if (conn == null) {
-            throw new EBaseException("CARemoteRequestHandler: unrevokeCertificate() to connid: " + connid + ": HttpConnector conn null.");
+            throw new EBaseException("CARemoteRequestHandler: unrevokeCertificate() to connid: " + unrevCAid + ": HttpConnector conn null.");
         }
         CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): sending request to CA");
         HttpResponse resp =
                 conn.send("unrevoke",
                         IRemoteRequest.CA_UNREVOKE_SERIAL + "=" + serialno);
         if (resp == null) {
-            throw new EBaseException("CARemoteRequestHandler: unrevokeCertificate() to connid: " + connid + ": response null.");
+            throw new EBaseException("CARemoteRequestHandler: unrevokeCertificate() to connid: " + unrevCAid + ": response null.");
         }
         String content = resp.getContent();
 
@@ -639,7 +666,7 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
             response.put(IRemoteRequest.RESPONSE_STATUS, ist);
 
             CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): ends.");
-            return new CARevokeCertResponse(connid, response);
+            return new CARevokeCertResponse(unrevCAid, response);
         } else {
             CMS.debug("CARemoteRequestHandler: unrevokeCertificate(): no response content.");
             throw new EBaseException("CARemoteRequestHandler: unrevokeCertificate(): no response content.");
@@ -693,14 +720,15 @@ public class CARemoteRequestHandler extends RemoteRequestHandler
         Exception exception = null;
 
         for (String ca : caList) {
+            CMS.debug("CARemoteRequestHandler: revokeFromOtherCA: processing caList: ca id:" + ca);
             try {
                 String caSkiString = getCaSki(ca);
                 if (certAkiString.equals(caSkiString)) {
                     CMS.debug("CARemoteRequestHandler: revokeFromOtherCA() cert AKI and caCert SKI matched");
                     if (revoke) {
-                        return revokeCertificate(serialno, reason);
+                        return revokeCertificate(ca, serialno, reason);
                     } else {
-                        return unrevokeCertificate(serialno);
+                        return unrevokeCertificate(ca, serialno);
                     }
                 } else { // not a match then iterate to next ca in list
                     CMS.debug("CARemoteRequestHandler: revokeFromOtherCA() cert AKI and caCert SKI not matched");
-- 
2.7.4


From 9bfe6101e82319d9f14edc0b0c1c16ca02a0f9a4 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Wed, 5 Oct 2016 22:58:16 +0200
Subject: [PATCH 07/14] Removed duplicate classes.

The CMake scripts have been modified to store compiled Java classes
in separate folders for each JAR files to avoid duplicates.

https://fedorahosted.org/pki/ticket/2505
(cherry picked from commit 0f9212ee0fee093be5e47afc15629d281984ec09)
---
 CMakeLists.txt                                     | 1 -
 base/ca/src/CMakeLists.txt                         | 4 ++--
 base/common/src/CMakeLists.txt                     | 4 ++--
 base/java-tools/src/CMakeLists.txt                 | 4 ++--
 base/kra/src/CMakeLists.txt                        | 4 ++--
 base/ocsp/src/CMakeLists.txt                       | 4 ++--
 base/server/cms/src/CMakeLists.txt                 | 4 ++--
 base/server/cmscore/src/CMakeLists.txt             | 4 ++--
 base/symkey/src/CMakeLists.txt                     | 4 ++--
 base/symkey/src/com/netscape/symkey/CMakeLists.txt | 2 +-
 base/tks/src/CMakeLists.txt                        | 4 ++--
 base/tps/src/CMakeLists.txt                        | 4 ++--
 base/util/src/CMakeLists.txt                       | 8 ++++----
 14 files changed, 27 insertions(+), 29 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c746056..457e144 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,7 +54,6 @@ macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source buil
 include(MacroCopyFile)
 include(Java)
 
-file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/classes)
 file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/dist)
 
 # required for all PKI components
diff --git a/base/ca/src/CMakeLists.txt b/base/ca/src/CMakeLists.txt
index 854ce28..e612d72 100644
--- a/base/ca/src/CMakeLists.txt
+++ b/base/ca/src/CMakeLists.txt
@@ -96,7 +96,7 @@ javac(pki-ca-classes
         ${PKI_CMSUTIL_JAR} ${PKI_NSUTIL_JAR}
         ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         symkey-jar pki-nsutil-jar pki-cmsutil-jar pki-certsrv-jar pki-cms-jar pki-cmscore-jar
 )
@@ -114,7 +114,7 @@ jar(pki-ca-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-ca.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/ca/*.class
         org/dogtagpki/server/ca/*.class
diff --git a/base/common/src/CMakeLists.txt b/base/common/src/CMakeLists.txt
index ee41b2f..7ce833c 100644
--- a/base/common/src/CMakeLists.txt
+++ b/base/common/src/CMakeLists.txt
@@ -131,7 +131,7 @@ javac(pki-certsrv-classes
         ${JAXRS_API_JAR} ${RESTEASY_JAXRS_JAR} ${RESTEASY_ATOM_PROVIDER_JAR} ${RESTEASY_CLIENT_JAR}
         ${HTTPCLIENT_JAR} ${HTTPCORE_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         pki-nsutil-jar pki-cmsutil-jar
 )
@@ -149,7 +149,7 @@ jar(pki-certsrv-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-certsrv.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/certsrv/*.class
         org/dogtagpki/tps/*.class
diff --git a/base/java-tools/src/CMakeLists.txt b/base/java-tools/src/CMakeLists.txt
index e7ca5db..6753102 100644
--- a/base/java-tools/src/CMakeLists.txt
+++ b/base/java-tools/src/CMakeLists.txt
@@ -100,7 +100,7 @@ javac(pki-tools-classes
         ${JAXRS_API_JAR} ${RESTEASY_JAXRS_JAR} ${RESTEASY_ATOM_PROVIDER_JAR}
         ${HTTPCLIENT_JAR} ${HTTPCORE_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         pki-nsutil-jar pki-cmsutil-jar pki-certsrv-jar
 )
@@ -118,7 +118,7 @@ jar(pki-tools-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-tools.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/cmstools/*.class
     DEPENDS
diff --git a/base/kra/src/CMakeLists.txt b/base/kra/src/CMakeLists.txt
index 400ec01..c04d7fe 100644
--- a/base/kra/src/CMakeLists.txt
+++ b/base/kra/src/CMakeLists.txt
@@ -118,7 +118,7 @@ javac(pki-kra-classes
         ${PKI_CMSUTIL_JAR} ${PKI_NSUTIL_JAR}
         ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR} ${TOMCAT_CATALINA_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         symkey-jar pki-nsutil-jar pki-cmsutil-jar pki-certsrv-jar pki-cms-jar pki-cmscore-jar
 )
@@ -136,7 +136,7 @@ jar(pki-kra-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-kra.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/kra/*.class
         org/dogtagpki/server/kra/*.class
diff --git a/base/ocsp/src/CMakeLists.txt b/base/ocsp/src/CMakeLists.txt
index 32fcc92..78df95f 100644
--- a/base/ocsp/src/CMakeLists.txt
+++ b/base/ocsp/src/CMakeLists.txt
@@ -80,7 +80,7 @@ javac(pki-ocsp-classes
         ${LDAPJDK_JAR} ${JAXRS_API_JAR}
         ${JSS_JAR} ${COMMONS_CODEC_JAR} ${SYMKEY_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         symkey-jar pki-nsutil-jar pki-cmsutil-jar pki-certsrv-jar pki-cms-jar pki-cmscore-jar
 )
@@ -98,7 +98,7 @@ jar(pki-ocsp-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-ocsp.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/ocsp/*.class
         org/dogtagpki/server/ocsp/*.class
diff --git a/base/server/cms/src/CMakeLists.txt b/base/server/cms/src/CMakeLists.txt
index 93f4a8a..447dcb1 100644
--- a/base/server/cms/src/CMakeLists.txt
+++ b/base/server/cms/src/CMakeLists.txt
@@ -133,7 +133,7 @@ javac(pki-cms-classes
         ${JAXRS_API_JAR} ${RESTEASY_JAXRS_JAR} ${RESTEASY_ATOM_PROVIDER_JAR}
         ${PKI_NSUTIL_JAR} ${PKI_CMSUTIL_JAR} ${PKI_CERTSRV_JAR} ${PKI_TOMCAT_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         pki-nsutil-jar pki-cmsutil-jar pki-certsrv-jar pki-tomcat-jar
 )
@@ -151,7 +151,7 @@ jar(pki-cms-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-cms.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/cms/*.class
         org/dogtagpki/server/*.class
diff --git a/base/server/cmscore/src/CMakeLists.txt b/base/server/cmscore/src/CMakeLists.txt
index 32e4351..fe8dba2 100644
--- a/base/server/cmscore/src/CMakeLists.txt
+++ b/base/server/cmscore/src/CMakeLists.txt
@@ -133,7 +133,7 @@ javac(pki-cmscore-classes
         ${HTTPCLIENT_JAR} ${HTTPCORE_JAR}
         ${NUXWDOG_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         pki-nsutil-jar pki-cmsutil-jar pki-certsrv-jar pki-cms-jar pki-tomcat-jar
 )
@@ -151,7 +151,7 @@ jar(pki-cmscore-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-cmscore.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/cmscore/*.class
     DEPENDS
diff --git a/base/symkey/src/CMakeLists.txt b/base/symkey/src/CMakeLists.txt
index 9a4e10f..8455d59 100644
--- a/base/symkey/src/CMakeLists.txt
+++ b/base/symkey/src/CMakeLists.txt
@@ -15,14 +15,14 @@ javac(symkey-classes
     CLASSPATH
         ${JSS_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
 )
 
 jar(symkey-jar
     CREATE
         ${CMAKE_BINARY_DIR}/dist/symkey.jar
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/symkey/*.class
     DEPENDS
diff --git a/base/symkey/src/com/netscape/symkey/CMakeLists.txt b/base/symkey/src/com/netscape/symkey/CMakeLists.txt
index 590a7d8..6915ee9 100644
--- a/base/symkey/src/com/netscape/symkey/CMakeLists.txt
+++ b/base/symkey/src/com/netscape/symkey/CMakeLists.txt
@@ -42,7 +42,7 @@ add_custom_command(
         ${symkey_library_HDRS}
     COMMAND
         ${Java_JAVAH_EXECUTABLE}
-            -classpath ${CMAKE_BINARY_DIR}/classes:${JAVA_LIB_INSTALL_DIR}/jss4.jar
+            -classpath ${CMAKE_CURRENT_BINARY_DIR}/../../../classes:${JAVA_LIB_INSTALL_DIR}/jss4.jar
             -jni -d ${CMAKE_CURRENT_BINARY_DIR}
             com.netscape.symkey.SessionKey
 )
diff --git a/base/tks/src/CMakeLists.txt b/base/tks/src/CMakeLists.txt
index 51f98c9..146e70a 100644
--- a/base/tks/src/CMakeLists.txt
+++ b/base/tks/src/CMakeLists.txt
@@ -118,7 +118,7 @@ javac(pki-tks-classes
         ${PKI_CMSUTIL_JAR} ${PKI_NSUTIL_JAR}
         ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         symkey-jar pki-nsutil-jar pki-cmsutil-jar pki-certsrv-jar pki-cms-jar pki-cmscore-jar
 )
@@ -136,7 +136,7 @@ jar(pki-tks-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-tks.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/tks/*.class
         org/dogtagpki/server/tks/*.class
diff --git a/base/tps/src/CMakeLists.txt b/base/tps/src/CMakeLists.txt
index 5e51f60..f517a63 100644
--- a/base/tps/src/CMakeLists.txt
+++ b/base/tps/src/CMakeLists.txt
@@ -121,7 +121,7 @@ javac(pki-tps-classes
         ${PKI_CMSUTIL_JAR} ${PKI_NSUTIL_JAR}
         ${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         symkey-jar pki-nsutil-jar pki-cmsutil-jar pki-certsrv-jar pki-cms-jar pki-cmscore-jar
 )
@@ -139,7 +139,7 @@ jar(pki-tps-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-tps.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         org/dogtagpki/server/tps/*.class
     DEPENDS
diff --git a/base/util/src/CMakeLists.txt b/base/util/src/CMakeLists.txt
index f374c01..bf531d4 100644
--- a/base/util/src/CMakeLists.txt
+++ b/base/util/src/CMakeLists.txt
@@ -76,7 +76,7 @@ javac(pki-nsutil-classes
         ${APACHE_COMMONS_LANG_JAR} ${LDAPJDK_JAR} ${XALAN_JAR} ${XERCES_JAR}
         ${JSS_JAR} ${COMMONS_CODEC_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
 )
 
 configure_file(
@@ -92,7 +92,7 @@ jar(pki-nsutil-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-nsutil.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         netscape/*.class
     DEPENDS
@@ -118,7 +118,7 @@ javac(pki-cmsutil-classes
         ${LDAPJDK_JAR} ${XALAN_JAR} ${XERCES_JAR}
         ${JSS_JAR} ${COMMONS_CODEC_JAR} ${NUXWDOG_JAR}
     OUTPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     DEPENDS
         pki-nsutil-jar
 )
@@ -136,7 +136,7 @@ jar(pki-cmsutil-jar
     PARAMS
         ${CMAKE_CURRENT_BINARY_DIR}/pki-cmsutil.mf
     INPUT_DIR
-        ${CMAKE_BINARY_DIR}/classes
+        ${CMAKE_CURRENT_BINARY_DIR}/classes
     FILES
         com/netscape/cmsutil/*.class
     DEPENDS
-- 
2.7.4


From 94063f38ca295b961b34caccbe30d6cdda5ad5e2 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Wed, 5 Oct 2016 06:58:27 +0200
Subject: [PATCH 08/14] Troubleshooting improvements for GetCertChain.

To help troubleshooting the GetCertChain servlet has been modified
to log the certificate chain being returned. The ConfigurationUtils
has also been modified to log the certificate chain received.

https://fedorahosted.org/pki/ticket/2463
(cherry picked from commit 8c40580327493e4d18dbc32c48fd66e86ab1e500)
---
 .../cms/servlet/csadmin/ConfigurationUtils.java     | 15 +++++++++++++--
 .../netscape/cms/servlet/csadmin/GetCertChain.java  | 21 +++++++++++++++++----
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index 92a9017..ed70a09 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -289,9 +289,20 @@ public class ConfigurationUtils {
                 // separate individual certs in chain for display
                 byte[] decoded = CryptoUtil.base64Decode(certchain);
                 java.security.cert.X509Certificate[] b_certchain = CryptoUtil.getX509CertificateFromPKCS7(decoded);
-                int size = 0;
 
-                if (b_certchain != null) {
+                int size;
+
+                if (b_certchain == null) {
+                    CMS.debug("ConfigurationUtils: no certificate chain");
+
+                    size = 0;
+
+                } else {
+                    CMS.debug("ConfigurationUtils: certificate chain:");
+                    for (java.security.cert.X509Certificate cert : b_certchain) {
+                        CMS.debug("ConfigurationUtils: - " + cert.getSubjectDN());
+                    }
+
                     size = b_certchain.length;
                 }
 
diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/GetCertChain.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/GetCertChain.java
index 8cc0f85..df60d42 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/GetCertChain.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/GetCertChain.java
@@ -19,6 +19,7 @@ package com.netscape.cms.servlet.csadmin;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.security.cert.X509Certificate;
 import java.util.Locale;
 
 import javax.servlet.ServletConfig;
@@ -26,8 +27,6 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import netscape.security.x509.CertificateChain;
-
 import org.w3c.dom.Node;
 
 import com.netscape.certsrv.apps.CMS;
@@ -39,6 +38,8 @@ import com.netscape.cms.servlet.base.UserInfo;
 import com.netscape.cms.servlet.common.CMSRequest;
 import com.netscape.cmsutil.xml.XMLObject;
 
+import netscape.security.x509.CertificateChain;
+
 public class GetCertChain extends CMSServlet {
 
     /**
@@ -70,17 +71,29 @@ public class GetCertChain extends CMSServlet {
      * @param cmsReq the object holding the request and response information
      */
     protected void process(CMSRequest cmsReq) throws EBaseException {
+
         HttpServletResponse httpResp = cmsReq.getHttpResp();
 
         CertificateChain certChain = ((ICertAuthority) mAuthority).getCACertChain();
 
         if (certChain == null) {
-            CMS.debug(
-                    "GetCertChain displayChain: cannot get the certificate chain.");
+            CMS.debug("GetCertChain: cannot get the certificate chain.");
             outputError(httpResp, "Error: Failed to get certificate chain.");
             return;
         }
 
+        X509Certificate[] certs = certChain.getChain();
+
+        if (certs == null) {
+            CMS.debug("GetCertChain: no certificate chain");
+
+        } else {
+            CMS.debug("GetCertChain: certificate chain:");
+            for (X509Certificate cert : certs) {
+                CMS.debug("GetCertChain: - " + cert.getSubjectDN());
+            }
+        }
+
         byte[] bytes = null;
 
         try {
-- 
2.7.4


From 2778e1886e1c5bc3139cbdf3278d1324377ec615 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Thu, 6 Oct 2016 01:00:42 +0200
Subject: [PATCH 09/14] Fixed NSSDatabase.create_request().

The NSSDatabase.create_request() has been modified to remove
a superfluous argument when invoking certutil.

(cherry picked from commit 173fa749c02e489cb1257288bef7c3b42a4aa208)
---
 base/common/python/pki/nssdb.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/base/common/python/pki/nssdb.py b/base/common/python/pki/nssdb.py
index 736efca..c044ba1 100644
--- a/base/common/python/pki/nssdb.py
+++ b/base/common/python/pki/nssdb.py
@@ -237,7 +237,7 @@ class NSSDatabase(object):
 
             if basic_constraints_ext:
 
-                cmd.extend(['-2', hash_alg])
+                cmd.extend(['-2'])
 
                 # Is this a CA certificate [y/N]?
                 if basic_constraints_ext['ca']:
-- 
2.7.4


From 6e0e2afbbeb1bb7acdf402edf5ca426bfc01a433 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Thu, 6 Oct 2016 22:08:15 +0200
Subject: [PATCH 10/14] Fixed ConfigurationUtils.importCertChain().

The ConfigurationUtils.importCertChain() has been modified to
ignore UNKNOWN_ISSUER error when connecting to a server that
does not have the complete certificate chain.

https://fedorahosted.org/pki/ticket/2497
(cherry picked from commit 343a756bb93abf057f2999858ba9e170fa84f143)
---
 .../cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java   | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index ed70a09..001b6ab 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -261,8 +261,9 @@ public class ConfigurationUtils {
 
         IConfigStore cs = CMS.getConfigStore();
         ConfigCertApprovalCallback certApprovalCallback = new ConfigCertApprovalCallback();
-        // Ignore untrusted issuer to get cert chain.
+        // Ignore untrusted/unknown issuer to get cert chain.
         certApprovalCallback.ignoreError(ValidityStatus.UNTRUSTED_ISSUER);
+        certApprovalCallback.ignoreError(ValidityStatus.UNKNOWN_ISSUER);
         String c = get(host, port, true, serverPath, null, certApprovalCallback);
 
         if (c != null) {
-- 
2.7.4


From 3ab6c634eca7705f31d86bb9e8dcce96f1e4056b Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu@dhcp-16-189.sjc.redhat.com>
Date: Wed, 5 Oct 2016 16:09:24 -0700
Subject: [PATCH 12/14] Ticket #2496 Cert/Key recovery is successful when the
 cert serial number and key id on the ldap user mismatches Problem: There are
 two ways to recover the keys with a. by cert b. by keyId When recovering by
 cert, KRA checks if cert and key matches before returning; However, in case
 of recovering by keyId, KRA has no way of checking.  TPS also has no way of
 checking because the recovered private keys are warpped. This patch adds a
 control parameter externalReg.recovery.byKeyID to determine if TPS should
 recover keys by keyIDs. By default, it is false, so certs are used to search
 for key record and recover.

Code summary for externalReg key recovery:
 config default: externalReg.recover.byKeyID=false
Recover either by keyID or by cert
 When recovering by keyid: externalReg.recover.byKeyID=true
   - keyid in record indicates actual recovery;
   - missing of which means retention;
 When recovering by cert: externalReg.recover.byKeyID=false
   - keyid field needs to be present
     but the value is not relevant and will be ignored (a "0" would be fine)
   - missing of keyid still means retention;

(In hindsight, recovery by keyid is probably more accident-prone and should be discouraged)

(cherry picked from commit e00a28fcdc3e8fea920c85563a3ab26b123dda2d)
---
 base/tps/shared/conf/CS.cfg                        | 18 +++++-
 .../server/tps/cms/KRARemoteRequestHandler.java    | 46 +++++++++------
 .../server/tps/processor/TPSEnrollProcessor.java   | 68 +++++++++++++++++-----
 3 files changed, 98 insertions(+), 34 deletions(-)

diff --git a/base/tps/shared/conf/CS.cfg b/base/tps/shared/conf/CS.cfg
index a8499a2..d5d9daf 100644
--- a/base/tps/shared/conf/CS.cfg
+++ b/base/tps/shared/conf/CS.cfg
@@ -150,7 +150,22 @@ externalReg._016=#         2. user record does not contain tokenType
 externalReg._017=#
 externalReg._018=# mappingResolver - when exists, tells whcih mappingResolver to use
 externalReg._019=#         to map to the right keySet
-externalReg._020=#########################################
+externalReg._020=#
+externalReg._021=# recover.byKeyID - (by default, recover by cert)
+externalReg._022=#    Recover either by keyID or by cert
+externalReg._023=#     When recovering by keyid: externalReg.recover.byKeyID=true
+externalReg._024=#       - keyid in record indicates actual recovery;
+externalReg._025=#         e.g. (certstoadd: 36,ca1,5,kra1)
+externalReg._026=#       - missing of which means retention;
+externalReg._027=#         e.g. (certstoadd: 36,ca1)
+externalReg._028=#     When recovering by cert: externalReg.recover.byKeyID=false
+externalReg._029=#       - keyid field needs to be present
+externalReg._030=#         but the value is not relevant and will be ignored
+externalReg._031=#         (a "0" would be fine)
+externalReg._032=#         e.g. (certstoadd: 36,ca1,0,kra1)
+externalReg._033=#       - missing of keyid still means retention;
+externalReg._034=#         e.g. (certstoadd: 36,ca1)
+externalReg._035=#########################################
 externalReg.authId=ldap1
 externalReg.allowRecoverInvalidCert.enable=true
 externalReg.default.tokenType=externalRegAddToToken
@@ -158,6 +173,7 @@ externalReg.delegation.enable=false
 externalReg.enable=false
 externalReg.format.loginRequest.enable=true
 externalReg.mappingResolver=keySetMappingResolver
+externalReg.recover.byKeyID=false
 failover.pod.enable=false
 general.applet_ext=ijc
 general.pwlength.min=16
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java
index 59b5208..80439ca 100644
--- a/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/KRARemoteRequestHandler.java
@@ -23,6 +23,7 @@ import java.util.Hashtable;
 
 import org.dogtagpki.server.connector.IRemoteRequest;
 import org.dogtagpki.server.tps.TPSSubsystem;
+import org.dogtagpki.tps.main.Util;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
@@ -262,26 +263,33 @@ public class KRARemoteRequestHandler extends RemoteRequestHandler
         CMS.debug("KRARemoteRequestHandler: recoverKey(): sending request to KRA");
 
         String sendMsg = null;
-        if (b64cert != null) { // recover by cert
-            sendMsg = IRemoteRequest.TOKEN_CUID + "=" +
-                    cuid +
-                    "&" + IRemoteRequest.KRA_UserId + "=" +
-                    userid +
-                    "&" + IRemoteRequest.KRA_RECOVERY_CERT + "=" +
-                    b64cert +
-                    "&" + IRemoteRequest.KRA_Trans_DesKey + "=" +
-                    sDesKey;
-        } else if (keyid != BigInteger.valueOf(0)){ // recover by keyid ... keyid != BigInteger.valueOf(0)
-            CMS.debug("KRARemoteRequestHandler: recoverKey(): keyid = " + keyid);
-            sendMsg = IRemoteRequest.TOKEN_CUID + "=" +
-                    cuid +
-                    "&" + IRemoteRequest.KRA_UserId + "=" +
-                    userid +
-                    "&" + IRemoteRequest.KRA_RECOVERY_KEYID + "=" +
-                    keyid.toString() +
-                    "&" + IRemoteRequest.KRA_Trans_DesKey + "=" +
-                    sDesKey;
+        try {
+            if (b64cert != null) { // recover by cert
+                // CMS.debug("KRARemoteRequestHandler: recoverKey(): uriEncoded cert= " + Util.uriEncode(b64cert));
+                sendMsg = IRemoteRequest.TOKEN_CUID + "=" +
+                        cuid +
+                        "&" + IRemoteRequest.KRA_UserId + "=" +
+                        userid +
+                        "&" + IRemoteRequest.KRA_RECOVERY_CERT + "=" +
+                        Util.uriEncode(b64cert) +
+                        "&" + IRemoteRequest.KRA_Trans_DesKey + "=" +
+                        Util.uriEncode(sDesKey);
+            } else if (keyid != BigInteger.valueOf(0)) { // recover by keyid ... keyid != BigInteger.valueOf(0)
+                CMS.debug("KRARemoteRequestHandler: recoverKey(): keyid = " + keyid);
+                sendMsg = IRemoteRequest.TOKEN_CUID + "=" +
+                        cuid +
+                        "&" + IRemoteRequest.KRA_UserId + "=" +
+                        userid +
+                        "&" + IRemoteRequest.KRA_RECOVERY_KEYID + "=" +
+                        keyid.toString() +
+                        "&" + IRemoteRequest.KRA_Trans_DesKey + "=" +
+                        Util.uriEncode(sDesKey);
+            }
+        } catch (Exception e) {
+            CMS.debug("KRARemoteRequestHandler: recoverKey(): uriEncode failed: " + e);
+            throw new EBaseException("KRARemoteRequestHandler: recoverKey(): uriEncode failed: " + e);
         }
+
         //CMS.debug("KRARemoteRequestHandler: recoverKey(): sendMsg =" + sendMsg);
         HttpResponse resp =
                 conn.send("TokenKeyRecovery",
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
index 9d42546..aa23bf0 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
@@ -14,11 +14,6 @@ import java.util.Map;
 import java.util.Random;
 import java.util.zip.DataFormatException;
 
-import netscape.security.provider.RSAPublicKey;
-//import org.mozilla.jss.pkcs11.PK11ECPublicKey;
-import netscape.security.util.BigInt;
-import netscape.security.x509.X509CertImpl;
-
 import org.dogtagpki.server.tps.TPSSession;
 import org.dogtagpki.server.tps.TPSSubsystem;
 import org.dogtagpki.server.tps.TPSTokenPolicy;
@@ -58,8 +53,6 @@ import org.mozilla.jss.pkcs11.PK11PubKey;
 import org.mozilla.jss.pkcs11.PK11RSAPublicKey;
 import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
 
-import sun.security.pkcs11.wrapper.PKCS11Constants;
-
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.EPropertyNotFound;
@@ -67,6 +60,12 @@ import com.netscape.certsrv.base.IConfigStore;
 import com.netscape.certsrv.tps.token.TokenStatus;
 import com.netscape.cmsutil.util.Utils;
 
+import netscape.security.provider.RSAPublicKey;
+//import org.mozilla.jss.pkcs11.PK11ECPublicKey;
+import netscape.security.util.BigInt;
+import netscape.security.x509.X509CertImpl;
+import sun.security.pkcs11.wrapper.PKCS11Constants;
+
 public class TPSEnrollProcessor extends TPSProcessor {
 
     public TPSEnrollProcessor(TPSSession session) {
@@ -1263,18 +1262,38 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 }
             }
 
+            // default: externalReg.recover.byKeyID=false
+            String b64cert = null;
+            if (getExternalRegRecoverByKeyID() == false) {
+                b64cert = certResp.getCertB64();
+                //CMS.debug("TPSEnrollProcessor.processRecovery: cert blob to recover key with: " + b64cert);
+            }
+
+            /*
+             * Recover either by keyID or by cert
+             * When recovering by keyid:
+             *   - keyid in record indicates actual recovery;
+             *   - missing of which means retention;
+             * When recovering by cert:
+             *   - keyid field needs to be present
+             *     but the value is not relevant (a "0" would be fine)
+             *   - missing of keyid still means retention;
+             */
             if (keyid == null) {
-                logMsg = " no keyid; skip key recovery; continue";
+                logMsg = " no keyid; retention; skip key recovery; continue";
                 CMS.debug(method + logMsg);
                 continue;
-            } else if (keyid.compareTo(BigInteger.valueOf(0)) == 0) {
-                logMsg = " keyid is 0; invalid; skip key recovery; continue";
+            } else {
+                logMsg = " keyid in user record: " + keyid.toString();
                 CMS.debug(method + logMsg);
-                continue;
+                if ((getExternalRegRecoverByKeyID() == false) &&
+                        keyid.compareTo(BigInteger.valueOf(0)) != 0) {
+                    logMsg = " Recovering by cert; keyid is irrelevant from user record";
+                    CMS.debug(method + logMsg);
+                }
             }
+
             // recover keys
-            logMsg = " recovering for keyid: " + keyid.toString();
-            CMS.debug(method + logMsg);
             KRARecoverKeyResponse keyResp = null;
             if (kraConn != null) {
                 logMsg = "kraConn not null:" + kraConn;
@@ -1290,7 +1309,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 }
 
                 keyResp = kraRH.recoverKey(cuid, userid, Util.specialURLEncode(channel.getDRMWrappedDesKey()),
-                        null, keyid);
+                        getExternalRegRecoverByKeyID() ? null : b64cert, keyid);
                 if (keyResp == null) {
                     auditInfo = "recovering key not found";
                     auditRecovery(userid, appletInfo, "failure",
@@ -1602,6 +1621,27 @@ public class TPSEnrollProcessor extends TPSProcessor {
         return enabled;
     }
 
+    /**
+     * getExternalRegRecoverByKeyID returns whether externalReg
+     * recovery is recovering by keyID or not; default is by cert
+     */
+    private boolean getExternalRegRecoverByKeyID() {
+        String method = "TPSEnrollProcessor.getExternalRegRecoverByKeyID";
+        IConfigStore configStore = CMS.getConfigStore();
+        boolean recoverByKeyID = false;
+
+        try {
+            String configValue = "externalReg.recover.byKeyID";
+            recoverByKeyID = configStore.getBoolean(configValue, false);
+        } catch (EBaseException e) {
+            // should never get here anyway
+            // but if it does, just take the default "false"
+            CMS.debug(method + " exception, take default: " + e);
+        }
+        CMS.debug(method + ": returning " + recoverByKeyID);
+        return recoverByKeyID;
+    }
+
     private String getRenewConfigKeyType(int keyTypeIndex) throws TPSException {
         String method = "TPSEnrollProcessor.getRenewConfigKeyType";
         IConfigStore configStore = CMS.getConfigStore();
-- 
2.7.4


From 1f33adbef839ce9f93f9e9dff2a0d6ea2638d3ff Mon Sep 17 00:00:00 2001
From: Jack Magne <jmagne@dhcp-16-206.sjc.redhat.com>
Date: Wed, 5 Oct 2016 18:16:35 -0700
Subject: [PATCH 13/14] Fix for: Add ability to disallow TPS to enroll a single
 user on multiple tokens. #1664

This bug was previously not completely fixed where we left a loophole to allow a user to
end up with 2 active tokens. This fix closes that loophole.

Also:

Fix for: Unable to read an encrypted email using renewed tokens. #2483

This fix provides for a new optional renewal based token policy, that
allows the user to retain or recover old encryption certs for that profile,
that get overwritten by the renewal process.

An example is:

RENEW=YES;RENEW_KEEP_OLD_ENC_CERTS=YES

The default is YESk you have to explicitly set it to NO to turn it off.

The second part of the policy is new.

When this is set to "YES", the system will make sure the old enc cert
will remain on the token. If it's missing or "NO", no such attempt will be made.

junk

(cherry picked from commit 1efc001db20afc34b7353f6d2b114593eb761b90)
---
 .../org/dogtagpki/server/tps/TPSTokenPolicy.java   |  8 ++
 .../org/dogtagpki/server/tps/main/PKCS11Obj.java   |  3 +-
 .../server/tps/processor/EnrolledCertsInfo.java    |  4 +
 .../server/tps/processor/TPSEnrollProcessor.java   | 94 +++++++++++++++++++++-
 4 files changed, 107 insertions(+), 2 deletions(-)

diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSTokenPolicy.java b/base/tps/src/org/dogtagpki/server/tps/TPSTokenPolicy.java
index 1a866f7..4d7af48 100644
--- a/base/tps/src/org/dogtagpki/server/tps/TPSTokenPolicy.java
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSTokenPolicy.java
@@ -36,6 +36,7 @@ public class TPSTokenPolicy {
             "RE_ENROLL=YES;RENEW=NO;FORCE_FORMAT=NO;PIN_RESET=NO;RESET_PIN_RESET_TO_NO=NO";
     private boolean re_enroll = true;
     private boolean renew = false;
+    private boolean renew_keep_old_enc_certs = true;
     private boolean force_format = false;
     private boolean pin_reset = true;
     private boolean reset_pin_reset_to_no = false;
@@ -85,6 +86,8 @@ public class TPSTokenPolicy {
                 pin_reset = getBool(policy[1], false);
             else if (policy[0].equalsIgnoreCase("RESET_PIN_RESET_TO_NO"))
                 reset_pin_reset_to_no = getBool(policy[1], false);
+            else if (policy[0].equalsIgnoreCase("RENEW_KEEP_OLD_ENC_CERTS"))
+                renew_keep_old_enc_certs = getBool(policy[1],true);
             //else no change, just take the default;
         }
     }
@@ -150,6 +153,11 @@ public class TPSTokenPolicy {
         return re_enroll;
     }
 
+    public boolean isAllowdRenewSaveOldEncCerts(String cuid) {
+        getUpdatedPolicy(cuid);
+        return renew_keep_old_enc_certs;
+    }
+
     public boolean isAllowdTokenRenew(String cuid) {
         getUpdatedPolicy(cuid);
 
diff --git a/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java b/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java
index 2fc62d7..6af39a7 100644
--- a/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java
+++ b/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java
@@ -655,6 +655,7 @@ public class PKCS11Obj {
             int index = os.getObjectIndex();
 
             if (type == 'C') { //found a certificate
+                CMS.debug("PKS11Obj: getNextFreeCertIdNumber: found cert index "+ index);
                 if (index >= 0 && index < 100) {
                     certTable[index] = 1;
                 }
@@ -669,7 +670,7 @@ public class PKCS11Obj {
             }
         }
 
-        CMS.debug("TPSEnrollProcessor.getNextFreeCertIdNumber: returning free cert id: " + free_cert_id );
+        CMS.debug("PKCS11Obj.getNextFreeCertIdNumber: returning free cert id: " + free_cert_id );
 
         return free_cert_id;
     }
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java b/base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java
index aac1a23..ae9919d 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java
@@ -152,6 +152,10 @@ public class EnrolledCertsInfo {
         certificates.add(x509Cert);
     }
 
+    public void removeCertificate(X509CertImpl x509Cert) {
+        certificates.remove(x509Cert);
+    }
+
     public void setStartProgress(int startP) {
         startProgress = startP;
 
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
index aa23bf0..db9a230 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
@@ -9,6 +9,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.Enumeration;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Random;
@@ -333,7 +334,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
         boolean allowMultiTokens = checkAllowMultiActiveTokensUser(isExternalReg);
 
-        if (isTokenPresent == false && allowMultiTokens == false) {
+        if (allowMultiTokens == false) {
             boolean alreadyHasActiveToken = checkUserAlreadyHasActiveToken(userid);
 
             if (alreadyHasActiveToken == true) {
@@ -1049,8 +1050,10 @@ public class TPSEnrollProcessor extends TPSProcessor {
                         CMS.debug(method + ": There are multiple token entries for user "
                                 + userid);
 
+                        if( checkUserAlreadyHasActiveToken(userid) == false) {
                             isRecover = true;
                             continue; // TODO: or break?
+                        }
                     }
 
                 } else if (tokenRecord.getTokenStatus() == TokenStatus.ACTIVE) {
@@ -1411,10 +1414,14 @@ public class TPSEnrollProcessor extends TPSProcessor {
          */
         Collection<TPSCertRecord> allCerts = tps.tdb.tdbGetCertRecordsByCUID(tokenRecord.getId());
 
+        Collection<TPSCertRecord> oldEncCertsToRecover = new ArrayList<TPSCertRecord>();
+
         certsInfo.setNumCertsToEnroll(keyTypeNum);
 
         CMS.debug(method + ": Number of certs to renew: " + keyTypeNum);
 
+        int numActuallyRenewed = 0;
+
         for (int i = 0; i < keyTypeNum; i++) {
             /*
              * e.g. op.enroll.userKey.renewal.keyType.value.0=signing
@@ -1515,6 +1522,23 @@ public class TPSEnrollProcessor extends TPSProcessor {
                         generateCertificate(certsInfo, channel, aInfo, keyType, TPSEngine.ENROLL_MODES.MODE_RENEWAL,
                                 -1, cEnrollInfo);
 
+                        numActuallyRenewed ++;
+
+
+
+                        if(keyType.equals(TPSEngine.CFG_ENCRYPTION)) {
+                            CMS.debug(method + ": found old encryption cert (just renewed) to attempt to recover back to token, in order to read old emails.");
+                            CMS.debug(method + " adding cert: " + cert);
+                            oldEncCertsToRecover.add(cert);
+
+                        }
+
+                        if(numActuallyRenewed == keyTypeNum) {
+                            CMS.debug(method + " We have already renewed the proper number of certs, bailing from loop.");
+                            status = TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED;
+                            break;
+                        }
+
                         //renewCertificate(cert, certsInfo, channel, aInfo, keyType);
                         status = TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED;
                     } catch (TPSException e) {
@@ -1532,6 +1556,74 @@ public class TPSEnrollProcessor extends TPSProcessor {
             CMS.debug(method + ":" + logMsg);
             throw new TPSException(logMsg + TPSStatus.STATUS_ERROR_RENEWAL_FAILED);
         }
+
+        //Handle recovery of old encryption certs
+
+        //See if policy calls for this feature
+
+        TPSTokenPolicy tokenPolicy = new TPSTokenPolicy(tps);
+
+        boolean recoverOldEncCerts = tokenPolicy.isAllowdRenewSaveOldEncCerts(tokenRecord.getId());
+        CMS.debug(method + " Recover Old Encryption Certs for Renewed Certs: " + recoverOldEncCerts);
+        if (oldEncCertsToRecover.size() > 0 && recoverOldEncCerts == true) {
+            CMS.debug("About to attempt to recover old encryption certs just renewed.");
+
+            Iterator<TPSCertRecord> iterator = oldEncCertsToRecover.iterator();
+
+            // while loop
+            while (iterator.hasNext()) {
+                TPSCertRecord toBeRecovered = iterator.next();
+                String serialToRecover = toBeRecovered.getSerialNumber();
+
+                try {
+
+                    CARetrieveCertResponse certResponse = tps.getEngine().recoverCertificate(toBeRecovered,
+                            serialToRecover, TPSEngine.CFG_ENCRYPTION, getCAConnectorID());
+
+                    String b64cert = certResponse.getCertB64();
+                    CMS.debug("TPSEnrollProcessor.processRecovery: cert blob recovered");
+
+                    KRARecoverKeyResponse keyResponse = tps.getEngine().recoverKey(toBeRecovered.getId(),
+                            toBeRecovered.getUserID(),
+                            channel.getDRMWrappedDesKey(), b64cert, getDRMConnectorID());
+
+
+                    //Try to write recovered cert to token
+
+                    CertEnrollInfo cEnrollInfo = new CertEnrollInfo();
+
+                    cEnrollInfo.setTokenToBeRecovered(tokenRecord);
+                    cEnrollInfo.setRecoveredCertData(certResponse);
+                    cEnrollInfo.setRecoveredKeyData(keyResponse);
+
+
+                    PKCS11Obj pkcs11obj = certsInfo.getPKCS11Obj();
+                    int newCertId = pkcs11obj.getNextFreeCertIdNumber();
+
+                    CMS.debug(method + " newCertId = " + newCertId);
+
+                    CMS.debug(method + "before calling generateCertificate, certsInfo.getCurrentCertIndex() ="
+                            + newCertId);
+                    generateCertificate(certsInfo, channel, aInfo,
+                            "encryption",
+                            TPSEngine.ENROLL_MODES.MODE_RECOVERY,
+                            newCertId, cEnrollInfo);
+
+                    //We don't want this quasi old encryption cert in the official list.
+                    // This cert is on the token ONLY to decrypt old emails after the real cert
+                    // has been renewed. We want to keep the official cert list to contain only the
+                    // legit certs, in order to not confuse other processes such as recovery.
+                    CMS.debug(method + " About to remove old encryption cert recovered from official token db list: ");
+                    certsInfo.removeCertificate(certResponse.getCert());
+
+
+                } catch (TPSException e) {
+                    CMS.debug(method + "Failure to recoverd old encryption certs during renewal operation.");
+
+                }
+            }
+        }
+
         return status;
     }
 
-- 
2.7.4


From 95e00e0b360da299ab78ec4761bdd0181bc71732 Mon Sep 17 00:00:00 2001
From: Jack Magne <jmagne@dhcp-16-206.sjc.redhat.com>
Date: Mon, 10 Oct 2016 15:56:03 -0700
Subject: [PATCH 14/14] Another Fix for: Add ability to disallow TPS to enroll
 a single user on multiple tokens. #1664

We just found out the code doesn't account for if the user has an active token which IS the
token currently being worked on.

(cherry picked from commit 68574756d5afa1c14cd6cc316298aa8f721e7244)
---
 .../src/org/dogtagpki/server/tps/TPSTokendb.java   | 24 +++++++++++++--
 .../server/tps/processor/TPSEnrollProcessor.java   | 35 +++++++++++++++++-----
 2 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java
index e9190d0..729e81e 100644
--- a/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java
+++ b/base/tps/src/org/dogtagpki/server/tps/TPSTokendb.java
@@ -25,6 +25,8 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
+import netscape.security.x509.RevocationReason;
+
 import org.dogtagpki.server.tps.cms.CARemoteRequestHandler;
 import org.dogtagpki.server.tps.cms.CARevokeCertResponse;
 import org.dogtagpki.server.tps.dbs.ActivityDatabase;
@@ -41,8 +43,6 @@ import com.netscape.certsrv.base.IConfigStore;
 import com.netscape.certsrv.dbs.EDBRecordNotFoundException;
 import com.netscape.certsrv.tps.token.TokenStatus;
 
-import netscape.security.x509.RevocationReason;
-
 /*
  * TPSTokendb class offers a collection of tokendb management convenience routines
  */
@@ -171,6 +171,26 @@ public class TPSTokendb {
         }
     }
 
+    public void tdbHasOtherActiveToken(String userid,String cuid)
+            throws Exception {
+         if (userid == null || cuid == null)
+             throw new Exception("TPSTokendb.tdbhasOtherActiveToken: uerid null, or cuid is null");
+
+         ArrayList<TokenRecord> tokens =
+                 tdbFindTokenRecordsByUID(userid);
+         boolean foundActive = false;
+         for (TokenRecord tokenRecord:tokens) {
+             if (tokenRecord.getTokenStatus().equals(TokenStatus.ACTIVE)) {
+
+                 if(!tokenRecord.getId().equalsIgnoreCase(cuid))
+                    foundActive = true;
+             }
+         }
+         if (!foundActive) {
+             throw new Exception("TPSTokendb.tdbhasActiveToken: active token not found");
+         }
+     }
+
     public void tdbAddTokenEntry(TokenRecord tokenRecord, TokenStatus status)
             throws Exception {
         tokenRecord.setTokenStatus(status);
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
index db9a230..c5015cc 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
@@ -15,6 +15,11 @@ import java.util.Map;
 import java.util.Random;
 import java.util.zip.DataFormatException;
 
+import netscape.security.provider.RSAPublicKey;
+//import org.mozilla.jss.pkcs11.PK11ECPublicKey;
+import netscape.security.util.BigInt;
+import netscape.security.x509.X509CertImpl;
+
 import org.dogtagpki.server.tps.TPSSession;
 import org.dogtagpki.server.tps.TPSSubsystem;
 import org.dogtagpki.server.tps.TPSTokenPolicy;
@@ -54,6 +59,8 @@ import org.mozilla.jss.pkcs11.PK11PubKey;
 import org.mozilla.jss.pkcs11.PK11RSAPublicKey;
 import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
 
+import sun.security.pkcs11.wrapper.PKCS11Constants;
+
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.EPropertyNotFound;
@@ -61,12 +68,6 @@ import com.netscape.certsrv.base.IConfigStore;
 import com.netscape.certsrv.tps.token.TokenStatus;
 import com.netscape.cmsutil.util.Utils;
 
-import netscape.security.provider.RSAPublicKey;
-//import org.mozilla.jss.pkcs11.PK11ECPublicKey;
-import netscape.security.util.BigInt;
-import netscape.security.x509.X509CertImpl;
-import sun.security.pkcs11.wrapper.PKCS11Constants;
-
 public class TPSEnrollProcessor extends TPSProcessor {
 
     public TPSEnrollProcessor(TPSSession session) {
@@ -335,7 +336,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
         boolean allowMultiTokens = checkAllowMultiActiveTokensUser(isExternalReg);
 
         if (allowMultiTokens == false) {
-            boolean alreadyHasActiveToken = checkUserAlreadyHasActiveToken(userid);
+            boolean alreadyHasActiveToken = checkUserAlreadyHasOtherActiveToken(userid,cuid);
 
             if (alreadyHasActiveToken == true) {
                 //We don't allow the user to have more than one active token, nip it in the bud right now
@@ -1050,6 +1051,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
                         CMS.debug(method + ": There are multiple token entries for user "
                                 + userid);
 
+                        //We already know the current token is not active
                         if( checkUserAlreadyHasActiveToken(userid) == false) {
                             isRecover = true;
                             continue; // TODO: or break?
@@ -3709,6 +3711,25 @@ public class TPSEnrollProcessor extends TPSProcessor {
         return result;
     }
 
+    private boolean checkUserAlreadyHasOtherActiveToken(String userid,String cuid) {
+        boolean result = false;
+        String method = "TPSEnrollProcessor.checkUserAlreadyHasOtherActiveToken: ";
+
+        TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID);
+        try {
+            tps.tdb.tdbHasOtherActiveToken(userid,cuid);
+            result = true;
+
+        } catch (Exception e) {
+            result = false;
+        }
+
+        CMS.debug(method + " user: " + userid + " has an active token already: not cuid:  " + cuid + " : " + result);
+
+
+        return result;
+    }
+
     private boolean checkAllowMultiActiveTokensUser(boolean isExternalReg) {
         boolean allow = true;
 
-- 
2.7.4