From 08fa0ff96d7dd6ed6c3b11527251e604b93f045a Mon Sep 17 00:00:00 2001
From: Jack Magne <jmagne@dhcp-16-206.sjc.redhat.com>
Date: Fri, 16 Dec 2016 16:25:48 -0800
Subject: [PATCH] Ticket #2569: Token memory not wiped after key deletion

This is the dogtag upstream side of the TPS portion of this ticket.
This fix also involves an applet fix, handled in another bug.
---
 base/common/src/org/dogtagpki/tps/apdu/APDU.java   |  3 +-
 .../org/dogtagpki/tps/apdu/ClearKeySlotsAPDU.java  | 24 ++++++
 .../server/tps/channel/SecureChannel.java          | 36 +++++++++
 .../org/dogtagpki/server/tps/main/PKCS11Obj.java   | 90 +++++++++++++++++++++-
 .../server/tps/processor/TPSEnrollProcessor.java   | 22 ++++--
 5 files changed, 165 insertions(+), 10 deletions(-)
 create mode 100644 base/common/src/org/dogtagpki/tps/apdu/ClearKeySlotsAPDU.java

diff --git a/base/common/src/org/dogtagpki/tps/apdu/APDU.java b/base/common/src/org/dogtagpki/tps/apdu/APDU.java
index 390252f..009c470 100644
--- a/base/common/src/org/dogtagpki/tps/apdu/APDU.java
+++ b/base/common/src/org/dogtagpki/tps/apdu/APDU.java
@@ -57,7 +57,8 @@ public abstract class APDU {
         APDU_SET_ISSUERINFO,
         APDU_GET_ISSUERINFO,
         APDU_GENERATE_KEY_ECC,
-        APDU_GET_LIFECYCLE
+        APDU_GET_LIFECYCLE,
+        APDU_CLEAR_KEY_SLOTS
     }
 
     protected byte cla;
diff --git a/base/common/src/org/dogtagpki/tps/apdu/ClearKeySlotsAPDU.java b/base/common/src/org/dogtagpki/tps/apdu/ClearKeySlotsAPDU.java
new file mode 100644
index 0000000..b3d71c4
--- /dev/null
+++ b/base/common/src/org/dogtagpki/tps/apdu/ClearKeySlotsAPDU.java
@@ -0,0 +1,24 @@
+package org.dogtagpki.tps.apdu;
+
+import org.dogtagpki.tps.main.TPSBuffer;
+
+
+public class ClearKeySlotsAPDU extends APDU {
+    public ClearKeySlotsAPDU(byte[] slotList) {
+        setCLA((byte) 0x84);
+        setINS((byte) 0x55);
+        setP1((byte) 0x0);
+        setP2((byte) 0x0);
+
+        data = new TPSBuffer();
+        data.addBytes(slotList);
+
+    }
+
+    @Override
+    public Type getType()
+    {
+        return Type.APDU_CLEAR_KEY_SLOTS;
+    }
+
+}
diff --git a/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java
index 8860f48..13fb534 100644
--- a/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java
+++ b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java
@@ -23,6 +23,7 @@ import org.dogtagpki.server.tps.engine.TPSEngine;
 import org.dogtagpki.server.tps.processor.TPSProcessor;
 import org.dogtagpki.tps.apdu.APDU;
 import org.dogtagpki.tps.apdu.APDUResponse;
+import org.dogtagpki.tps.apdu.ClearKeySlotsAPDU;
 import org.dogtagpki.tps.apdu.CreateObjectAPDU;
 import org.dogtagpki.tps.apdu.CreatePinAPDU;
 import org.dogtagpki.tps.apdu.DeleteFileAPDU;
@@ -850,6 +851,41 @@ public class SecureChannel {
         return keyInfoData;
     }
 
