From 911d7fde7a49d2f854f391ea95771b4000c8535e Mon Sep 17 00:00:00 2001
From: Jack Magne <jmagne@localhost.localdomain>
Date: Fri, 22 Jan 2016 18:03:36 -0800
Subject: [PATCH] Allow cert and key indexes > 9.

Ticket: Ticket #1734 : TPS issue with overflowing PKCS#11 cert index numbers

This patch contains the following:

1. Fixes in TPS to allow the server to set and read muscle object ID's that are greater than 9.

The id is stored as a single ASCII byte in the object id. Previous libcoolkey patches exist to now support numbers
larger than 9, by the following:

0-9 is represented by the ascii chars for 0 through 9,.
10 - 35 represented by the ascii chars for 'A' through 'Z'.
36 - 61 represented by the ascii chars for 'a' through 'z'.

Once coolkey is updated it will be able to read these id's.

TPS with this patch will be able to both read number 0 - 62 and to set them when creating pkcs#11 objects to be stored on the token.

When the proper libcoolkey is installed, the coolkey driver will be able to read certs and keys with id's > 9. Thus, for instance a cert with an id of C6, with keys of k12, and k13, will be supported and viewable in the Firefox cert viewer. Also the certs will be usable for operations.

2. A fix to the routine that finds a free id number to assign to a soon to be recovered cert will now have the ability to find unused slots instead of just inrementing one over the highest currently used index.

3. Made a couple of minor cleanup fixes to externalReg functionality discovered during testing of this feature.
---
 .../org/dogtagpki/server/tps/main/ObjectSpec.java  | 208 +++++++++++++++++++-
 .../org/dogtagpki/server/tps/main/PKCS11Obj.java   |  92 ++++-----
 .../server/tps/processor/CertEnrollInfo.java       |   9 +-
 .../server/tps/processor/EnrolledCertsInfo.java    |   7 +
 .../server/tps/processor/TPSEnrollProcessor.java   | 213 ++++++++++++---------
 5 files changed, 380 insertions(+), 149 deletions(-)

