>From 7b1076fae16e7a4141234cd1f3714b37abeed9de Mon Sep 17 00:00:00 2001
From: Christina Fu <cfu@redhat.com>
Date: Thu, 3 Dec 2015 15:00:55 -0800
Subject: [PATCH] Ticket #1375 Provide cert/key retention for externalReg
 Ticket #1514 TPS: Recovered certs on a token has status expired Ticket #1587
 External Registration Recovery only works for 1024 sized keys out of the box
 This patch provides the cert/key retention feature for externalReg. if the
 certsToAdd field contains (serial,ca#) instead of the full (serial, ca#,
 keyId, kra#), then it is expecting the cert/key to be retained from token
 without having to do a full retrieval (recovery). This patch also fixes the
 issues reported in #1514 and #1587 as testing of #13745 is easier with those
 two issues addressed. An issue was found during development where Coolkey
 puts limits on the cert/key ids on the token and make it impossible to inject
 cert ID higher than 4, as it would then result in key ids into two digits.
 This issue will be filed as a separte ticket and addressed separately. Most
 testing will then be conducted.

---
 .../src/com/netscape/cmscore/apps/CMSEngine.java   |  16 +-
 .../server/tps/cms/CARetrieveCertResponse.java     |   7 +-
 .../server/tps/processor/TPSEnrollProcessor.java   | 371 +++++++++++++++++++--
 .../server/tps/processor/TPSProcessor.java         |  34 +-
 4 files changed, 379 insertions(+), 49 deletions(-)

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 1e1f844cd85d444703ae81ee273c14f7b1170834..d050060d909c3cb4608aa3d1379d26de57ab9326 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
@@ -1203,14 +1203,20 @@ public class CMSEngine implements ICMSEngine {
              */
             mSAuditCertNickName = mConfig.getString(PROP_SIGNED_AUDIT_CERT_NICKNAME);
             mManager = CryptoManager.getInstance();
-            org.mozilla.jss.crypto.X509Certificate cert = mManager.findCertByNickname(mSAuditCertNickName);
+            CMS.debug("CMSEngine: about to look for cert for auto-shutdown support:" + mSAuditCertNickName);
+            org.mozilla.jss.crypto.X509Certificate cert = null;
+            try {
+                cert = mManager.findCertByNickname(mSAuditCertNickName);
+            } catch (Exception as) {
+                // can't support auto-shutdown at this point
+                CMS.debug("CMSEngine: cert not found:" + mSAuditCertNickName);
+                CMS.debug("CMSEngine: Exception:" + as.toString());
+            }
             if (cert != null) {
                 CMS.debug("CMSEngine: found cert:" + mSAuditCertNickName);
-            } else {
-                CMS.debug("CMSEngine: cert not found:" + mSAuditCertNickName);
+                mSigningKey = mManager.findPrivKeyByCert(cert);
+                mSigningData = cert.getPublicKey().getEncoded();
             }
-            mSigningKey = mManager.findPrivKeyByCert(cert);
-            mSigningData = cert.getPublicKey().getEncoded();
 
         } catch (Exception e) {
             CMS.debug("CMSEngine: " + e.toString());
diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/CARetrieveCertResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/CARetrieveCertResponse.java
index bf19d72b137a801752dc737cac218d629a734c4d..b9150c456f615cf8f441962bb3fb8fca75558619 100644
--- a/base/tps/src/org/dogtagpki/server/tps/cms/CARetrieveCertResponse.java
+++ b/base/tps/src/org/dogtagpki/server/tps/cms/CARetrieveCertResponse.java
@@ -18,6 +18,7 @@
 
 package org.dogtagpki.server.tps.cms;
 
+import com.netscape.certsrv.apps.CMS;
 import java.security.cert.CertificateExpiredException;
 import java.security.cert.CertificateNotYetValidException;
 import java.util.Hashtable;
@@ -66,7 +67,11 @@ public class CARetrieveCertResponse extends RemoteResponse
         try {
             cert.checkValidity();
             return true;
-        } catch (CertificateExpiredException | CertificateNotYetValidException e) {
+        } catch (CertificateExpiredException e) {
+            CMS.debug("CARetrieveCertResponse.isCertValid: exception thrown: " + e.toString());
+            return false;
+        } catch (CertificateNotYetValidException e) {
+            CMS.debug("CARetrieveCertResponse.isCertValid: exception thrown: " + e.toString());
             return false;
         }
     }
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 2376ea76caa5f086ed349849bfae6adafa9d819e..b225323c06c56e4966d7d54bf787574923b56e7f 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
@@ -4,6 +4,7 @@ import java.io.IOException;
 import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.Enumeration;
@@ -12,11 +13,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;
@@ -36,6 +32,7 @@ import org.dogtagpki.server.tps.dbs.TPSCertRecord;
 import org.dogtagpki.server.tps.dbs.TokenRecord;
 import org.dogtagpki.server.tps.engine.TPSEngine;
 import org.dogtagpki.server.tps.engine.TPSEngine.ENROLL_MODES;
+import org.dogtagpki.server.tps.main.AttributeSpec;
 import org.dogtagpki.server.tps.main.ExternalRegAttrs;
 import org.dogtagpki.server.tps.main.ExternalRegCertToRecover;
 import org.dogtagpki.server.tps.main.ExternalRegCertToRecover.CertStatus;
@@ -62,6 +59,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) {
@@ -400,10 +403,6 @@ public class TPSEnrollProcessor extends TPSProcessor {
         certsInfo.setStartProgress(15);
         certsInfo.setEndProgress(90);
 
-        // TODO:
-        // remove the not-to-be-retained cert objects from the pkcs11obj
-        // cleanObjectListBeforeExternalRecovery(certsInfo);
-
         boolean renewed = false;
         boolean recovered = false;
 
@@ -420,13 +419,11 @@ public class TPSEnrollProcessor extends TPSProcessor {
         else if (status == TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED) {
             statusString = "Recovery processed";
             recovered = true;
-            //TODO:
-            //tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(), auditMsg, "success");
+            tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(), auditMsg, "success");
         } else if (status == TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED) {
             statusString = "Renewal processed";
             renewed = true;
-            //TODO:
-            //tps.tdb.tdbActivity(ActivityDatabase.OP_RENEWAL, tokenRecord, session.getIpAddress(), auditMsg, "success");
+            tps.tdb.tdbActivity(ActivityDatabase.OP_RENEWAL, tokenRecord, session.getIpAddress(), auditMsg, "success");
         } else {
             auditMsg = " generateCertsAfterRenewalRecoveryPolicy returned status=" + status;
             CMS.debug(method + auditMsg);
@@ -469,10 +466,10 @@ public class TPSEnrollProcessor extends TPSProcessor {
                         CMS.debug(method + " after externalRegRecover status is:" + recoverStatus);
                         if (recoverStatus == TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED) {
                             recovered = true;
-                            //TODO:
-                            //tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(), auditMsg, "success");
+                            auditMsg = method + " externalRegRecover returned: recoverStatus=" + recoverStatus;
+                            tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(), auditMsg, "success");
                         } else {
-                            auditMsg = method + " externalRegRecover: recoverStatus=" + recoverStatus;
+                            auditMsg = method + " externalRegRecover returned: recoverStatus=" + recoverStatus;
                             CMS.debug(auditMsg);
                             tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(),
                                     auditMsg,
@@ -538,6 +535,9 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
         statusUpdate(92, "PROGRESS_WRITE_OBJECTS");
 
+        // Purge the object list of certs that have not been explicilty saved from deletion
+        cleanObjectListBeforeExternalRecovery(certsInfo);
+
         writeFinalPKCS11ObjectToToken(pkcs11objx, appletInfo, channel);
         statusUpdate(98, "PROGRESS_ISSUER_INFO");
         writeIssuerInfoToToken(channel,appletInfo);
@@ -582,6 +582,258 @@ public class TPSEnrollProcessor extends TPSProcessor {
         statusUpdate(100, "PROGRESS_DONE_ENROLLMENT");
     }
 
+
+    /*
+     * cleanObjectListBeforeExternalRecovery
+     *  - in the ExternalReg case, certs not to be retained are cleaned off the pkcs11obj before further processing
+     *  - certs to be retained are represented in the certsToAdd attribute as <serialNum, caConn>  without the keyId and kraConn
+     */
+    private TPSStatus cleanObjectListBeforeExternalRecovery(EnrolledCertsInfo certsInfo) {
+        TPSStatus status = TPSStatus.STATUS_NO_ERROR;
+        final String method = "TPSEnrollProcessor.cleanObjectListBeforeExternalRecovery :";
+        final int MAX_CERTS = 30;
+        IConfigStore configStore = CMS.getConfigStore();
+
+        /*
+         * Arrays that hold simple indexes of certsToDelete and certsToSave.
+         * certsToDelete is a list of certs NOT in the recovery list.
+         * certsToSave is a list of certs to spare from deletion because they
+         * were enrolled by the regular token profile.
+         */
+        int certsToDelete[] = new int[MAX_CERTS];
+        int certsToSave[] = new int[MAX_CERTS];
+        int numCertsToDelete = 0;
+        int numCertsToSave = 0;
+
+        CMS.debug(method + ": begins");
+        if (certsInfo == null) {
+            CMS.debug(method + "certsInfo cannot be null");
+            return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
+        }
+        PKCS11Obj pkcs11obj = certsInfo.getPKCS11Obj();
+        if (pkcs11obj == null) {
+            CMS.debug(method + "no pkcs11obj to work with");
+            return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
+        }
+        ExternalRegAttrs erAttrs = session.getExternalRegAttrs();
+        if (session == null || erAttrs == null ||
+                erAttrs.getCertsToRecover() == null) {
+            CMS.debug(method + "no externalReg attrs to work with");
+            return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
+        }
+
+        int count = erAttrs.getCertsToRecoverCount();
+        CMS.debug(method + "number of certs to recover=" + count);
+        if (count == 0) {
+            CMS.debug(method + " nothing to process. Returning status: "
+                + status);
+            return status;
+        }
+        String tokenType = erAttrs.getTokenType();
+        if (tokenType == null) {
+            CMS.debug(method + " erAttrs tokenType null. Returning status: "
+                    + status);
+            return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
+        }
+
+        /*
+         * Now let's try to save the just freshly enrolled certificates
+         * based on regular profile from deletion.
+         */
+        String configName = "op.enroll." +
+                tokenType + "." +
+                "keyGen.keyType.num";
+        int keyTypeNum = 0;
+        try {
+            CMS.debug(method + " getting config : " + configName);
+            Integer keyTypeNumI = configStore.getInteger(configName);
+            keyTypeNum = keyTypeNumI.intValue();
+        } catch (Exception e) {
+            //return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
+            // some externalReg profiles are for "recovering only"
+            keyTypeNum = 0;
+        }
+        CMS.debug(method + " config keyTypeNum: " + keyTypeNum);
+
+        if (keyTypeNum > 0) {
+            int index = -1;
+            for (int i=0; i < keyTypeNum; i++) {
+                configName = "op.enroll." +
+                    tokenType + "." +
+                    "keyGen.keyType.value." + i;
+                String keyTypeValue;
+                try {
+                    CMS.debug(method + " getting config : " + configName);
+                    keyTypeValue = configStore.getString(configName);
+                } catch (EPropertyNotFound e) {
+                    e.printStackTrace();
+                    return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
+                } catch (EBaseException e) {
+                    e.printStackTrace();
+                    return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
+                }
+                CMS.debug(method + " config keyTypeValue: " + keyTypeValue);
+                String keyTypePrefix = "op.enroll." +
+                    tokenType + ".keyGen." + keyTypeValue;
+                CMS.debug(method + " keyTypePrefix is: " + keyTypePrefix);
+
+                configName = keyTypePrefix + ".certId";
+                String certId;
+                try {
+                    CMS.debug(method + " getting config : " + configName);
+                    certId = configStore.getString(configName);
+                } catch (EPropertyNotFound e) {
+                    e.printStackTrace();
+                    return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
+                } catch (EBaseException e) {
+                    e.printStackTrace();
+                    return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
+                }
+                CMS.debug(method + " certId is: " + certId);
+                if (certId != null && certId.length() >1) {
+                    index = Character.getNumericValue(certId.charAt(1));
+                }
+
+                if (index >=0 && numCertsToSave < MAX_CERTS) {
+                    /* Set an entry in the list in order to save from subsequent deletion. */
+                    CMS.debug(method + " saving object index to certsToSave: " + index);
+                    certsToSave[numCertsToSave++] = index;
+                }
+            }
+        }
+
+        int num_objs = pkcs11obj.getObjectSpecCount();
+        CMS.debug(method + " pkcs11obj num_objs =" + num_objs);
+        char[] bytesA = new char[3];
+
+        /*
+         * Go through the object spec list and remove stuff we have marked
+         * for deletion. Remove Cert and all associated objects of that cert.
+         */
+        for (int i = 0; i< num_objs; i++) {
+            ObjectSpec os = pkcs11obj.getObjectSpec(i);
+            long oid = os.getObjectID();
+            bytesA[0] = (char)((oid >> 24) & 0xff);
+            bytesA[1] = (char)((oid >> 16) & 0xff);
+            bytesA[2] = '\0';
+
+            if ( bytesA[0] == 'C' )   {    /* Is this a cert object ? */
+                for (int j = 0 ; j <  os.getAttributeSpecCount() ; j++ ) {
+                    AttributeSpec as = os.getAttributeSpec(j);
+                    if (as.getAttributeID() == PKCS11Constants.CKA_VALUE) {
+                        if (as.getType() == (byte) 0) {
+                            TPSBuffer certBuff = as.getValue();
+                            X509CertImpl xCert = null;
+                            try {
+                                xCert = new X509CertImpl(certBuff.toBytesArray());
+                            } catch (CertificateException e) {
+                                CMS.debug(method + e);
+                                e.printStackTrace();
+                            }
+                            boolean present = isInCertsToRecoverList(xCert);
+                            int certId = Character.getNumericValue(bytesA[1]);
+                            if ( present == false) {
+                                CMS.debug(method + " cert not found in recovery list, possible deletion... id:" + certId);
+                                /*
+                                 * Now check the certsToSave list to see if this cert is protected
+                                 */
+                                boolean protect = false;
+                                for(int p = 0 ; p < numCertsToSave; p++) {
+                                    if( certsToSave[p] == certId)  {
+                                        protect = true;
+                                        break;
+                                    }
+                                }
+                                CMS.debug(method + " protect cert " + certId +
+                                    ": " + protect);
+                                /*
+                                 * Delete this cert if it is NOT protected by
+                                 * the certs generated by the profile enrollment.
+                                 */
+                                if((numCertsToDelete < MAX_CERTS) &&
+                                    (protect == false )) {
+                                    /*
+                                     * TODO:
+                                     * do we need ExternalRegCertToDelete?
+                                     */
+                                    certsToDelete[numCertsToDelete++] = certId;
+                                }
+                            } else {
+                                CMS.debug(method + " cert found in recovery list, to be retained. id:" + certId);
+                                // add retained cert so tokendb will reflect
+                                certsInfo.addCertificate(xCert);
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        /*
+         * Now rifle through the certsToDeleteList and remove those that
+         *  need to be deleted
+         */
+        for(int k = 0 ; k <  numCertsToDelete ; k ++ ) {
+            CMS.debug(method + "cert to delete: " + certsToDelete[k]);
+            removeCertFromObjectList(certsToDelete[k], pkcs11obj);
+        }
+
+        CMS.debug(method + " ends. Returning status: "
+                + status);
+        return status;
+    }
+
+    /*
+     * Remove a certificate from the Object Spec List based on Cert index ,
+     *     C(1), C(2), etc
+     */
+    void removeCertFromObjectList(int cIndex, PKCS11Obj pkcs11obj) {
+        String method = "TPSEnrollProcessor.removeCertFromObjectList: ";
+        if ( pkcs11obj == null ) {
+            CMS.debug(method + " pkcs11obj null");
+            return;
+        }
+
+        CMS.debug(method + " index of cert to delete is: " + cIndex);
+
+        int C = cIndex;
+        int c = cIndex;
+        int k1 = 2 * cIndex;
+        int k2 = 2 * cIndex + 1;
+
+        // loop through all objects on token
+        int index = 0;
+        for (int i = 0; i <  pkcs11obj.getObjectSpecCount(); i++) {
+            ObjectSpec spec = pkcs11obj.getObjectSpec(i);
+            long objectID = spec.getObjectID();
+            char c1 = (char) ((objectID >> 24) & 0xff);
+            char cont_id = (char) ((objectID >> 16) & 0xff);
+
+            /* locate all certificate objects */
+            index = Character.getNumericValue(cont_id);
+            if (c1 == 'c' || c1 == 'C') {
+                if (index == C || index == c ) {
+                    CMS.debug(method + " found index:"+ index +
+                       "; Removing cert Object");
+                    pkcs11obj.removeObjectSpec(i);
+                    i--;
+                }
+            }
+
+            if (c1 == 'k') {
+                if (index == k1 || index == k2) {
+                    CMS.debug(method + " found index:"+ index +
+                       "; Removing key Object");
+                    pkcs11obj.removeObjectSpec(i);
+                    i--;
+                }
+            }
+        }
+
+    }
+
+
     private void writeFinalPKCS11ObjectToToken(PKCS11Obj pkcs11objx, AppletInfo ainfo, SecureChannel channel)
             throws TPSException, IOException {
         if (pkcs11objx == null || ainfo == null || channel == null) {
@@ -712,10 +964,38 @@ public class TPSEnrollProcessor extends TPSProcessor {
         return pkcs11objx;
     }
 
+    /*
+     *  Does given cert exist in the ExternalRegAttrs CertsToRecoverList
+     *  We need to know if this cert is to be retained for an ExternalReg Recovery operation.
+     *  If cert is in the list, it will be retained and not erased, otherwise it will go away.
+     */
+    private boolean isInCertsToRecoverList(X509CertImpl xCert) {
+        final String method = "TPSEnrollProcessor.isInCertsToRecoverList :";
+        boolean foundObj = false;
+        ExternalRegAttrs erAttrs = session.getExternalRegAttrs();
+        ArrayList<ExternalRegCertToRecover> erCertsToRecover =
+                erAttrs.getCertsToRecover();
+        CMS.debug(method + " begins checking for cert, serial:" + xCert.getSerialNumber());
 
-    private boolean isInCertsToRetainList(X509CertImpl xCert, ArrayList<ExternalRegCertToRecover> toBeRetained) {
-        // TODO Auto-generated method stub
-        return false;
+        int count = erAttrs.getCertsToRecoverCount();
+        if (count <= 0) {
+            CMS.debug(method + "ends. recover list empty. returning: " + foundObj);
+            return foundObj;
+        }
+
+        for (ExternalRegCertToRecover certToRecover : erCertsToRecover) {
+            if (certToRecover == null) {
+                continue;
+            }
+            // TODO: could enhance the comparison to include more than serials
+            if (xCert.getSerialNumber().compareTo(certToRecover.getSerial()) == 0) {
+                foundObj = true;
+                break;
+            }
+        }
+
+        CMS.debug(method + " ends. returning: " + foundObj);
+        return foundObj;
     }
 
     /*
@@ -958,6 +1238,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
             }
             auditMsg = "ExternalReg cert record: serial=" +
                     serial.toString();
+            CMS.debug(method + auditMsg);
 
             // recover cert
             CARemoteRequestHandler caRH = new CARemoteRequestHandler(caConn);
@@ -971,7 +1252,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
             String retCertB64 = certResp.getCertB64();
             byte[] cert_bytes;
             if (retCertB64 != null) {
-                CMS.debug(method + "recovered:  retCertB64: " + retCertB64);
+                //CMS.debug(method + "recovered:  retCertB64: " + retCertB64);
+                CMS.debug(method + "recovered retCertB64");
                 cert_bytes = Utils.base64decode(retCertB64);
 
                 TPSBuffer cert_bytes_buf = new TPSBuffer(cert_bytes);
@@ -997,14 +1279,25 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 erCert.setCertStatus(CertStatus.ACTIVE);
 
                 // check if expired or not yet valid
-                if (certResp.isCertValid()) {
+                if (!certResp.isCertValid()) {
                     auditMsg = "cert expired or not yet valid";
                     CMS.debug(auditMsg);
                     erCert.setCertStatus(CertStatus.EXPIRED); // it could be not yet valid
                 }
             }
 
+            if (keyid == null) {
+                auditMsg = " no keyid; skip key recovery; continue";
+                CMS.debug(method + auditMsg);
+                continue;
+            } else if ( keyid.compareTo(BigInteger.valueOf(0))==0) {
+                auditMsg = " keyid is 0; invalid; skip key recovery; continue";
+                CMS.debug(method + auditMsg);
+                continue;
+            }
             // recover keys
+            auditMsg = " recovering for keyid: " + keyid.toString();
+            CMS.debug(method + auditMsg);
             KRARecoverKeyResponse keyResp = null;
             if (kraConn != null) {
                 auditMsg = "kraConn not null:" + kraConn;
@@ -1019,7 +1312,10 @@ public class TPSEnrollProcessor extends TPSProcessor {
                     CMS.debug(method + auditMsg);
                 }
 
-                // if keyid > 0, recovder by keyid
+
+                keyResp = kraRH.recoverKey(cuid, userid, Util.specialURLEncode(channel.getDRMWrappedDesKey()),
+                            null, keyid);
+                /* if keyid > 0, recovder by keyid
                 if (keyid != null && keyid.compareTo(BigInteger.valueOf(0))==1) {
                     auditMsg = "recovering by keyid: "+ keyid.toString();
                     CMS.debug(method + auditMsg);
@@ -1033,6 +1329,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
                     keyResp = kraRH.recoverKey(cuid, userid, Util.specialURLEncode(channel.getDRMWrappedDesKey()),
                             Util.uriEncode(retCertB64));
                 }
+                */
                 if (keyResp == null) {
                     auditMsg = "recovering key not found";
                     CMS.debug(method + auditMsg);
@@ -1040,18 +1337,19 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 }
             }
 
-
-
             CertEnrollInfo cEnrollInfo = new CertEnrollInfo();
-
             cEnrollInfo.setTokenToBeRecovered(tokenRecord);
             cEnrollInfo.setRecoveredCertData(certResp);
+
             cEnrollInfo.setRecoveredKeyData(keyResp);
 
+            CMS.debug(method + "before calling generateCertificate, certsInfo.getCurrentCertIndex() =" + certsInfo.getCurrentCertIndex());
+            PKCS11Obj pkcs11obj = certsInfo.getPKCS11Obj();
+            int newCertId = pkcs11obj.getNextFreeCertIdNumber();
             generateCertificate(certsInfo, channel, appletInfo,
                     "encryption",
                     TPSEngine.ENROLL_MODES.MODE_RECOVERY,
-                    certsInfo.getCurrentCertIndex() + 1, cEnrollInfo);
+                    newCertId, cEnrollInfo);
 
             CMS.debug(method + "after generateCertificate() with MODE_RECOVERY");
         }
@@ -1948,21 +2246,30 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
                 publicKeyStr = keyResp.getPublicKey();
                 public_key_blob = new TPSBuffer(Utils.base64decode(publicKeyStr));
-
             }
 
             try {
                 parsedPK11PubKey = PK11RSAPublicKey.fromSPKI(public_key_blob.toBytesArray());
+                parsedPubKey_ba = parsedPK11PubKey.getEncoded();
 
+                if (isRecovery == true) {
+                    // reset to accurate keysize
+                    RSAPublicKey rsaKey = new RSAPublicKey(parsedPubKey_ba);
+                    cEnrollInfo.setKeySize(rsaKey.getKeySize());
+                    CMS.debug("TPSEnrollProcessor.enrollOneCertificate: recovery reset keysize to:" + rsaKey.getKeySize());
+                }
             } catch (InvalidKeyFormatException e) {
-                CMS.debug("TPSEnrollProcessor.enrollOneCertificate, can't create public key object from server side key generated public key blob!");
-                throw new TPSException(
-                        "TPSEnrollProcessor.enrollOneCertificate, can't create public key object from server side key generated public key blob!",
+                String msg = "TPSEnrollProcessor.enrollOneCertificate, can't create public key object from server side key generated public key blob! " + e.toString();
+                CMS.debug(msg);
+                throw new TPSException( msg,
+                        TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
+            } catch (InvalidKeyException e) {
+                String msg = "TPSEnrollProcessor.enrollOneCertificate, can't create public key object from server side key generated public key blob! " + e.toString();
+                CMS.debug(msg);
+                throw new TPSException( msg,
                         TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
             }
 
-            parsedPubKey_ba = parsedPK11PubKey.getEncoded();
-
         } else if (isRenewal) {
 
             CMS.debug("TPSEnrollProcessor: We are in renewal mode, no work to do with the keys, in renewal the keys remain on the token.");
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
index a9355b9bf58037650d3e1fbc28bbfe8fc74115f0..6ea8fa2bad7894e65ed3fa5988b6610fb37f2b9d 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
@@ -33,8 +33,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import netscape.security.x509.RevocationReason;
-
 import org.dogtagpki.server.tps.TPSSession;
 import org.dogtagpki.server.tps.TPSSubsystem;
 import org.dogtagpki.server.tps.authentication.AuthUIParameter;
@@ -93,6 +91,8 @@ import com.netscape.certsrv.common.Constants;
 import com.netscape.certsrv.tps.token.TokenStatus;
 import com.netscape.symkey.SessionKey;
 
+import netscape.security.x509.RevocationReason;
+
 public class TPSProcessor {
 
     public static final int RESULT_NO_ERROR = 0;
@@ -1669,20 +1669,20 @@ public class TPSProcessor {
                         new ExternalRegCertToRecover();
                 int i = 0;
                 for (i = 0; i < items.length; i++) {
-                    if (i == 0)
+                    if (i == 0) {
+                        CMS.debug(method + "setting serial: " + items[i]);
                         erCert.setSerial(new BigInteger(items[i]));
-                    else if (i == 1)
+                    } else if (i == 1)
                         erCert.setCaConn(items[i]);
-                    else if (i == 2)
+                    else if (i == 2) {
+                        CMS.debug(method + "setting keyid: " + items[i]);
                         erCert.setKeyid(new BigInteger(items[i]));
-                    else if (i == 3)
+                    } else if (i == 3)
                         erCert.setKraConn(items[i]);
                 }
-                /* TODO: for phase 3, retenable certs/keys
                 if (i<3) {
                     erCert.setIsRetainable(true);
                 }
-                */
                 erAttrs.addCertToRecover(erCert);
             }
         } else {
@@ -1877,6 +1877,21 @@ public class TPSProcessor {
                     throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_MISCONFIGURATION);
                 }
                 session.setExternalRegAttrs(erAttrs);
+                /* test
+                ArrayList<ExternalRegCertToRecover> erCertsToRecover =
+                session.getExternalRegAttrs().getCertsToRecover();
+
+                for (ExternalRegCertToRecover erCert : erCertsToRecover) {
+                    BigInteger serial = erCert.getSerial();
+                    CMS.debug("In TPSProcessor.format: " + "serial: " + serial.toString());
+                    BigInteger keyid = erCert.getKeyid();
+                    if (keyid != null)
+                        CMS.debug("In TPSProcessor.format: " + "keyid: " + keyid.toString());
+                    else
+                        CMS.debug("In TPSProcessor.format: " + "no keyid");
+                }
+                test ends */
+
                 setSelectedTokenType(erAttrs.getTokenType());
             }
             CMS.debug("In TPSProcessor.format: isExternalReg: about to process keySet resolver");
@@ -2057,9 +2072,6 @@ public class TPSProcessor {
         tokenRecord.setStatus("uninitialized");
         try {
             tps.tdb.tdbUpdateTokenEntry(tokenRecord);
-            String successMsg = "update token success";
-            tps.tdb.tdbActivity(ActivityDatabase.OP_FORMAT, tokenRecord, session.getIpAddress(), successMsg,
-                    "success");
         } catch (Exception e) {
             String failMsg = "update token failure";
             auditMsg = failMsg + ":" + e.toString();
-- 
2.4.3