+    //Call the applet to clear unused key slots
+    public void clearAppletKeySlotData(TPSBuffer data) {
+        String method = "SecureChannel.clearAppletKeySlotData: ";
+
+        CMS.debug(method + " entering ...");
+
+        if(data == null) {
+            CMS.debug(method + " Invalid input data returning...");
+            return;
+        }
+
+
+
+       // CMS.debug(method + " apdu sending: " + clearKey.getEncoding().toHexString());
+
+
+
+        APDUResponse response;
+        try {
+
+            ClearKeySlotsAPDU  clearKey = new ClearKeySlotsAPDU(data.toBytesArray());
+            computeAPDU(clearKey);
+            response = processor.handleAPDURequest(clearKey);
+        } catch (TPSException | IOException e) {
+            CMS.debug(method + " bad apdu return!");
+            return;
+
+        }
+
+        if (!response.checkResult()) {
+            CMS.debug(method + " bad apdu return!");
+        }
+
+    }
+
     public void writeObject(TPSBuffer objectID, TPSBuffer objectData) throws TPSException, IOException {
         CMS.debug("SecureChannel.writeObject: entering ...");
 
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 6af39a7..ccfcbb7 100644
--- a/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java
+++ b/base/tps/src/org/dogtagpki/server/tps/main/PKCS11Obj.java
@@ -265,6 +265,92 @@ public class PKCS11Obj {
 
     }
 
+    public TPSBuffer getKeyIndexList() {
+
+        TPSBuffer data = new TPSBuffer();
+
+
+        int objectCount = getObjectSpecCount();
+
+
+        CMS.debug("PKCS11Obj:getKeyIndexList: objectCount: " + objectCount);
+
+      //Add first byte for length, set to 0 for now
+
+        byte keyListCount = 0;
+
+        for (int i = 0; i < objectCount; i++) {
+            ObjectSpec spec = getObjectSpec(i);
+
+            char c = spec.getObjectType();
+            long fixedAttrs = spec.getFixedAttributes();
+            int xclass = (int) ((fixedAttrs & 0x70) >> 4);
+            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;
+
+                /* locate the certificate object */
+                for (int u = 0; u < objectCount; u++) {
+                    ObjectSpec u_spec = getObjectSpec(u);
+                    char u_c = u_spec.getObjectType();
+                    long u_fixedAttrs =
+                            u_spec.getFixedAttributes();
+                    int u_xclass = (int) ((u_fixedAttrs & 0x70) >> 4);
+                    int u_id = (int) (u_fixedAttrs & 0x0f);
+                    if (u_c == 'C' && u_xclass == PKCS11Constants.CKO_CERTIFICATE && u_id == id) {
+                        CMS.debug("PKCSObj:getKeyIndexList: found cert object: id: " + id + " u_id: " + u_id);
+                    }
+                }
+
+                /* locate private object */
+                for (int y = 0; y < objectCount; y++) {
+                    ObjectSpec y_spec = getObjectSpec(y);
+                    long y_fixedAttrs =
+                            y_spec.getFixedAttributes();
+                    int y_xclass = (int) ((y_fixedAttrs & 0x70) >> 4);
+                    int y_id = (int) (y_fixedAttrs & 0x0f);
+                    if (y_xclass == PKCS11Constants.CKO_PRIVATE_KEY && y_id == id) {
+                        CMS.debug("PKCS11Obj::getKeyIndexList: found private key object: id: " + y_spec.getObjectIndex());
+
+                        data.add((byte) y_spec.getObjectIndex());
+                        keyListCount++;
+
+                    }
+                }
+
+                /* locate public object */
+                for (int x = 0; x < objectCount; x++) {
+                    ObjectSpec x_spec = getObjectSpec(x);
+                    long x_fixedAttrs =
+                            x_spec.getFixedAttributes();
+                    int x_xclass = (int) ((x_fixedAttrs & 0x70) >> 4);
+                    int x_id = (int) (x_fixedAttrs & 0x0f);
+                    if (x_xclass == PKCS11Constants.CKO_PUBLIC_KEY && x_id == id) {
+                        CMS.debug("PKCSObj::getKeyIndexList: found public key object: id: " + x_spec.getObjectIndex());
+
+                        data.add((byte) x_spec.getObjectIndex());
+                        keyListCount++;
+                    }
+                }
+
+
+            }
+        }
+
+        CMS.debug("PKCS11Obj::getKeyIndexList: returning: " + data.toHexString());
+
+        return data;
+
+
+    }
+
     private TPSBuffer getRawData() {
         TPSBuffer data = new TPSBuffer();
 
@@ -335,7 +421,7 @@ public class PKCS11Obj {
                     int x_xclass = (int) ((x_fixedAttrs & 0x70) >> 4);
                     int x_id = (int) (x_fixedAttrs & 0x0f);
                     if (x_xclass == PKCS11Constants.CKO_PUBLIC_KEY && x_id == id) {
-                        CMS.debug("PKCSObj:getRawData: found public key object: id: " + id);
+                        CMS.debug("PKCSObj:getRawData: found public key object: id: " + x_spec.getObjectIndex());
                         data.add(x_spec.getData());
                     }
                 }
@@ -348,7 +434,7 @@ public class PKCS11Obj {
                     int y_xclass = (int) ((y_fixedAttrs & 0x70) >> 4);
                     int y_id = (int) (y_fixedAttrs & 0x0f);
                     if (y_xclass == PKCS11Constants.CKO_PRIVATE_KEY && y_id == id) {
-                        CMS.debug("PKCSObj:getRawData: found private key object: id: " + id);
+                        CMS.debug("PKCSObj:getRawData: found private key object: id: " + y_spec.getObjectIndex());
                         data.add(y_spec.getData());
                     }
                 }
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 64cc571..54e03a8 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,12 @@ 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.RevocationReason;
+import netscape.security.x509.X509CertImpl;
+
 import org.dogtagpki.server.tps.TPSSession;
 import org.dogtagpki.server.tps.TPSSubsystem;
 import org.dogtagpki.server.tps.TPSTokenPolicy;
@@ -53,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;
@@ -60,13 +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.RevocationReason;
-import netscape.security.x509.X509CertImpl;
-import sun.security.pkcs11.wrapper.PKCS11Constants;
-
 public class TPSEnrollProcessor extends TPSProcessor {
 
     public TPSEnrollProcessor(TPSSession session) {
@@ -585,6 +586,13 @@ public class TPSEnrollProcessor extends TPSProcessor {
             throw new TPSException(logMsg);
         }
 
+      //Now let's clear off any key slots if the enrollment left any unused but occupied with key data on the applet
+
+        TPSBuffer keyList = pkcs11objx.getKeyIndexList();
+
+        channel.clearAppletKeySlotData(keyList);
+
+
         CMS.debug(method + " leaving ...");
 
         statusUpdate(100, "PROGRESS_DONE_ENROLLMENT");
-- 
2.5.0