diff --git a/base/tps/src/org/dogtagpki/server/tps/main/ObjectSpec.java b/base/tps/src/org/dogtagpki/server/tps/main/ObjectSpec.java
index a8dbdb1..00cc447 100644
--- a/base/tps/src/org/dogtagpki/server/tps/main/ObjectSpec.java
+++ b/base/tps/src/org/dogtagpki/server/tps/main/ObjectSpec.java
@@ -236,7 +236,8 @@ public class ObjectSpec {
         // down to the cert's id, the code below changes both "4" and "5" back
         // to "2".
 
-        int val = (objectID.charAt(1) - '0');
+        int val = objectSpec.getObjectIndex();
+
         switch (objectID.charAt(0)) {
         case 'c':
 
@@ -290,7 +291,7 @@ public class ObjectSpec {
 
         fixedAttrs = 0x00000080; /* CKA_TOKEN */
         xclass = (int) PKCS11Constants.CKO_CERTIFICATE;
-        id = objectID.charAt(1) - '0';
+        id = objectSpec.getObjectIndex();
 
         objectSpec.setFixedAttributes(fixedAttrs | (xclass << 4) | id);
     }
@@ -453,4 +454,207 @@ public class ObjectSpec {
         return data;
     }
 
+    public int getObjectIndex() {
+        return ObjectSpec.getObjectIndex(this.objectID);
+    }
+
+    public static int getObjectIndex(long objectID) {
+        char char_index = (char) ((objectID >> 16) & 0xff);
+        int index = -1;
+
+        if (char_index >= '0' && char_index <= '9') {
+            index = char_index - '0';
+        }
+        if (char_index >= 'A' && char_index <= 'Z') {
+            index = char_index - 'A' + 10;
+        }
+        if (char_index >= 'a' && char_index <= 'z') {
+            index = char_index - 'a' + 26;
+        }
+
+        if ( index == -1) {
+            index = 0x0100 + char_index;
+        }
+
+        return index;
+    }
+
+    public char getObjectType() {
+        return ObjectSpec.getObjectType(objectID);
+    }
+
+    public static char getObjectType(long objectID) {
+        char type = '0';
+        type = (char) ((objectID >> 24) & 0xff);
+        return type;
+    }
+
+    public static char getObjectIndexChar(long objectID) {
+        char char_index = (char) ((objectID >> 16) & 0xff);
+        return char_index;
+    }
+
+    public static long createObjectID(char type, int index) {
+        long id = 0;
+
+        if (type != 'c' && type != 'C' && type != 'k') {
+            return 0;
+        }
+
+        if (index > 61 || index < 0) {
+            return 0;
+        }
+
+        char indexChar = '0';
+
+        long l1 = (type & 0xff) << 24;
+
+        if (index >= 0 && index <= 9) {
+            indexChar = (char) (index + '0');
+        }
+
+        // Handle 10 - 35 : A - Z
+
+        if (index >= 10 && index <= 35) {
+            indexChar = (char) (index - 10 + 'A');
+        }
+
+        // Handle 36 - 61 : a - z
+
+        if (index >= 36 && index <= 61) {
+            indexChar = (char) (index - 26 + 'a');
+        }
+
+        long l2 = (indexChar & 0xff) << 16;
+
+        id = l1 + l2;
+
+        return id;
+    }
+
+    public String getAttrId() {
+        return ObjectSpec.getAttrId(this.objectID);
+    }
+
+    public static String getAttrId(long objectID) {
+        String attrId = "";
+
+        attrId = ObjectSpec.getObjectType(objectID) + String.valueOf(ObjectSpec.getObjectIndex(objectID));
+        return attrId;
+    }
+
+    public static char getObjectType(String attrId) {
+
+        long obj = ObjectSpec.createObjectID(attrId);
+        return ObjectSpec.getObjectType(obj);
+    }
+
+    public static int getObjectIndex(String attrId) {
+        long obj = ObjectSpec.createObjectID(attrId);
+        return ObjectSpec.getObjectIndex(obj);
+    }
+
+    public static long createObjectID(String attrId) {
+        long id = 0;
+
+        if (attrId == null) {
+            return 0;
+        }
+
+        // Allow ex: c0 - c9, or cA - cZ or  ca - cz
+        // C or c or k allowed for types.
+
+        int len = attrId.length();
+
+        if (len < 2 || len > 3) {
+            return 0;
+        }
+
+        String indexStr = attrId.substring(1);
+
+        char typeCh = attrId.charAt(0);
+        int index = 0;
+
+        try
+        {
+            index = Integer.parseInt(indexStr.trim());
+        } catch (NumberFormatException nfe)
+        {
+            CMS.debug("ObjectSpec.createObjectID(Str) bad object index string.");
+            return 0;
+        }
+
+        id = ObjectSpec.createObjectID(typeCh, index);
+        return id;
+    }
+
+    public static void main(String[] args) {
+        String attr1 = "k0";
+        String attr2 = "k10";
+        String attr3 = "c27";
+        String attr4 = "C37";
+
+        long objectID1 = ObjectSpec.createObjectID(attr1);
+        long objectID2 = ObjectSpec.createObjectID(attr2);
+        long objectID3 = ObjectSpec.createObjectID(attr3);
+        long objectID4 = ObjectSpec.createObjectID(attr4);
+
+        System.out.println("objectID1: " + objectID1);
+        System.out.println("objectID2: " + objectID2);
+        System.out.println("objectID3: " + objectID3);
+        System.out.println("objectID4: " + objectID4);
+
+        System.out.println("\n");
+
+        System.out.println("attr1 values: " + attr1 + "\n");
+
+        char type1 = ObjectSpec.getObjectType(objectID1);
+        System.out.println("type1: " + type1);
+
+        int index1 = ObjectSpec.getObjectIndex(objectID1);
+        System.out.println("index1: " + index1);
+
+        System.out.println("index1 getAttrId: " + ObjectSpec.getAttrId(objectID1));
+
+        System.out.println("\n");
+
+        System.out.println("attr2 values: " + attr2 + "\n");
+
+        char type2 = ObjectSpec.getObjectType(objectID2);
+        System.out.println("type2: " + type2);
+
+        int index2 = ObjectSpec.getObjectIndex(objectID2);
+        System.out.println("index2: " + index2);
+        System.out.println("index2 getAttrId: " + ObjectSpec.getAttrId(objectID2));
+        System.out.println("\n");
+
+        System.out.println("attr3 values: " + attr3 + "\n");
+
+        char type3 = ObjectSpec.getObjectType(objectID3);
+        System.out.println("type3: " + type3);
+
+        int index3 = ObjectSpec.getObjectIndex(objectID3);
+        System.out.println("index3: " + index3);
+        System.out.println("index3 getAttrId: " + ObjectSpec.getAttrId(objectID3));
+        System.out.println("\n");
+
+        System.out.println("attr4 values: " + attr4 + "\n");
+
+        char type4 = ObjectSpec.getObjectType(objectID4);
+        System.out.println("type4: " + type4);
+
+        int index4 = ObjectSpec.getObjectIndex(objectID4);
+        System.out.println("index4: " + index4);
+        System.out.println("index4 getAttrId: " + ObjectSpec.getAttrId(objectID4));
+        System.out.println("\n");
+
+        long test_id = 1798307840;
+
+        char testType = ObjectSpec.getObjectType(test_id);
+        int testIndex = ObjectSpec.getObjectIndex(test_id);
+
+        System.out.println("test_id: " + test_id + " testType: " + testType + " testIndex: " + testIndex);
+        System.out.println("\n");
+    }
+
 }
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 40e7951..a878410 100644
--- a/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java
+++ b/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java
@@ -3,7 +3,6 @@ package org.dogtagpki.server.tps.main;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.zip.DataFormatException;
 import java.util.zip.Deflater;
 import java.util.zip.Inflater;
@@ -103,29 +102,22 @@ public class PKCS11Obj {
             nread = objSpec.getParseReadSize();
             o.addObjectSpec(objSpec);
 
-            long oid = objSpec.getObjectID();
-            char[] b1 = new char[2];
-
-            b1[0] = (char) ((oid >> 24) & 0xff);
-            b1[1] = (char) ((oid >> 16) & 0xff);
+            char type = objSpec.getObjectType();
+            int index = objSpec.getObjectIndex();
 
-            CMS.debug("PKCS11Obj.parse " + "About to parse = " + b1[0] + ":" + b1[1]);
-            System.out.println("PKCS11Obj.parse " + "About to parse = " + b1[0] + ":" + b1[1]);
+            CMS.debug("PKCS11Obj.parse " + "About to parse = " + type + ":" + index);
+            System.out.println("PKCS11Obj.parse " + "About to parse = " + type + ":" + index);
 
             // add corresponding 'C' object for 'c'
-            if (b1[0] == 'c') {
+            if (type == 'c') {
                 for (int j = 0; j < objSpec.getAttributeSpecCount(); j++) {
                     AttributeSpec as = objSpec.getAttributeSpec(j);
                     if (as.getAttributeID() == PKCS11Constants.CKA_VALUE) {
                         if (as.getType() == (byte) 0) {
                             TPSBuffer cert = as.getValue();
 
-                            long l1 = 0x43; // 'C'
-                            long l2 = b1[1];
-
-                            l1 = (l1 & 0xff) << 24;
-                            l2 = (l2 & 0xff) << 16;
-                            long certid = l1 + l2;
+                            long certid = ObjectSpec.createObjectID('C', index);
+                            System.out.println("certid : " + certid);
 
                             ObjectSpec certSpec =
                                     ObjectSpec.parseFromTokenData(
@@ -148,23 +140,14 @@ public class PKCS11Obj {
     public boolean doesCertIdExist(String certId) {
 
         boolean foundObj = false;
-        char[] certChars = certId.toCharArray();
-
         for (ObjectSpec objSpec : objectSpecs) {
 
-            long oid = objSpec.getObjectID();
-
-            char[] b1 = new char[2];
+            String attrId = objSpec.getAttrId();
 
-            b1[0] = (char) ((oid >> 24) & 0xff);
-            b1[1] = (char) ((oid >> 16) & 0xff);
-
-            if (Arrays.equals(b1, certChars)) {
+            if (attrId != null && attrId.equals(certId)) {
                 foundObj = true;
-                CMS.debug("PKCD11Obj.doesCertIdExist: match found!");
-                break;
+                CMS.debug("PKCD11Obj.doesCertIdExist: match found new way!");
             }
-
         }
 
         return foundObj;
@@ -231,11 +214,9 @@ public class PKCS11Obj {
 
             if (oid == p.getObjectID()) {
                 objectSpecs.remove(objSpec);
-                char[] b1 = new char[2];
 
-                b1[0] = (char) ((oid >> 24) & 0xff);
-                b1[1] = (char) ((oid >> 16) & 0xff);
-                String oidStr = new String(b1);
+                String oidStr = objSpec.getAttrId();
+
                 CMS.debug("PKCS11Obj.addObjectSpec: found dup, removing...: " + oidStr);
                 break;
             }
@@ -307,25 +288,25 @@ public class PKCS11Obj {
 
         for (int i = 0; i < objectCount; i++) {
             ObjectSpec spec = getObjectSpec(i);
-            long objectID = spec.getObjectID();
-            char c = (char) ((objectID >> 24) & 0xff);
+
+            char c = spec.getObjectType();
             long fixedAttrs = spec.getFixedAttributes();
             int xclass = (int) ((fixedAttrs & 0x70) >> 4);
-            char cont_id = (char) ((objectID >> 16) & 0xff);
+            long cont_id = spec.getObjectIndex();
             long id = (int) (fixedAttrs & 0x0f);
+
             /* locate all certificate objects */
             if (c == 'c' && xclass == PKCS11Constants.CKO_CERTIFICATE) {
 
                 //We need to use the container id, there may be more than one cert
                 //with the same CKA_ID byte
 
-                id = cont_id - '0';
+                id = cont_id;
 
                 /* locate the certificate object */
                 for (int u = 0; u < objectCount; u++) {
                     ObjectSpec u_spec = getObjectSpec(u);
-                    long u_objectID = u_spec.getObjectID();
-                    char u_c = (char) ((u_objectID >> 24) & 0xff);
+                    char u_c = u_spec.getObjectType();
                     long u_fixedAttrs =
                             u_spec.getFixedAttributes();
                     int u_xclass = (int) ((u_fixedAttrs & 0x70) >> 4);
@@ -618,6 +599,10 @@ public class PKCS11Obj {
 
         System.out.println("CertID " + certId + " exists: " + exists);
 
+        int nextFreeCertId = object.getNextFreeCertIdNumber();
+
+        System.out.println("Next Free CertID: " + nextFreeCertId);
+
         // This gets the compressed blob that will go out to token of the parsed data.
         TPSBuffer implodedData = object.getCompressedData();
 
@@ -653,7 +638,9 @@ public class PKCS11Obj {
 
     public int getNextFreeCertIdNumber() {
 
-        int highest_cert_id = 0;
+        int free_cert_id = 0;
+
+        int[] certTable = new int[100];
 
         int numObjs = getObjectSpecCount();
 
@@ -662,28 +649,27 @@ public class PKCS11Obj {
             if (os == null)
                 continue;
 
-            long objid = os.getObjectID();
-
-            char[] b1 = new char[2];
-
-            b1[0] = (char) ((objid >> 24) & 0xff);
-            b1[1] = (char) ((objid >> 16) & 0xff);
-
-            if (b1[0] == 'C') { //found a certificate
+            char type = os.getObjectType();
+            int index = os.getObjectIndex();
 
-                int id_int = b1[1] - '0';
-
-                if (id_int > highest_cert_id) {
-                    highest_cert_id = id_int;
+            if (type == 'C') { //found a certificate
+                if (index >= 0 && index < 100) {
+                    certTable[index] = 1;
                 }
             }
+        }
+
+        for (int i = 0; i < 100; i++) {
+            if (certTable[i] == 0) {
 
+                free_cert_id = i;
+                break;
+            }
         }
 
-        highest_cert_id++;
-        CMS.debug("TPSEnrollProcessor.getNextFreeCertIdNumber: returning: " + highest_cert_id);
+        CMS.debug("TPSEnrollProcessor.getNextFreeCertIdNumber: returning free cert id: " + free_cert_id );
 
-        return highest_cert_id;
+        return free_cert_id;
     }
 
 }
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/CertEnrollInfo.java b/base/tps/src/org/dogtagpki/server/tps/processor/CertEnrollInfo.java
index 9dfb3f1..d6a49a4 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/CertEnrollInfo.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/CertEnrollInfo.java
@@ -23,6 +23,7 @@ import org.dogtagpki.server.tps.cms.CARetrieveCertResponse;
 import org.dogtagpki.server.tps.cms.KRARecoverKeyResponse;
 import org.dogtagpki.server.tps.dbs.TokenRecord;
 import org.dogtagpki.server.tps.engine.TPSEngine;
+import org.dogtagpki.server.tps.main.ObjectSpec;
 
 public class CertEnrollInfo {
 
@@ -257,14 +258,12 @@ public class CertEnrollInfo {
 
     public int getCertIdIndex() {
         int result = 0;
+        long objectID = 0;
 
-        if(certId != null && certId.length() == 2) {
-         result = certId.charAt(1) - '0';
-        }
+        objectID = ObjectSpec.createObjectID(certId);
+        result = ObjectSpec.getObjectIndex(objectID);
 
         return result;
     }
 
-
-
 }
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 87b86f7..5547f44 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/EnrolledCertsInfo.java
@@ -38,6 +38,7 @@ public class EnrolledCertsInfo {
         ktypes = new ArrayList<String>();
         origins = new ArrayList<String>();
         tokenTypes = new ArrayList<String>();
+        externalRegRecoveryEnrollList = new ArrayList<CertEnrollInfo>();
     }
 
     EnrolledCertsInfo(PKCS11Obj obj, TPSBuffer wrappedChallenge, TPSBuffer plainChallenge, int keyTypeNum,
@@ -57,6 +58,8 @@ public class EnrolledCertsInfo {
     private ArrayList<String> tokenTypes;
     private ArrayList<X509CertImpl> certificates;
 
+    private ArrayList<CertEnrollInfo> externalRegRecoveryEnrollList;
+
     //Input challenge data
     private TPSBuffer wrappedChallenge;
     private TPSBuffer plaintextChallenge;
@@ -72,6 +75,10 @@ public class EnrolledCertsInfo {
         return currentCertIndex;
     }
 
+    public ArrayList<CertEnrollInfo> getExternalRegRecoveryEnrollList() {
+        return externalRegRecoveryEnrollList;
+    }
+
     public void setCurrentCertIndex(int index) {
         currentCertIndex = index;
     }
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 e21f7ca..89e1191 100644
--- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
+++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java
@@ -13,6 +13,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;
@@ -52,6 +57,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;
@@ -59,12 +66,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) {
@@ -238,7 +239,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
              *    plugin used
              */
             try {
-            String resolverInstName = getKeySetResolverInstanceName();
+                String resolverInstName = getKeySetResolverInstanceName();
 
                 if (!resolverInstName.equals("none") && (selectedKeySet == null)) {
                     FilterMappingParams mappingParams = createFilterMappingParams(resolverInstName,
@@ -266,7 +267,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
              *    plugin used (tokenType resolved perhaps via authentication)
              */
             try {
-            String resolverInstName = getResolverInstanceName();
+                String resolverInstName = getResolverInstanceName();
 
                 if (!resolverInstName.equals("none") && (selectedTokenType == null)) {
                     FilterMappingParams mappingParams = createFilterMappingParams(resolverInstName,
@@ -357,7 +358,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
         CMS.debug(method + " Finished updating applet if needed.");
 
         //Check and upgrade keys if called for
-        SecureChannel channel = checkAndUpgradeSymKeys(appletInfo,tokenRecord);
+        SecureChannel channel = checkAndUpgradeSymKeys(appletInfo, tokenRecord);
         channel.externalAuthenticate();
 
         //Reset the token's pin, create one if we don't have one already
@@ -441,7 +442,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 CMS.debug(method + "generateCertificates returned false means cert enrollment unsuccessful");
                 // in case isExternalReg, leave the token alone, do not format
                 if (!isExternalReg) {
-                    CMS.debug(method + "generateCertificates returned false means some certs failed enrollment;  clean up (format) the token");
+                    CMS.debug(method
+                            + "generateCertificates returned false means some certs failed enrollment;  clean up (format) the token");
                     format(true /*skipAuth*/);
                 }
                 tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), logMsg,
@@ -467,7 +469,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
                         if (recoverStatus == TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED) {
                             recovered = true;
                             logMsg = method + " externalRegRecover returned: recoverStatus=" + recoverStatus;
-                            tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(), logMsg, "success");
+                            tps.tdb.tdbActivity(ActivityDatabase.OP_RECOVERY, tokenRecord, session.getIpAddress(),
+                                    logMsg, "success");
                         } else {
                             logMsg = method + " externalRegRecover returned: recoverStatus=" + recoverStatus;
                             CMS.debug(logMsg);
@@ -545,7 +548,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
         writeFinalPKCS11ObjectToToken(pkcs11objx, appletInfo, channel);
         statusUpdate(98, "PROGRESS_ISSUER_INFO");
-        writeIssuerInfoToToken(channel,appletInfo);
+        writeIssuerInfoToToken(channel, appletInfo);
 
         statusUpdate(99, "PROGRESS_SET_LIFECYCLE");
         channel.setLifeycleState((byte) 0x0f);
@@ -587,7 +590,6 @@ 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
@@ -631,7 +633,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
         CMS.debug(method + "number of certs to recover=" + count);
         if (count == 0) {
             CMS.debug(method + " nothing to process. Returning status: "
-                + status);
+                    + status);
             return status;
         }
         String tokenType = erAttrs.getTokenType();
@@ -661,10 +663,10 @@ public class TPSEnrollProcessor extends TPSProcessor {
         CMS.debug(method + " config keyTypeNum: " + keyTypeNum);
 
         int index = -1;
-        for (int i=0; i < keyTypeNum; i++) {
+        for (int i = 0; i < keyTypeNum; i++) {
             configName = "op.enroll." +
-                tokenType + "." +
-                "keyGen.keyType.value." + i;
+                    tokenType + "." +
+                    "keyGen.keyType.value." + i;
             String keyTypeValue;
             try {
                 CMS.debug(method + " getting config : " + configName);
@@ -678,7 +680,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
             }
             CMS.debug(method + " config keyTypeValue: " + keyTypeValue);
             String keyTypePrefix = "op.enroll." +
-                tokenType + ".keyGen." + keyTypeValue;
+                    tokenType + ".keyGen." + keyTypeValue;
             CMS.debug(method + " keyTypePrefix is: " + keyTypePrefix);
 
             configName = keyTypePrefix + ".certId";
@@ -694,11 +696,11 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 return TPSStatus.STATUS_ERROR_MISCONFIGURATION;
             }
             CMS.debug(method + " certId is: " + certId);
-            if (certId != null && certId.length() >1) {
-                index = Character.getNumericValue(certId.charAt(1));
+            if (certId != null && certId.length() > 1) {
+                index = ObjectSpec.getObjectIndex(certId);
             }
 
-            if (index >=0 && numCertsToSave < MAX_CERTS) {
+            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;
@@ -707,21 +709,20 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
         int num_objs = pkcs11obj.getObjectSpecCount();
         CMS.debug(method + " pkcs11obj num_objs =" + num_objs);
-        char[] bytesA = new char[3];
+        // 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++) {
+        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++ ) {
+            char type = os.getObjectType();
+            int objIndex = os.getObjectIndex();
+
+            if (type == '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) {
@@ -735,27 +736,30 @@ public class TPSEnrollProcessor extends TPSProcessor {
                                 return TPSStatus.STATUS_ERROR_CONTACT_ADMIN;
                             }
                             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);
+
+                            int certId = objIndex;
+
+                            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)  {
+                                for (int p = 0; p < numCertsToSave; p++) {
+                                    if (certsToSave[p] == certId) {
                                         protect = true;
                                         break;
                                     }
                                 }
                                 CMS.debug(method + " protect cert " + certId +
-                                    ": " + protect);
+                                        ": " + protect);
                                 /*
                                  * Delete this cert if it is NOT protected by
                                  * the certs generated by the profile enrollment.
                                  */
-                                if((numCertsToDelete < MAX_CERTS) &&
-                                    (protect == false )) {
+                                if ((numCertsToDelete < MAX_CERTS) &&
+                                        (protect == false)) {
                                     certsToDelete[numCertsToDelete++] = certId;
                                 }
                             } else {
@@ -774,7 +778,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
          * Now rifle through the certsToDeleteList and remove those that
          *  need to be deleted
          */
-        for(int k = 0 ; k <  numCertsToDelete ; k ++ ) {
+        for (int k = 0; k < numCertsToDelete; k++) {
             CMS.debug(method + "cert to delete: " + certsToDelete[k]);
             removeCertFromObjectList(certsToDelete[k], pkcs11obj);
         }
@@ -790,7 +794,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
      */
     void removeCertFromObjectList(int cIndex, PKCS11Obj pkcs11obj) {
         String method = "TPSEnrollProcessor.removeCertFromObjectList: ";
-        if ( pkcs11obj == null ) {
+        if (pkcs11obj == null) {
             CMS.debug(method + " pkcs11obj null");
             return;
         }
@@ -804,18 +808,15 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
         // loop through all objects on token
         int index = 0;
-        for (int i = 0; i <  pkcs11obj.getObjectSpecCount(); i++) {
+        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);
-
+            char c1 = spec.getObjectType();
+            index = spec.getObjectIndex();
             /* 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");
+                if (index == C || index == c) {
+                    CMS.debug(method + " found index:" + index +
+                            "; Removing cert Object");
                     pkcs11obj.removeObjectSpec(i);
                     i--;
                 }
@@ -823,8 +824,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
             if (c1 == 'k') {
                 if (index == k1 || index == k2) {
-                    CMS.debug(method + " found index:"+ index +
-                       "; Removing key Object");
+                    CMS.debug(method + " found index:" + index +
+                            "; Removing key Object");
                     pkcs11obj.removeObjectSpec(i);
                     i--;
                 }
@@ -833,7 +834,6 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
     }
 
-
     private void writeFinalPKCS11ObjectToToken(PKCS11Obj pkcs11objx, AppletInfo ainfo, SecureChannel channel)
             throws TPSException, IOException {
         if (pkcs11objx == null || ainfo == null || channel == null) {
@@ -1223,6 +1223,9 @@ public class TPSEnrollProcessor extends TPSProcessor {
             CMS.debug(method + "nothing to recover...");
             return status;
         }
+
+        ArrayList<CertEnrollInfo> preRecoveredCerts = certsInfo.getExternalRegRecoveryEnrollList();
+
         CMS.debug(method + "number of certs to recover=" +
                 session.getExternalRegAttrs().getCertsToRecoverCount());
         ArrayList<ExternalRegCertToRecover> erCertsToRecover =
@@ -1294,7 +1297,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 logMsg = " no keyid; skip key recovery; continue";
                 CMS.debug(method + logMsg);
                 continue;
-            } else if ( keyid.compareTo(BigInteger.valueOf(0))==0) {
+            } else if (keyid.compareTo(BigInteger.valueOf(0)) == 0) {
                 logMsg = " keyid is 0; invalid; skip key recovery; continue";
                 CMS.debug(method + logMsg);
                 continue;
@@ -1317,7 +1320,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 }
 
                 keyResp = kraRH.recoverKey(cuid, userid, Util.specialURLEncode(channel.getDRMWrappedDesKey()),
-                            null, keyid);
+                        null, keyid);
                 if (keyResp == null) {
                     logMsg = "recovering key not found";
                     CMS.debug(method + logMsg);
@@ -1328,18 +1331,43 @@ public class TPSEnrollProcessor extends TPSProcessor {
             CertEnrollInfo cEnrollInfo = new CertEnrollInfo();
             cEnrollInfo.setTokenToBeRecovered(tokenRecord);
             cEnrollInfo.setRecoveredCertData(certResp);
-
             cEnrollInfo.setRecoveredKeyData(keyResp);
+            preRecoveredCerts.add(cEnrollInfo);
+
+        }
 
-            CMS.debug(method + "before calling generateCertificate, certsInfo.getCurrentCertIndex() =" + certsInfo.getCurrentCertIndex());
+        // Now that we know we have the data for all the certs recovered, let's actually touch the token
+        // and recover the certificates.
+
+        if (preRecoveredCerts != null && preRecoveredCerts.size() != 0) {
             PKCS11Obj pkcs11obj = certsInfo.getPKCS11Obj();
-            int newCertId = pkcs11obj.getNextFreeCertIdNumber();
-            generateCertificate(certsInfo, channel, appletInfo,
-                    "encryption",
-                    TPSEngine.ENROLL_MODES.MODE_RECOVERY,
-                    newCertId, cEnrollInfo);
 
-            CMS.debug(method + "after generateCertificate() with MODE_RECOVERY");
+            int numCerts = preRecoveredCerts.size();
+
+            certsInfo.setNumCertsToEnroll(numCerts);
+
+            for (int i = 0; i < preRecoveredCerts.size(); i++) {
+
+                CertEnrollInfo certRecoveredInfo = preRecoveredCerts.get(i);
+
+                if (certRecoveredInfo != null) {
+
+                    int newCertId = pkcs11obj.getNextFreeCertIdNumber();
+                    certsInfo.setCurrentCertIndex(i);
+
+                    //certsInfo.setCurrentCertIndex(i);
+
+                    CMS.debug(method + "before calling generateCertificate, certsInfo.getCurrentCertIndex() ="
+                            + certsInfo.getCurrentCertIndex());
+                    generateCertificate(certsInfo, channel, appletInfo,
+                            "encryption",
+                            TPSEngine.ENROLL_MODES.MODE_RECOVERY,
+                            newCertId, certRecoveredInfo);
+
+                    CMS.debug(method + "after generateCertificate() with MODE_RECOVERY");
+                }
+
+            }
         }
 
         CMS.debug(method + "ends");
@@ -1483,11 +1511,12 @@ public class TPSEnrollProcessor extends TPSProcessor {
                         //Renew and fetch the renewed cert blob.
 
                         CARenewCertResponse certResponse = tps.getEngine().renewCertificate(cert,
-                                cert.getSerialNumber(), selectedTokenType, keyType, getCAConnectorID("renewal", keyType));
+                                cert.getSerialNumber(), selectedTokenType, keyType,
+                                getCAConnectorID("renewal", keyType));
                         cEnrollInfo.setRenewedCertData(certResponse);
 
                         generateCertificate(certsInfo, channel, aInfo, keyType, TPSEngine.ENROLL_MODES.MODE_RENEWAL,
-                                0, cEnrollInfo);
+                                -1, cEnrollInfo);
 
                         //renewCertificate(cert, certsInfo, channel, aInfo, keyType);
                         status = TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED;
@@ -1824,8 +1853,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
                     try {
                         // set cert status to active
                         tps.tdb.updateCertsStatus(certToRecover.getSerialNumber(),
-                                                  certToRecover.getIssuedBy(),
-                                                  "active");
+                                certToRecover.getIssuedBy(),
+                                "active");
                     } catch (Exception e) {
                         logMsg = "failed tdbUpdateCertEntry";
                         CMS.debug(method + ":" + logMsg);
@@ -1876,7 +1905,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
             String keyType = getConfiguredKeyType(i);
             certsInfo.setCurrentCertIndex(i);
             try {
-                generateCertificate(certsInfo, channel, aInfo, keyType, TPSEngine.ENROLL_MODES.MODE_ENROLL, 0, null);
+                generateCertificate(certsInfo, channel, aInfo, keyType, TPSEngine.ENROLL_MODES.MODE_ENROLL, -1, null);
             } catch (TPSException e) {
                 CMS.debug("TPSEnrollProcessor.generateCertificate: exception:" + e);
                 noFailedCerts = false;
@@ -2066,7 +2095,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
             // Thus overriding what is found in the config.
             // Used in recovery mostly up to this point.
 
-            if (certIdNumOverride > 0) {
+            if (certIdNumOverride >= 0) {
                 CMS.debug("TPSEnrollProcessor.generateCertificate: called with overridden cert id number: "
                         + certIdNumOverride);
 
@@ -2109,10 +2138,16 @@ public class TPSEnrollProcessor extends TPSProcessor {
             int currentCertIndex = certsInfo.getCurrentCertIndex();
             int totalNumCerts = certsInfo.getNumCertsToEnroll();
 
+            CMS.debug("TPSEnrollProcessor.generateCertificate: Progress values: certsStartProgress: "
+                    + certsStartProgress + " certsEndProgress: " + certsEndProgress +
+                    " currentCertIndex: " + currentCertIndex + " totalNumCerts: " + totalNumCerts);
+
             int progressBlock = 0;
             if (totalNumCerts != 0) {
                 progressBlock =
-                   (certsEndProgress - certsStartProgress) / totalNumCerts;
+                        (certsEndProgress - certsStartProgress) / totalNumCerts;
+
+                CMS.debug("TPSEnrollProcessor.generateCertificate: progressBlock: " + progressBlock);
             } else {//TODO need to make this more accurate
                 CMS.debug("TPSEnrollProcessor.generateCertificate: totalNumCerts =0, progressBlock left at 0");
             }
@@ -2121,6 +2156,9 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
             int endCertProgValue = startCertProgValue + progressBlock;
 
+            CMS.debug("TPSEnrollProcessor.generateCertificate: startCertProgValue: " + startCertProgValue
+                    + " endCertProgValue: " + endCertProgValue);
+
             cEnrollInfo.setStartProgressValue(startCertProgValue);
             cEnrollInfo.setEndProgressValue(endCertProgValue);
 
@@ -2244,17 +2282,20 @@ public class TPSEnrollProcessor extends TPSProcessor {
                     // reset to accurate keysize
                     RSAPublicKey rsaKey = new RSAPublicKey(parsedPubKey_ba);
                     cEnrollInfo.setKeySize(rsaKey.getKeySize());
-                    CMS.debug("TPSEnrollProcessor.enrollOneCertificate: recovery reset keysize to:" + rsaKey.getKeySize());
+                    CMS.debug("TPSEnrollProcessor.enrollOneCertificate: recovery reset keysize to:"
+                            + rsaKey.getKeySize());
                 }
             } catch (InvalidKeyFormatException e) {
-                String msg = "TPSEnrollProcessor.enrollOneCertificate, can't create public key object from server side key generated public key blob! " + e.toString();
+                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,
+                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();
+                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,
+                throw new TPSException(msg,
                         TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU);
             }
 
@@ -2307,7 +2348,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
                         + aInfo.getCUIDhexString());
 
                 CAEnrollCertResponse caEnrollResp;
-                if (session.getExternalRegAttrs()!= null &&
+                if (session.getExternalRegAttrs() != null &&
                         session.getExternalRegAttrs().getIsDelegation()) {
                     int sanNum = 0;
                     String urlSanExt = null;
@@ -2588,15 +2629,17 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
             //Write cert to the token,do this in all modes
 
-            long l1, l2;
+            //   long l1, l2;
             long objid;
             PKCS11Obj pkcs11Obj = certsInfo.getPKCS11Obj();
 
             String certId = cEnrollInfo.getCertId();
 
-            l1 = (certId.charAt(0) & 0xff) << 24;
-            l2 = (certId.charAt(1) & 0xff) << 16;
-            objid = l1 + l2;
+            objid = ObjectSpec.createObjectID(certId);
+
+            //           l1 = (certId.charAt(0) & 0xff) << 24;
+            //          l2 = (certId.charAt(1) & 0xff) << 16;
+            //         objid = l1 + l2;
 
             CMS.debug("TPSEnrollProcess.enrollOneCertificate:  cert objid long: " + objid);
 
@@ -2612,9 +2655,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
                 TPSBuffer certAttrsBuffer = channel.createPKCS11CertAttrsBuffer(cEnrollInfo.getKeyTypeEnum(),
                         certAttrId, label, keyid);
 
-                l1 = (certAttrId.charAt(0) & 0xff) << 24;
-                l2 = (certAttrId.charAt(1) & 0xff) << 16;
-                objid = l1 + l2;
+                objid = ObjectSpec.createObjectID(certAttrId);
 
                 CMS.debug("TPSEnrollProcess.enrollOneCertificate:  cert attr objid long: " + objid);
                 ObjectSpec certAttrObjSpec = ObjectSpec.parseFromTokenData(objid, certAttrsBuffer);
@@ -2624,10 +2665,7 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
                 String priKeyAttrId = cEnrollInfo.getPrivateKeyAttrId();
 
-                l1 = (priKeyAttrId.charAt(0) & 0xff) << 24;
-                l2 = (priKeyAttrId.charAt(1) & 0xff) << 16;
-
-                objid = l1 + l2;
+                objid = ObjectSpec.createObjectID(priKeyAttrId);
 
                 CMS.debug("TPSEnrollProcess.enrollOneCertificate: pri key objid long: " + objid);
 
@@ -2641,10 +2679,8 @@ public class TPSEnrollProcessor extends TPSProcessor {
 
                 String pubKeyAttrId = cEnrollInfo.getPublicKeyAttrId();
 
-                l1 = (pubKeyAttrId.charAt(0) & 0xff) << 24;
-                l2 = (pubKeyAttrId.charAt(1) & 0xff) << 16;
+                objid = ObjectSpec.createObjectID(pubKeyAttrId);
 
-                objid = l1 + l2;
                 CMS.debug("TPSEnrollProcess.enrollOneCertificate: pub key objid long: " + objid);
 
                 TPSBuffer pubKeyAttrsBuffer = channel.createPKCS11PublicKeyAttrsBuffer(pubKeyAttrId, label, keyid,
@@ -2798,7 +2834,6 @@ public class TPSEnrollProcessor extends TPSProcessor {
         data.add(ivParamsBuff);
         CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8: key data outgoing: " + data.toHexString());
 
-
         int pe1 = (cEnrollInfo.getKeyUser() << 4) + cEnrollInfo.getPrivateKeyNumber();
         int pe2 = (cEnrollInfo.getKeyUsage() << 4) + cEnrollInfo.getPublicKeyNumber();
 
-- 
2.1.0

