From 3f04d1fff3b7d8f1b163a6a591e7edf30d0a9ec6 Mon Sep 17 00:00:00 2001
From: Jack Magne <jmagne@dhcp-16-213.sjc.redhat.com>
Date: Fri, 25 Apr 2014 20:27:09 -0700
Subject: [PATCH] Support for Applet Upgrade and Format.

The following changes have been done:

1. Applet Upgrade for real token. The applet is written and an instance of applet created.
2. 95% of the format operation done. This includes proper status update progreass bar
for esc and writing the phone home url to the token. Once this operation is complete,
the token can be entered into esc and esc will be able to phone home and point to TPS
for further operations such as enrollment and pin reset when they are implemented.
3. The phoneHome xml file changed slightly to prevent esc from reading exttraneous line
feeds when phoning home.
4. The CS.cfg has been changed to correctly reflect the phone home url we want to write to
the token.

The following to be done to fully finish format, later tickets.

1.Updating the tokendb with tne newly formatted token. Future ticket.
2.Revoking tokens current certificates, if any. Future ticket.
3.Symmetric Key changeover. Future ticket.
---
 .../org/dogtagpki/tps/apdu/InstallLoadAPDU.java    |   8 +-
 .../src/org/dogtagpki/tps/main/TPSBuffer.java      |   5 +
 .../src/org/dogtagpki/tps/msg/TPSMessage.java      |  11 ++
 base/tps-tomcat/shared/conf/CS.cfg.in              |  12 +-
 base/tps-tomcat/shared/conf/phoneHome.xml          |  21 +--
 .../src/org/dogtagpki/server/tps/TPSPhoneHome.java |   9 +-
 .../src/org/dogtagpki/server/tps/TPSSession.java   |   2 +-
 .../server/tps/channel/SecureChannel.java          | 203 +++++++++++++++++++++
 .../org/dogtagpki/server/tps/engine/TPSEngine.java |   5 +-
 .../server/tps/processor/TPSProcessor.java         | 176 +++++++++++++++---
 10 files changed, 402 insertions(+), 50 deletions(-)

diff --git a/base/common/src/org/dogtagpki/tps/apdu/InstallLoadAPDU.java b/base/common/src/org/dogtagpki/tps/apdu/InstallLoadAPDU.java
index cb84b93..d754801 100644
--- a/base/common/src/org/dogtagpki/tps/apdu/InstallLoadAPDU.java
+++ b/base/common/src/org/dogtagpki/tps/apdu/InstallLoadAPDU.java
@@ -45,9 +45,11 @@ public class InstallLoadAPDU extends APDU {
         inputData.add((byte) 0x04);
         inputData.add((byte) 0xC6);
         inputData.add((byte) 0x02);
-        fileLen += 24 + sdAID.size();
-        inputData.add((byte) ((fileLen >> 8) & 0xff));
-        inputData.add((byte) (fileLen & 0xff));
+        int finalLen = fileLen + 24 + sdAID.size();
+
+        inputData.add((byte) ((finalLen >> 8) & 0xff));
+        inputData.add((byte) (finalLen & 0xff));
+        inputData.add((byte) 0x0);
 
         setData(inputData);
     }
diff --git a/base/common/src/org/dogtagpki/tps/main/TPSBuffer.java b/base/common/src/org/dogtagpki/tps/main/TPSBuffer.java
index 03ec460..ef40a3a 100644
--- a/base/common/src/org/dogtagpki/tps/main/TPSBuffer.java
+++ b/base/common/src/org/dogtagpki/tps/main/TPSBuffer.java
@@ -300,6 +300,11 @@ public class TPSBuffer {
         TPSBuffer b6 = new TPSBuffer("A0000000030000");
         b6.dump();
 
+        TPSBuffer empty = new TPSBuffer();
+
+        int emptySize = empty.size();
+        System.out.println("empty buffer size: " + emptySize);
+
     }
 
 }
diff --git a/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java b/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java
index 036c44c..c6e7cf7 100644
--- a/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java
+++ b/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java
@@ -85,6 +85,7 @@ public class TPSMessage {
     public static final String INFO_NAME = "next_task_name";
     public static final String REQUIRED_PARAMETER_NAME = "required_parameter";
     public static final String PARAMETER_NAME = "parameter";
+    public static final String STATUS_UPDATE_EXTENSION_NAME = "statusUpdate";
 
     private Map<String, String> map = new LinkedHashMap<String, String>();
 
@@ -466,6 +467,12 @@ public class TPSMessage {
         case MSG_STATUS_UPDATE_REQUEST:
             break;
         case MSG_STATUS_UPDATE_RESPONSE:
+
+            String statusValue = get(TPSMessage.STATUS_NAME);
+            CMS.debug("statusValue: " + statusValue);
+            int statusInt = Integer.parseInt(statusValue);
+            CMS.debug("statusInt: " + statusInt);
+            result = new StatusUpdateResponse(statusInt);
             break;
         case MSG_TOKEN_PDU_REQUEST:
             break;
@@ -474,6 +481,10 @@ public class TPSMessage {
             break;
         default:
             //Something was garbled with the message coming in
+            throw new IOException("TPSMessage.createMessage: Can't locate incoming TPS message!");
+        }
+
+        if(result == null) {
             throw new IOException("TPSMessage.createMessage: Can't create incoming TPS message!");
         }
 
diff --git a/base/tps-tomcat/shared/conf/CS.cfg.in b/base/tps-tomcat/shared/conf/CS.cfg.in
index 3898e98..78b48ab 100644
--- a/base/tps-tomcat/shared/conf/CS.cfg.in
+++ b/base/tps-tomcat/shared/conf/CS.cfg.in
@@ -269,7 +269,7 @@ op.enroll.soKey.auth.enable=true
 op.enroll.soKey.auth.id=ldap2
 op.enroll.soKey.cardmgr_instance=A0000000030000
 op.enroll.soKey.issuerinfo.enable=true
-op.enroll.soKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/cgi-bin/so/index.cgi
+op.enroll.soKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
 op.enroll.soKey.keyGen.encryption.ca.conn=ca1
 op.enroll.soKey.keyGen.encryption.ca.profileId=caTokenUserEncryptionKeyEnrollment
 op.enroll.soKey.keyGen.encryption.certAttrId=c2
@@ -643,7 +643,7 @@ op.enroll.userKey.auth.enable=true
 op.enroll.userKey.auth.id=ldap1
 op.enroll.userKey.cardmgr_instance=A0000000030000
 op.enroll.userKey.issuerinfo.enable=true
-op.enroll.userKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/cgi-bin/home/index.cgi
+op.enroll.userKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
 op.enroll.userKey.keyGen.encryption.ca.conn=ca1
 op.enroll.userKey.keyGen.encryption.ca.profileId=caTokenUserEncryptionKeyEnrollment
 op.enroll.userKey.keyGen.encryption.certAttrId=c2
@@ -1066,7 +1066,7 @@ op.format.soKey.auth.id=ldap2
 op.format.soKey.ca.conn=ca1
 op.format.soKey.cardmgr_instance=A0000000030000
 op.format.soKey.issuerinfo.enable=true
-op.format.soKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/cgi-bin/so/index.cgi
+op.format.soKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
 op.format.soKey.loginRequest.enable=true
 op.format.soKey.revokeCert=true
 op.format.soKey.tks.conn=tks1
@@ -1081,7 +1081,7 @@ op.format.soUserKey.auth.id=ldap1
 op.format.soUserKey.ca.conn=ca1
 op.format.soUserKey.cardmgr_instance=A0000000030000
 op.format.soUserKey.issuerinfo.enable=true
-op.format.soUserKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/cgi-bin/home/index.cgi
+op.format.soUserKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
 op.format.soUserKey.loginRequest.enable=false
 op.format.soUserKey.revokeCert=true
 op.format.soUserKey.tks.conn=tks1
@@ -1096,7 +1096,7 @@ op.format.tokenKey.auth.id=ldap1
 op.format.tokenKey.ca.conn=ca1
 op.format.tokenKey.cardmgr_instance=A0000000030000
 op.format.tokenKey.issuerinfo.enable=true
-op.format.tokenKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/cgi-bin/home/index.cgi
+op.format.tokenKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
 op.format.tokenKey.loginRequest.enable=true
 op.format.tokenKey.revokeCert=true
 op.format.tokenKey.tks.conn=tks1
@@ -1111,7 +1111,7 @@ op.format.userKey.auth.id=ldap1
 op.format.userKey.ca.conn=ca1
 op.format.userKey.cardmgr_instance=A0000000030000
 op.format.userKey.issuerinfo.enable=true
-op.format.userKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/cgi-bin/home/index.cgi
+op.format.userKey.issuerinfo.value=http://[PKI_HOSTNAME]:[PKI_UNSECURE_PORT]/tps/phoneHome
 op.format.userKey.loginRequest.enable=true
 op.format.userKey.revokeCert=true
 op.format.userKey.tks.conn=tks1
diff --git a/base/tps-tomcat/shared/conf/phoneHome.xml b/base/tps-tomcat/shared/conf/phoneHome.xml
index c5f29dc..442959f 100644
--- a/base/tps-tomcat/shared/conf/phoneHome.xml
+++ b/base/tps-tomcat/shared/conf/phoneHome.xml
@@ -1,20 +1,11 @@
 <ServiceInfo>
-<IssuerName>
-Fedora Project
+<IssuerName>FedoraProject</IssuerName>
 </IssuerName>
 <Services>
-<Operation>
-https://[PKI_HOSTNAME]:[PKI_SECURE_PORT]/tps/tps
-</Operation>
-<UI>
-</UI>
-<EnrolledTokenBrowserURL>
-http://fedoraproject.org
-</EnrolledTokenBrowserURL>
-<EnrolledTokenURL>
-</EnrolledTokenURL>
-<TokenType>
-userKey
-</TokenType>
+<Operation>https://[PKI_HOSTNAME]:[PKI_SECURE_PORT]/tps/tps</Operation>
+<UI></UI>
+<EnrolledTokenBrowserURL>http://fedoraproject.org</EnrolledTokenBrowserURL>
+<EnrolledTokenURL></EnrolledTokenURL>
+<TokenType>userKey</TokenType>
 </Services>
 </ServiceInfo>
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSPhoneHome.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSPhoneHome.java
index e34b849..e0b3b6b 100644
--- a/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSPhoneHome.java
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSPhoneHome.java
@@ -11,6 +11,8 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.dogtagpki.tps.main.TPSBuffer;
+
 import com.netscape.certsrv.apps.CMS;
 
 public class TPSPhoneHome extends HttpServlet {
@@ -47,8 +49,13 @@ public class TPSPhoneHome extends HttpServlet {
             buf = new BufferedInputStream(input);
 
             int readBytes = 0;
-            while ((readBytes = buf.read()) != -1)
+            TPSBuffer readData = new TPSBuffer();
+            while ((readBytes = buf.read()) != -1) {
                 stream.write(readBytes);
+                readData.add((byte) readBytes);
+            }
+
+            CMS.debug("TPSPhoneHome.renderPhoneHome: data: " + readData.toHexString());
 
         } catch (IOException e) {
             CMS.debug("TPSPhoneHome.renderPhoneHome: Error encountered:  " + e);
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSSession.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSSession.java
index 32741c6..31b6c41 100644
--- a/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSSession.java
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSSession.java
@@ -77,7 +77,7 @@ public class TPSSession {
     }
 
     public void process() throws IOException {
-        EndOp.TPSStatus status = EndOp.TPSStatus.STATUS_ERROR_BAD_STATUS;
+        EndOp.TPSStatus status = EndOp.TPSStatus.STATUS_NO_ERROR;
         CMS.debug("In TPSSession.process()");
 
         TPSMessage firstMsg = read();
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/channel/SecureChannel.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/channel/SecureChannel.java
index e2976ca..22ee968 100644
--- a/base/tps-tomcat/src/org/dogtagpki/server/tps/channel/SecureChannel.java
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/channel/SecureChannel.java
@@ -25,6 +25,10 @@ import org.dogtagpki.tps.apdu.APDUResponse;
 import org.dogtagpki.tps.apdu.DeleteFileAPDU;
 import org.dogtagpki.tps.apdu.ExternalAuthenticateAPDU;
 import org.dogtagpki.tps.apdu.ExternalAuthenticateAPDU.SecurityLevel;
+import org.dogtagpki.tps.apdu.InstallAppletAPDU;
+import org.dogtagpki.tps.apdu.InstallLoadAPDU;
+import org.dogtagpki.tps.apdu.LoadFileAPDU;
+import org.dogtagpki.tps.apdu.SetIssuerInfoAPDU;
 import org.dogtagpki.tps.main.TPSBuffer;
 import org.dogtagpki.tps.main.TPSException;
 import org.dogtagpki.tps.main.Util;
@@ -171,6 +175,205 @@ public class SecureChannel {
 
     }
 
+    // Begin process of loading applet onto token.
+    public void installLoad(TPSBuffer packageAID, TPSBuffer sdAID, int fileLength) throws TPSException, IOException {
+
+        CMS.debug("SecureChannel.installLoad: entering ...");
+
+        if (packageAID == null || sdAID == null || fileLength <= 0) {
+            throw new TPSException("SecureChannel.insallLoad bad input parameters!",
+                    TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+        }
+
+        InstallLoadAPDU install = new InstallLoadAPDU(packageAID, sdAID, fileLength);
+
+        CMS.debug("SecureChannel.installLoad: Pre computed apdu: " + install.getEncoding().toHexString());
+
+        computeAPDU(install);
+
+        APDUResponse response = processor.handleAPDURequest(install);
+
+        if (!response.checkResult()) {
+            throw new TPSException("SecureChannel.installLoad. Failed to perform installLoad operation.",
+                    TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+        }
+
+    }
+
+    //Actually load applet file onto the token.
+
+    public void loadFile(TPSBuffer programFile, int blockSize, int startProgress, int endProgress) throws TPSException,
+            IOException {
+        CMS.debug("SecureChannel.loadFile entering...");
+
+        if (programFile == null || blockSize <= 0) {
+            throw new TPSException("ScureChannel.loadFile. Bad input data.", TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+        }
+
+        TPSBuffer length = null;
+
+        TPSBuffer tag = new TPSBuffer(1, (byte) 0xC4);
+
+        int progSize = programFile.size();
+
+        if (progSize < 128) {
+            length = new TPSBuffer(1, (byte) progSize);
+        } else if (progSize <= 255) {
+            length = new TPSBuffer(1, (byte) 0x81);
+            length.add((byte) progSize);
+        } else {
+            length = new TPSBuffer(1, (byte) 0x82);
+            length.add((byte) ((progSize >> 8) & 0xff));
+            length.add((byte) (progSize & 0xff));
+
+        }
+
+        TPSBuffer tbsProgramFile = new TPSBuffer(tag);
+        tbsProgramFile.add(length);
+        tbsProgramFile.add(programFile);
+
+        int totalLen = tbsProgramFile.size();
+        int sizeToSend = totalLen;
+
+        int finalBlockSize = 0;
+        float progressBlockSize = 0;
+
+        if (secLevel == SecurityLevel.SECURE_MSG_MAC_ENC) {
+            // need leave room for possible encryption padding
+            finalBlockSize = blockSize - 0x10;
+        } else {
+            finalBlockSize = blockSize - 8;
+        }
+
+        //rough number is good enough
+        int numLoops = sizeToSend / blockSize;
+
+        if (numLoops == 0) { // We have bogus data here. Good bye.
+            throw new TPSException("SecureChannel.loadFile. Bad input data.", TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+        }
+        progressBlockSize = (float) (endProgress - startProgress) / numLoops;
+
+        int count = 0;
+        byte refControl = 0x00;
+
+        do {
+            if (sizeToSend < finalBlockSize) {
+                finalBlockSize = sizeToSend;
+                refControl = (byte) 0x80;
+
+            }
+
+            CMS.debug("SecureChannel.loadFile: taking data substring from: " + (totalLen - sizeToSend) + " size: "
+                    + finalBlockSize + " to: " + ((totalLen - sizeToSend) + finalBlockSize));
+
+            TPSBuffer piece = tbsProgramFile.substr(totalLen - sizeToSend, finalBlockSize);
+
+            CMS.debug("SecureChannel.loadFile: attempting to send piece: " + sizeToSend);
+
+            loadFileSegment(refControl, count, piece);
+
+            if (processor.requiresStatusUpdate()) {
+                processor.statusUpdate(startProgress + (int) (count * progressBlockSize), "PROGRESS_APPLET_BLOCK");
+            }
+
+            sizeToSend -= finalBlockSize;
+
+            count++;
+
+        } while (sizeToSend > 0);
+
+    }
+
+    //Load one piece of the applet file onto the token.
+    private void loadFileSegment(byte refControl, int count, TPSBuffer piece) throws TPSException, IOException {
+
+        if (piece == null || count < 0) {
+            throw new TPSException("SecureChannel.loadFileSegment: invalid input data.",
+                    TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+        }
+
+        LoadFileAPDU loadFile = new LoadFileAPDU(refControl, (byte) count, piece);
+
+        computeAPDU(loadFile);
+
+        APDUResponse response = processor.handleAPDURequest(loadFile);
+
+        if (!response.checkResult()) {
+            throw new TPSException(
+                    "SecureChannel.loadFileSegment. Failed to perform loadFileSegmentInstallLoad operation.",
+                    TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+        }
+
+    }
+
+    // Kick off the applet loading process.
+    public void installApplet(TPSBuffer netkeyPAIDBuff, TPSBuffer netkeyAIDBuff, byte appPrivileges,
+            int channelInstanceSize,
+            int channelAppletMemSize) throws TPSException, IOException {
+
+        CMS.debug("SecureChannel.installApplet: entering...");
+
+        // Would be tough to put a check on the various input sizes, let the applet
+        // decide if the values are appropriate for channelInstanceSize and channelAppletMemSize
+
+        if (netkeyPAIDBuff == null || netkeyAIDBuff == null || channelInstanceSize < 0 || channelAppletMemSize < 0) {
+            throw new TPSException("SecureChannel.installApplet. Invalid input parameters!",
+                    TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+
+        }
+
+        InstallAppletAPDU install = new InstallAppletAPDU(netkeyPAIDBuff, netkeyAIDBuff, appPrivileges,
+                channelInstanceSize, channelAppletMemSize);
+
+        computeAPDU(install);
+
+        APDUResponse response = processor.handleAPDURequest(install);
+
+        if (!response.checkResult()) {
+            throw new TPSException("SecureChannel.installApplett. Failed installApplet operation.",
+                    TPSStatus.STATUS_ERROR_SECURE_CHANNEL);
+        }
+
+    }
+
+    // Burn the phone home URL into the token.
+    public void setIssuerInfo(TPSBuffer issuerInfoBuff) throws TPSException, IOException {
+        CMS.debug("SecureChannel.setIssuerInfo entering...");
+
+        final int finalIssuerLength = 224;
+        final int approxMinUrlSize = 5;
+
+        if (issuerInfoBuff == null || issuerInfoBuff.size() < approxMinUrlSize) {
+            throw new TPSException("SecureChannel.setIssuerInfo: Invalid input data.",
+                    TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+        }
+
+        int issuerLen = issuerInfoBuff.size();
+
+        int paddingLen = finalIssuerLength - issuerLen;
+
+        TPSBuffer paddingBuff = new TPSBuffer(paddingLen, (byte) 0x0);
+
+        TPSBuffer finalIssuerBuff = new TPSBuffer(issuerInfoBuff);
+
+        finalIssuerBuff.add(paddingBuff);
+
+        CMS.debug("finalIssuerBuff len: " + finalIssuerBuff.size() + " issuerInfo: " + finalIssuerBuff.toString());
+        SetIssuerInfoAPDU setIssuer = new SetIssuerInfoAPDU((byte) 0x0, (byte) 0x0, finalIssuerBuff);
+
+        computeAPDU(setIssuer);
+
+        APDUResponse response = processor.handleAPDURequest(setIssuer);
+
+        if (!response.checkResult()) {
+            throw new TPSException("SecureChannel.setIssuerInfo. Failed to set issuer info!",
+                    TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+        }
+
+        CMS.debug("SecureChannel.setIssuerInfo: leaving...");
+
+    }
+
     public TPSBuffer getKeyDiversificationData() {
         return keyDiversificationData;
     }
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/engine/TPSEngine.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/engine/TPSEngine.java
index ab422df..b4a8aee 100644
--- a/base/tps-tomcat/src/org/dogtagpki/server/tps/engine/TPSEngine.java
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/engine/TPSEngine.java
@@ -83,6 +83,8 @@ public class TPSEngine {
     public static final String CFG_CHANNEL_DEFKEY_VERSION = "channel.defKeyVersion";
     public static final String CFG_CHANNEL_APPLET_MEMORY_SIZE = "channel.appletMemorySize";
     public static final String CFG_CHANNEL_DEFKEY_INDEX = "channel.defKeyIndex";
+    public static final String CFG_ISSUER_INFO_ENABLE = "issuerinfo.enable";
+    public static final String CFG_ISSUER_INFO_VALUE = "issuerinfo.value";
 
     /* default values */
     public static final String CFG_DEF_CARDMGR_INSTANCE_AID = "A0000000030000";
@@ -94,9 +96,10 @@ public class TPSEngine {
     public static final String CFG_ENABLED = "Enabled";
 
     public static final int CFG_CHANNEL_DEF_BLOCK_SIZE = 242;
-    public static final int CFG_CHANNEL_DEF_INSTANCE_SIZE = 1800;
+    public static final int CFG_CHANNEL_DEF_INSTANCE_SIZE = 18000;
     public static final int CFG_CHANNEL_DEF_APPLET_MEMORY_SIZE = 5000;
 
+
     /* External reg values */
 
     public static final String CFG_EXTERNAL_REG = "externalReg";
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/processor/TPSProcessor.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
index 68bd497..f054b7e 100644
--- a/base/tps-tomcat/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/processor/TPSProcessor.java
@@ -42,6 +42,7 @@ import org.dogtagpki.tps.main.TPSBuffer;
 import org.dogtagpki.tps.main.TPSException;
 import org.dogtagpki.tps.msg.BeginOp;
 import org.dogtagpki.tps.msg.EndOp.TPSStatus;
+import org.dogtagpki.tps.msg.StatusUpdateRequest;
 import org.dogtagpki.tps.msg.TokenPDURequest;
 import org.dogtagpki.tps.msg.TokenPDUResponse;
 import org.mozilla.jss.CryptoManager.NotInitializedException;
@@ -76,8 +77,7 @@ public class TPSProcessor {
 
     private String currentTokenOperation;
 
-
-
+    private BeginOp beginMsg;
 
     public TPSProcessor(TPSSession session) {
         setSession(session);
@@ -98,6 +98,14 @@ public class TPSProcessor {
         return session;
     }
 
+    protected void setBeginMessage(BeginOp msg) {
+        beginMsg = msg;
+    }
+
+    public BeginOp getBeginMessage() {
+        return beginMsg;
+    }
+
     protected void setSelectedTokenType(String theTokenType) {
 
         if (theTokenType == null) {
@@ -443,12 +451,10 @@ public class TPSProcessor {
         return channel;
     }
 
-    protected String upgradeApplet(String operation, String new_version, SecurityLevel securityLevel,
+    protected void upgradeApplet(String operation, String new_version, SecurityLevel securityLevel,
             Map<String, String> extensions, String connId, int startProgress, int endProgress) throws IOException,
             TPSException {
 
-        String newVersion = null;
-        boolean appletUpgraded = false;
         String NetKeyAID = null;
         String NetKeyPAID = null;
         String CardMgrAID = null;
@@ -462,7 +468,8 @@ public class TPSProcessor {
                     TPSEngine.CFG_DEF_NETKEY_INSTANCE_AID);
             CMS.debug("In TPS_Processor.upgradeApplet. CardManagerAID: " + " NetKeyAID: " + NetKeyAID);
             NetKeyPAID = configStore.getString(TPSEngine.CFG_APPLET_NETKEY_FILE_AID, TPSEngine.CFG_DEF_NETKEY_FILE_AID);
-            CardMgrAID = configStore.getString(TPSEngine.CFG_APPLET_CARDMGR_INSTANCE_AID,TPSEngine.CFG_DEF_CARDMGR_INSTANCE_AID);
+            CardMgrAID = configStore.getString(TPSEngine.CFG_APPLET_CARDMGR_INSTANCE_AID,
+                    TPSEngine.CFG_DEF_CARDMGR_INSTANCE_AID);
 
         } catch (EBaseException e1) {
             CMS.debug("TPS_Processor.upgradeApplet: Internal Error obtaining mandatory config values. Error: " + e1);
@@ -474,8 +481,6 @@ public class TPSProcessor {
         TPSBuffer netkeyPAIDBuff = new TPSBuffer(NetKeyPAID);
         TPSBuffer cardMgrAIDBuff = new TPSBuffer(CardMgrAID);
 
-        //Not all of these used yet, but will be
-        //ToDo
         int channelBlockSize = getChannelBlockSize();
         int channelInstanceSize = getChannelInstanceSize();
         int channelAppletMemSize = getAppletMemorySize();
@@ -493,9 +498,6 @@ public class TPSProcessor {
 
         CMS.debug("TPSProcessor.upgradeApplet: targe applet file name: " + appletFilePath);
 
-        //Not ready to use this yet.
-        //ToDo
-
         appletData = getAppletFileData(appletFilePath);
 
         APDUResponse select = selectApplet((byte) 0x04, (byte) 0x00, cardMgrAIDBuff);
@@ -511,15 +513,26 @@ public class TPSProcessor {
         channel.deleteFileX(netkeyPAIDBuff);
 
         // Next step will be to load the applet file to token.
-        // ToDo:
 
-        //ToDo actually finish this later.
-        if (appletUpgraded == false) {
-            throw new TPSException("TPSProcessor.upgradeApplet: Error upgrading applet",
+        TPSBuffer empty = new TPSBuffer();
+
+        channel.installLoad(netkeyPAIDBuff, empty, appletData.length);
+
+        TPSBuffer appletDataBuff = new TPSBuffer(appletData);
+
+        channel.loadFile(appletDataBuff, channelBlockSize, startProgress, endProgress);
+
+        channel.installApplet(netkeyPAIDBuff, netkeyAIDBuff, (byte) 0, channelInstanceSize, channelAppletMemSize);
+
+        //Now select our new applet
+
+        select = selectApplet((byte) 0x04, (byte) 0x00, netkeyAIDBuff);
+
+        if (!select.checkResult()) {
+            throw new TPSException("TPSProcessor.upgradeApplet: Cannot select newly created applet!",
                     TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
         }
 
-        return newVersion;
     }
 
     protected byte[] getAppletFileData(String appletFilePath) throws IOException, TPSException {
@@ -548,7 +561,7 @@ public class TPSProcessor {
         return contents;
     }
 
-    protected void format(BeginOp message) throws TPSException, IOException {
+    protected void format() throws TPSException, IOException {
 
         IConfigStore configStore = CMS.getConfigStore();
 
@@ -632,7 +645,7 @@ public class TPSProcessor {
         }
 
         String tokenType = getTokenType(TPSEngine.OP_FORMAT_PREFIX, major_version, minor_version, cuid, msn,
-                message.getExtensions());
+                beginMsg.getExtensions());
 
         CMS.debug("TPS_Processor.format: calculated tokenType: " + tokenType);
 
@@ -665,11 +678,67 @@ public class TPSProcessor {
 
         String tksConnId = getTKSConnectorID();
 
-        String newKeyVersion = upgradeApplet(TPSEngine.OP_FORMAT_PREFIX, appletRequiredVersion, secLevel,
-                message.getExtensions(), tksConnId,
+        upgradeApplet(TPSEngine.OP_FORMAT_PREFIX, appletRequiredVersion, secLevel,
+                beginMsg.getExtensions(), tksConnId,
                 10, 90);
 
-        CMS.debug("TPSProcessor.format: upgraded aplet version: " + newKeyVersion);
+        CMS.debug("TPSProcessor.format: Completed applet upgrade.");
+
+        // Add issuer info to the token
+
+        if (checkIssuerInfoEnabled()) {
+
+            int defKeyIndex = getChannelDefKeyIndex();
+            int defKeyVersion = getChannelDefKeyVersion();
+
+            SecureChannel channel = setupSecureChannel((byte) defKeyVersion, (byte) defKeyIndex, secLevel, tksConnId);
+
+            channel.externalAuthenticate();
+
+            String issuer = getIssuerInfoValue();
+
+            // We know this better be ASCII value URL.
+            byte[] issuer_bytes = issuer.getBytes("US-ASCII");
+            TPSBuffer issuerInfoBuff = new TPSBuffer(issuer_bytes);
+
+            channel.setIssuerInfo(issuerInfoBuff);
+
+        }
+
+        if (requiresStatusUpdate()) {
+            statusUpdate(100, "PROGRESS_DONE");
+        }
+
+        //ToDo:  Symmetric Key Changeover
+
+        // ToDo: Update Token DB
+
+        // ToDo:  Revoke certificates
+
+    }
+
+    protected String getIssuerInfoValue() throws TPSException {
+        IConfigStore configStore = CMS.getConfigStore();
+        String info = null;
+
+        String config = "op." + currentTokenOperation + "." + selectedTokenType + "." + TPSEngine.CFG_ISSUER_INFO_VALUE;
+
+        CMS.debug("TPSProcessor.getIssuerInfoValue: config: " + config);
+        try {
+            info = configStore.getString(config, null);
+        } catch (EBaseException e) {
+            throw new TPSException("TPSProcessor.getIssuerInfoValue: Internal error finding config value.");
+
+        }
+
+        if (info == null) {
+            throw new TPSException("TPSProcessor.getIssuerInfoValue: Can't find issuer info value in the config.",
+                    TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+        }
+
+        CMS.debug("TPSProcessor.getIssuerInfoValue: returning: " + info);
+
+        return info;
     }
 
     void checkProfileStateOK() throws TPSException {
@@ -694,6 +763,32 @@ public class TPSProcessor {
 
     }
 
+    protected boolean checkIssuerInfoEnabled() throws TPSException {
+
+        CMS.debug("TPSProcessor.checkIssuerEnabled entering...");
+
+        IConfigStore configStore = CMS.getConfigStore();
+
+        String issuerEnabledConfig = "op." + currentTokenOperation + "." + selectedTokenType + "."
+                + TPSEngine.CFG_ISSUER_INFO_ENABLE;
+
+        CMS.debug("TPSProcessor.checkIssuerEnabled config to check: " + issuerEnabledConfig);
+
+        boolean issuerInfoEnabled = false;
+
+        try {
+            issuerInfoEnabled = configStore.getBoolean(issuerEnabledConfig, false);
+        } catch (EBaseException e) {
+            //Default TPSException will return a "contact admin" error code.
+            throw new TPSException(
+                    "TPSProcessor.checkIssuerInfo: internal error in getting value from config.");
+        }
+
+        CMS.debug("TPSProcessor.checkIssuerEnabled returning: " + issuerInfoEnabled);
+        return issuerInfoEnabled;
+
+    }
+
     boolean checkServerSideKeyGen(String connId) throws TPSException {
 
         boolean result;
@@ -790,7 +885,6 @@ public class TPSProcessor {
 
         CMS.debug("TPSProcessor.getTKSConectorID: returning: " + id);
 
-
         return id;
     }
 
@@ -978,7 +1072,27 @@ public class TPSProcessor {
     }
 
     public void process(BeginOp beginMsg) throws TPSException, IOException {
-        format(beginMsg);
+
+        if (beginMsg == null) {
+            throw new TPSException("TPSProcessor.process: invalid input data, not beginMsg provided.",
+                    TPSStatus.STATUS_ERROR_UPGRADE_APPLET);
+        }
+        setBeginMessage(beginMsg);
+
+        format();
+    }
+
+    public void statusUpdate(int status, String info) throws IOException {
+
+        CMS.debug("In statusUpdate status: " + " info: " + info);
+
+        StatusUpdateRequest statusUpdate = new StatusUpdateRequest(status, info);
+        session.write(statusUpdate);
+
+        //We don't really care about the response, just that we get it.
+
+        session.read();
+
     }
 
     /* Return calculated token profile type.
@@ -1244,6 +1358,22 @@ public class TPSProcessor {
 
     }
 
+    // Do the incoming extensions support status update?
+    public boolean requiresStatusUpdate() {
+
+        boolean result = false;
+
+        // We can't get here without a begin message established.
+        String update = getBeginMessage().getExtension(BeginOp.STATUS_UPDATE_EXTENSION_NAME);
+
+        if (update != null && update.equals("true")) {
+            result = true;
+        }
+
+        return result;
+
+    }
+
     public static void main(String[] args) {
     }
 
-- 
1.8.3.1

