diff --git a/doc/CS.cfg b/doc/CS.cfg
index 686b282..a698662 100755
--- a/doc/CS.cfg
+++ b/doc/CS.cfg
@@ -102,7 +102,7 @@ logging.audit.level=10
 logging.audit.logSigning=false
 logging.audit.signedAuditCertNickname=auditSigningCert cert-[INSTANCE_ID]
 logging.audit.selected.events=AUTHZ_SUCCESS,AUTHZ_FAIL,AUTH_FAIL,AUTH_SUCCESS,ROLE_ASSUME,ENROLLMENT,PIN_RESET,FORMAT,CONFIG,CONFIG_ROLE,CONFIG_TOKEN,CONFIG_PROFILE,CONFIG_AUDIT,APPLET_UPGRADE,KEY_CHANGEOVER,RENEWAL,CIMC_CERT_VERIFICATION
-logging.audit.selectable.events=AUTHZ_SUCCESS,AUTHZ_FAIL,AUTH_FAIL,AUTH_SUCCESS,ROLE_ASSUME,ENROLLMENT,PIN_RESET,FORMAT,CONFIG,CONFIG_ROLE,CONFIG_TOKEN,CONFIG_PROFILE,CONFIG_AUDIT,APPLET_UPGRADE,KEY_CHANGEOVER,RENEWAL,CIMC_CERT_VERIFICATION
+logging.audit.selectable.events=AUTHZ_SUCCESS,AUTHZ_FAIL,AUTH_FAIL,AUTH_SUCCESS,ROLE_ASSUME,ENROLLMENT,PIN_RESET,FORMAT,CONFIG,CONFIG_ROLE,CONFIG_TOKEN,CONFIG_PROFILE,CONFIG_AUDIT,APPLET_UPGRADE,KEY_CHANGEOVER,RENEWAL,CIMC_CERT_VERIFICATION,KEY_SANITY_CHECK,TOKENDB_UPDATE
 logging.audit.nonselectable.events=AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,LOGGING_SIGNED_AUDIT_SIGNING
 logging.audit.buffer.size=512
 logging.audit.flush.interval=5
@@ -743,6 +743,12 @@ op.enroll.userKey._088=#                                  recover last for
 op.enroll.userKey._089=#                                  encryption cert.
 op.enroll.userKey._090=#########################################
 op.enroll.allowUnknownToken=true
+op.enroll.userKey.cuidMustMatchKDD=true
+op.enroll.userKey.enableBoundedGPKeyVersion=true
+op.enroll.userKey.minimumGPKeyVersion=01
+op.enroll.userKey.maximumGPKeyVersion=FF
+op.enroll.userKey.rollbackKeyVersionOnPutKeyFailure=false
+op.enroll.userKey.validateCardKeyInfoAgainstTokenDB=true
 op.enroll.userKey.temporaryToken.tokenType=userKeyTemporary
 op.enroll.userKey.keyGen.recovery.destroyed.keyType.num=2
 op.enroll.userKey.keyGen.recovery.destroyed.keyType.value.0=signing
@@ -884,6 +890,12 @@ op.enroll.userKeyTemporary.keyGen.encryption.recovery.onHold.revokeCert.reason=0
 op.enroll.userKey.keyGen.encryption.serverKeygen.enable=[SERVER_KEYGEN]
 op.enroll.userKey.keyGen.encryption.serverKeygen.drm.conn=drm1
 op.enroll.userKey.keyGen.encryption.serverKeygen.archive=true
+op.enroll.userKeyTemporary.cuidMustMatchKDD=true
+op.enroll.userKeyTemporary.enableBoundedGPKeyVersion=true
+op.enroll.userKeyTemporary.minimumGPKeyVersion=01
+op.enroll.userKeyTemporary.maximumGPKeyVersion=FF
+op.enroll.userKeyTemporary.rollbackKeyVersionOnPutKeyFailure=false
+op.enroll.userKeyTemporary.validateCardKeyInfoAgainstTokenDB=true
 op.enroll.userKeyTemporary.keyGen.encryption.serverKeygen.enable=true
 op.enroll.userKeyTemporary.keyGen.encryption.serverKeygen.drm.conn=drm1
 op.enroll.userKeyTemporary.keyGen.encryption.serverKeygen.archive=true
@@ -1062,6 +1074,12 @@ op.enroll.userKey.renewal.signing.ca.conn=ca1
 op.enroll.userKey.renewal.encryption.ca.conn=ca1
 op.enroll.userKey.renewal.signing.ca.profileId=caTokenUserSigningKeyRenewal
 op.enroll.userKey.renewal.encryption.ca.profileId=caTokenUserEncryptionKeyRenewal
+op.enroll.soKey.cuidMustMatchKDD=true
+op.enroll.soKey.enableBoundedGPKeyVersion=true
+op.enroll.soKey.minimumGPKeyVersion=01
+op.enroll.soKey.maximumGPKeyVersion=FF
+op.enroll.soKey.rollbackKeyVersionOnPutKeyFailure=false
+op.enroll.soKey.validateCardKeyInfoAgainstTokenDB=true
 op.enroll.soKey.temporaryToken.tokenType=soKeyTemporary
 op.enroll.soKey.keyGen.recovery.destroyed.keyType.num=2
 op.enroll.soKey.keyGen.recovery.destroyed.keyType.value.0=signing
@@ -1203,6 +1221,12 @@ op.enroll.soKeyTemporary.keyGen.encryption.recovery.onHold.revokeCert.reason=0
 op.enroll.soKey.keyGen.encryption.serverKeygen.enable=[SERVER_KEYGEN]
 op.enroll.soKey.keyGen.encryption.serverKeygen.drm.conn=drm1
 op.enroll.soKey.keyGen.encryption.serverKeygen.archive=true
+op.enroll.soKeyTemporary.cuidMustMatchKDD=true
+op.enroll.soKeyTemporary.enableBoundedGPKeyVersion=true
+op.enroll.soKeyTemporary.minimumGPKeyVersion=01
+op.enroll.soKeyTemporary.maximumGPKeyVersion=FF
+op.enroll.soKeyTemporary.rollbackKeyVersionOnPutKeyFailure=false
+op.enroll.soKeyTemporary.validateCardKeyInfoAgainstTokenDB=true
 op.enroll.soKeyTemporary.keyGen.encryption.serverKeygen.enable=true
 op.enroll.soKeyTemporary.keyGen.encryption.serverKeygen.drm.conn=drm1
 op.enroll.soKeyTemporary.keyGen.encryption.serverKeygen.archive=true
@@ -1797,6 +1821,12 @@ op.pinReset._015=#
 op.pinReset._016=# - N/A for HouseKey
 op.pinReset._017=# - N/A for HouseKey with Legacy Applet
 op.pinReset._018=#########################################
+op.pinReset.userKey.cuidMustMatchKDD=true
+op.pinReset.userKey.enableBoundedGPKeyVersion=true
+op.pinReset.userKey.minimumGPKeyVersion=01
+op.pinReset.userKey.maximumGPKeyVersion=FF
+op.pinReset.userKey.rollbackKeyVersionOnPutKeyFailure=false
+op.pinReset.userKey.validateCardKeyInfoAgainstTokenDB=true
 op.pinReset.userKey.update.applet.emptyToken.enable=true
 op.pinReset.userKey.update.applet.enable=false
 op.pinReset.userKey.update.applet.requiredVersion=1.4.5265a65e
@@ -1836,6 +1866,12 @@ op.format._007=# - applicable to HouseKey
 op.format._008=# - applicable to HouseKey with Legacy Applet
 op.format._009=#########################################
 op.format.allowUnknownToken=true
+op.format.soCleanUserToken.cuidMustMatchKDD=true
+op.format.soCleanUserToken.enableBoundedGPKeyVersion=true
+op.format.soCleanUserToken.minimumGPKeyVersion=01
+op.format.soCleanUserToken.maximumGPKeyVersion=FF
+op.format.soCleanUserToken.rollbackKeyVersionOnPutKeyFailure=false
+op.format.soCleanUserToken.validateCardKeyInfoAgainstTokenDB=true
 op.format.soCleanUserToken.update.applet.emptyToken.enable=true
 op.format.soCleanUserToken.update.applet.requiredVersion=1.4.5265a65e
 op.format.soCleanUserToken.update.applet.directory=[TPS_DIR]/applets
@@ -1851,6 +1887,12 @@ op.format.soCleanUserToken.auth.id=ldap1
 op.format.soCleanUserToken.auth.enable=false
 op.format.soCleanUserToken.issuerinfo.enable=true
 op.format.soCleanUserToken.issuerinfo.value=
+op.format.soCleanSOToken.cuidMustMatchKDD=true
+op.format.soCleanSOToken.enableBoundedGPKeyVersion=true
+op.format.soCleanSOToken.minimumGPKeyVersion=01
+op.format.soCleanSOToken.maximumGPKeyVersion=FF
+op.format.soCleanSOToken.rollbackKeyVersionOnPutKeyFailure=false
+op.format.soCleanSOToken.validateCardKeyInfoAgainstTokenDB=true
 op.format.soCleanSOToken.update.applet.emptyToken.enable=true
 op.format.soCleanSOToken.update.applet.requiredVersion=1.4.5265a65e
 op.format.soCleanSOToken.update.applet.directory=[TPS_DIR]/applets
@@ -1866,6 +1908,12 @@ op.format.soCleanSOToken.auth.id=ldap1
 op.format.soCleanSOToken.auth.enable=false
 op.format.soCleanSOToken.issuerinfo.enable=true
 op.format.soCleanSOToken.issuerinfo.value=
+op.format.cleanToken.cuidMustMatchKDD=true
+op.format.cleanToken.enableBoundedGPKeyVersion=true
+op.format.cleanToken.minimumGPKeyVersion=01
+op.format.cleanToken.maximumGPKeyVersion=FF
+op.format.cleanToken.rollbackKeyVersionOnPutKeyFailure=false
+op.format.cleanToken.validateCardKeyInfoAgainstTokenDB=true
 op.format.cleanToken.update.applet.emptyToken.enable=true
 op.format.cleanToken.update.applet.requiredVersion=1.4.5265a65e
 op.format.cleanToken.update.applet.directory=[TPS_DIR]/applets
@@ -1881,6 +1929,12 @@ op.format.cleanToken.auth.id=ldap1
 op.format.cleanToken.auth.enable=false
 op.format.cleanToken.issuerinfo.enable=true
 op.format.cleanToken.issuerinfo.value=
+op.format.soUserKey.cuidMustMatchKDD=true
+op.format.soUserKey.enableBoundedGPKeyVersion=true
+op.format.soUserKey.minimumGPKeyVersion=01
+op.format.soUserKey.maximumGPKeyVersion=FF
+op.format.soUserKey.rollbackKeyVersionOnPutKeyFailure=false
+op.format.soUserKey.validateCardKeyInfoAgainstTokenDB=true
 op.format.soUserKey.update.applet.emptyToken.enable=true
 op.format.soUserKey.update.applet.requiredVersion=1.4.5265a65e
 op.format.soUserKey.update.applet.directory=[TPS_DIR]/applets
@@ -1896,6 +1950,12 @@ op.format.soUserKey.auth.id=ldap1
 op.format.soUserKey.auth.enable=false
 op.format.soUserKey.issuerinfo.enable=true
 op.format.soUserKey.issuerinfo.value=http://[SERVER_NAME]:[PORT]/cgi-bin/home/index.cgi
+op.format.soKey.cuidMustMatchKDD=true
+op.format.soKey.enableBoundedGPKeyVersion=true
+op.format.soKey.minimumGPKeyVersion=01
+op.format.soKey.maximumGPKeyVersion=FF
+op.format.soKey.rollbackKeyVersionOnPutKeyFailure=false
+op.format.soKey.validateCardKeyInfoAgainstTokenDB=true
 op.format.soKey.update.applet.emptyToken.enable=true
 op.format.soKey.update.applet.requiredVersion=1.4.5265a65e
 op.format.soKey.update.applet.directory=[TPS_DIR]/applets
@@ -1911,6 +1971,12 @@ op.format.soKey.auth.id=ldap2
 op.format.soKey.auth.enable=true
 op.format.soKey.issuerinfo.enable=true
 op.format.soKey.issuerinfo.value=http://[SERVER_NAME]:[PORT]/cgi-bin/so/index.cgi
+op.format.userKey.cuidMustMatchKDD=true
+op.format.userKey.enableBoundedGPKeyVersion=true
+op.format.userKey.minimumGPKeyVersion=01
+op.format.userKey.maximumGPKeyVersion=FF
+op.format.userKey.rollbackKeyVersionOnPutKeyFailure=false
+op.format.userKey.validateCardKeyInfoAgainstTokenDB=true
 op.format.userKey.update.applet.emptyToken.enable=true
 op.format.userKey.update.applet.requiredVersion=1.4.5265a65e
 op.format.userKey.update.applet.directory=[TPS_DIR]/applets
@@ -1926,6 +1992,12 @@ op.format.userKey.auth.id=ldap1
 op.format.userKey.auth.enable=true
 op.format.userKey.issuerinfo.enable=true
 op.format.userKey.issuerinfo.value=http://[SERVER_NAME]:[PORT]/cgi-bin/home/index.cgi
+op.format.tokenKey.cuidMustMatchKDD=true
+op.format.tokenKey.enableBoundedGPKeyVersion=true
+op.format.tokenKey.minimumGPKeyVersion=01
+op.format.tokenKey.maximumGPKeyVersion=FF
+op.format.tokenKey.rollbackKeyVersionOnPutKeyFailure=false
+op.format.tokenKey.validateCardKeyInfoAgainstTokenDB=true
 op.format.tokenKey.update.applet.emptyToken.enable=true
 op.format.tokenKey.update.applet.requiredVersion=1.4.5265a65e
 op.format.tokenKey.update.applet.directory=[TPS_DIR]/applets
diff --git a/src/engine/RA.cpp b/src/engine/RA.cpp
index 0f87117..83590e3 100755
--- a/src/engine/RA.cpp
+++ b/src/engine/RA.cpp
@@ -1575,6 +1575,7 @@ void RA::ServerSideKeyGen(RA_Session *session, const char* cuid,
 
 PK11SymKey *RA::ComputeSessionKey(RA_Session *session,
                                   Buffer &CUID,
+                                  Buffer &KDD,
                                   Buffer &keyInfo,
                                   Buffer &card_challenge,
                                   Buffer &host_challenge,
@@ -1597,6 +1598,7 @@ PK11SymKey *RA::ComputeSessionKey(RA_Session *session,
     char * hostc = NULL;
     char * cardCrypto = NULL;
     char * cuid = NULL;
+    char * kdd = NULL;
     char * keyinfo =  NULL;
     PSHttpResponse *response = NULL;
     HttpConnection *tksConn = NULL;
@@ -1627,6 +1629,7 @@ PK11SymKey *RA::ComputeSessionKey(RA_Session *session,
         hostc = Util::SpecialURLEncode(host_challenge);
         cardCrypto = Util::SpecialURLEncode(card_cryptogram);
         cuid = Util::SpecialURLEncode(CUID);
+        kdd = Util::SpecialURLEncode(KDD);
         keyinfo = Util::SpecialURLEncode(keyInfo);
 
         if ((cardc == NULL) || (hostc == NULL) || (cardCrypto == NULL) ||
@@ -1634,8 +1637,8 @@ PK11SymKey *RA::ComputeSessionKey(RA_Session *session,
 	    goto loser;
 
         PR_snprintf((char *)body, MAX_BODY_LEN, 
-          "serversideKeygen=%s&CUID=%s&card_challenge=%s&host_challenge=%s&KeyInfo=%s&card_cryptogram=%s&keySet=%s", serverKeygen? "true":"false", cuid, 
-          cardc, hostc, keyinfo, cardCrypto, keySet);
+          "serversideKeygen=%s&CUID=%s&KDD=%s&card_challenge=%s&host_challenge=%s&KeyInfo=%s&card_cryptogram=%s&keySet=%s", serverKeygen? "true":"false", cuid,
+          kdd, cardc, hostc, keyinfo, cardCrypto, keySet);
 
         PR_snprintf((char *)configname, 256, "conn.%s.servlet.computeSessionKey", connId);
         const char *servletID = GetConfigStore()->GetConfigAsString(configname);
@@ -1859,6 +1862,10 @@ PK11SymKey *RA::ComputeSessionKey(RA_Session *session,
         PR_Free( cuid );
         cuid = NULL;
     }
+    if( kdd != NULL ){
+        PR_Free( kdd );
+        kdd = NULL;
+    }
     if( keyinfo != NULL ) {
         PR_Free( keyinfo );
         keyinfo = NULL;
@@ -2972,6 +2979,53 @@ TPS_PUBLIC char *RA::ra_get_cert_issuer(LDAPMessage *entry) {
     return get_cert_issuer(entry);
 }
 
+/**
+ *
+ *  Returns a string representation of the key info value from TokenDB, if it exists, otherwise returns NULL
+ *  cuid is the token cuid for key info
+ *
+ */
+
+/**
+ *
+ * PAS Modification
+ * Introduced this function to wrap the get_key_info(LDAPMessage) function in tus_db.c
+ *
+ */
+
+
+TPS_PUBLIC char *RA::ra_get_key_info(char *cuid){
+
+    LDAPMessage *result = NULL;
+    LDAPMessage *e = NULL;
+//    char **v = NULL;
+    char *ret = NULL;
+    int rc = -1;
+
+    if (cuid != NULL && PL_strlen(cuid) > 0) {
+        if ((rc = find_tus_db_entry (cuid, 0, &result)) == LDAP_SUCCESS) {
+            e = get_first_entry (result);
+            if (e != NULL) {
+
+                ret = get_key_info(e);
+
+
+                if(ret == NULL){
+                    RA::Debug("RA::ra_get_key_info", "keyinfo for %s is NULL!", cuid);
+                }
+
+            }
+            if( result != NULL ) {
+                free_results( result );
+                result = NULL;
+            }
+        }
+    }
+    return ret;
+
+}
+
+
 TPS_PUBLIC int RA::ra_tus_has_active_tokens(char *userid) {
     return tus_has_active_tokens(userid);
 }
diff --git a/src/include/engine/RA.h b/src/include/engine/RA.h
index aad9568..e67bbf9 100755
--- a/src/include/engine/RA.h
+++ b/src/include/engine/RA.h
@@ -114,6 +114,7 @@ class RA
 
  	  static PK11SymKey *ComputeSessionKey(RA_Session *session,
                                            Buffer &CUID,
+                                           Buffer &KDD,
                                            Buffer &keyinfo,
                                            Buffer &card_challenge,
                                            Buffer &host_challenge,
@@ -197,6 +198,7 @@ class RA
       TPS_PUBLIC static char *ra_get_cert_cn(LDAPMessage *entry);
       TPS_PUBLIC static char *ra_get_cert_status(LDAPMessage *entry);
       TPS_PUBLIC static char *ra_get_cert_type(LDAPMessage *entry);
+      TPS_PUBLIC static char *ra_get_key_info(char * cuid);
       TPS_PUBLIC static char *ra_get_cert_serial(LDAPMessage *entry);
       TPS_PUBLIC static char *ra_get_cert_issuer(LDAPMessage *entry);
           TPS_PUBLIC static int ra_delete_certificate_entry(LDAPMessage *entry);
diff --git a/src/include/engine/audit.h b/src/include/engine/audit.h
index f8b50de..1fa8c14 100755
--- a/src/include/engine/audit.h
+++ b/src/include/engine/audit.h
@@ -58,6 +58,19 @@
 // op is either "revoke" or "unrevoke"
 #define AUDIT_MSG_CERT_STATUS_CHANGE "[SubjectID=%s][Outcome=%s][op=%s][Serial=%s][CA_ID=%s] %s" 
 
+/**
+ * PAS Modification
+ * for EV_KEY_SANITY_CHECK; note: "op" is operation such as "format," "enrollment," "pinReset," "renewal"
+ */
+#define AUDIT_MSG_KEY_SANITY_CHECK "[CUID=%s][KDD=%s][Outcome=%s][op=%s][TokenKeyVersion=%s][NewKeyVersion=%s][TokenDBKeyVersion=%s] %s"
+
+/**
+ * PAS Modification
+ * for EV_TOKENDB_UPDATE
+ */
+#define AUDIT_MSG_TOKENDB_UPDATE "[USERID=%s] [CUID=%s] [AppletVersion=%s] [KeyVersion=%s] [State=%s] [Reason=%s] [TokenType=%s] %s"
+
+
 /*
  * Audit events definitions
  */
@@ -83,6 +96,14 @@
 
 #define EV_RENEWAL "RENEWAL"
 
+/**
+ * PAS Modification
+ * Added new event macro for GP KEY SANITY CHECKS
+ * Added new event macro for TOKENDB_UPDATE
+ */
+#define EV_KEY_SANITY_CHECK "KEY_SANITY_CHECK"
+#define EV_TOKENDB_UPDATE "TOKENDB_UPDATE"
+
 // authentication for both user login for token ops and role user login (this is different from EV_AUTHZ which is for role authorization)
 #define EV_AUTH_SUCCESS "AUTH_SUCCESS"
 #define EV_AUTH_FAIL "AUTH_FAIL"
diff --git a/src/include/processor/RA_Enroll_Processor.h b/src/include/processor/RA_Enroll_Processor.h
index 02cd0c9..d093aa8 100755
--- a/src/include/processor/RA_Enroll_Processor.h
+++ b/src/include/processor/RA_Enroll_Processor.h
@@ -245,6 +245,7 @@ class RA_Enroll_Processor : public RA_Processor
 				RA_Session *a_session,
 				NameValueSet *a_extensions,
 				char *a_cuid,
+				Buffer &CUID,
 				const char *a_tokenType,
 				char *&o_current_applet_on_token,
 				BYTE &o_major_version,
@@ -259,6 +260,7 @@ class RA_Enroll_Processor : public RA_Processor
 				RA_Session *session,
 				NameValueSet* extensions,
 				char *cuid,
+				Buffer &CUID,
 				const char *tokenType,
 				char *msn,
                                 const char* applet_version, 
diff --git a/src/include/processor/RA_Processor.h b/src/include/processor/RA_Processor.h
index 50a51ee..e9598a5 100755
--- a/src/include/processor/RA_Processor.h
+++ b/src/include/processor/RA_Processor.h
@@ -126,9 +126,15 @@ class RA_Processor
 
 		Buffer *GetAppletVersion(RA_Session *session);
 
-		Secure_Channel *SetupSecureChannel(RA_Session *session, BYTE key_version, BYTE key_index, const char *connId);
+		/**
+		 * PAS Modification
+		 * Added Buffer CUID parameter
+		 * Added const char *opPrefix
+		 * Added const char *tokenType
+		 */
+		Secure_Channel *SetupSecureChannel(RA_Session *session, BYTE key_version, BYTE key_index, const char *connId, Buffer &CUID, const char *opPrefix, const char *tokenType);
 		Secure_Channel *SetupSecureChannel(RA_Session *session,
-				BYTE key_version, BYTE key_index, SecurityLevel security_level, const char *connId);
+				BYTE key_version, BYTE key_index, SecurityLevel security_level, const char *connId, Buffer &CUID, const char *opPrefix, const char *tokenType);
 
 		SecureId *RequestSecureId(RA_Session *session);
 
@@ -136,16 +142,21 @@ class RA_Processor
 
 		char *RequestASQ(RA_Session *session, char *question);
 
-		int EncryptData(Buffer &cuid, Buffer &versionID, Buffer &in, Buffer &out, const char *connid);
+		/**
+		 * PAS Modification
+		 * Added KDD buffer parameter
+		 */
+		int EncryptData(Buffer &cuid, Buffer &kdd, Buffer &versionID, Buffer &in, Buffer &out, const char *connid);
                 
 		int ComputeRandomData(Buffer &data_out, int dataSize,  const char *connid);
 
 		int CreateKeySetData(
-			Buffer &cuid, 
+			Buffer &CUID,
+			Buffer &KDD,
 			Buffer &versionID, 
 			Buffer &NewMasterVer, 
 			Buffer &out, 
-			const char *connid);
+			const char *connid, const char *opPrefix, const char *tokenType);
 
 		bool GetTokenType(
 			const char *prefix, 
@@ -163,6 +174,10 @@ class RA_Processor
 
 		int SelectApplet(RA_Session *session, BYTE p1, BYTE p2, Buffer *aid);
 
+		/**
+         * PAS Modification
+         * Added Buffer CUID parameter
+         */
 		int UpgradeApplet(
 				RA_Session *session, 
                 char *prefix,
@@ -174,7 +189,8 @@ class RA_Processor
 				const char *connid, 
 				NameValueSet *extensions,
 				int start_progress, int end_progress,
-                                char **key_version);
+                                char **key_version,
+                                Buffer &CUID);
 
 		int UpgradeKey(RA_Session *session, BYTE major_version, BYTE minor_version, int new_version);
 
@@ -191,13 +207,24 @@ class RA_Processor
 				unsigned short keyCreationPermissions,
 				unsigned short pinCreationPermissions);
 
+		/**
+		 * PAS Modification
+		 *
+		 * Added Buffer card_cuid
+		 * Added const char *opPrefix
+		 * Added const char *tokenType
+		 */
+
 		Secure_Channel *GenerateSecureChannel(
 				RA_Session *session, const char *connid,
+				Buffer &card_cuid,
 				Buffer &card_diversification_data,
 				Buffer &card_key_data,
 				Buffer &card_challenge,
 				Buffer &card_cryptogram,
-				Buffer &host_challenge);
+				Buffer &host_challenge,
+				const char *opPrefix,
+				const char *tokenType);
                 AuthenticationEntry *GetAuthenticationEntry(
                                 const char * a_prefix,
                                 const char * a_configname,
@@ -251,6 +278,22 @@ class RA_Processor
                                 char *tokenType, char *userid, RA_Status &status );
 		int IsTokenDisabledByTus(Secure_Channel *channel);
 
+		/**
+		 * PAS Modification
+		 *
+		 * New functions to enforce GP sanity checks
+		 */
+		int checkCUIDMatchesKDD(Buffer &bufCUID, Buffer &bufKDD,
+		                        const char *pcharOpPrefix);
+
+		int checkCardGPKeyVersionIsInRange(Buffer &bufCUID, Buffer &bufKDD,
+		                                   Buffer &bufCardSuppliedKeyInfo,
+		                                   const char *pcharOpPrefix, const char *pcharTokenType);
+
+		int checkCardGPKeyVersionMatchesTokenDB(Buffer &bufCUID, Buffer &bufKDD,
+		                                        Buffer &bufCardSuppliedKeyInfo, const char *pcharOpPrefix,
+		                                        const char *pcharTokenType);
+
                 int totalAvailableMemory;
                 int totalFreeMemory;
 };
diff --git a/src/main/Buffer.cpp b/src/main/Buffer.cpp
index 2a547fe..4cbc99f 100755
--- a/src/main/Buffer.cpp
+++ b/src/main/Buffer.cpp
@@ -228,8 +228,18 @@ Buffer::toHex()
     unsigned int i;
 
     char *hx =  (char *)PR_Malloc(1024);
+
     if (hx == NULL)
 	    return NULL;
+
+    /**
+     * PAS Modification
+     * Insert \0 to hx[0] to protect against empty buffers
+     *
+     */
+
+    hx[0] = '\0';
+
     for( i=0; i < len; ++i ) {
       PR_snprintf(hx+(i*2),1024-(i*2),"%02x", (unsigned char)buf[i]);
     }
diff --git a/src/processor/RA_Enroll_Processor.cpp b/src/processor/RA_Enroll_Processor.cpp
index be73127..935a010 100755
--- a/src/processor/RA_Enroll_Processor.cpp
+++ b/src/processor/RA_Enroll_Processor.cpp
@@ -1275,6 +1275,7 @@ bool RA_Enroll_Processor::CheckAndUpgradeApplet(
 		RA_Session *a_session,
 		NameValueSet *a_extensions,
 		char *a_cuid,
+		Buffer &CUID,
 		const char *a_tokenType,
 		char *&o_current_applet_on_token,
 		BYTE &o_major_version,
@@ -1336,7 +1337,7 @@ bool RA_Enroll_Processor::CheckAndUpgradeApplet(
 				connid, a_extensions, 
 				5, 
 				12, 
-                                keyVersion) != 1) {
+                                keyVersion, CUID) != 1) {
 
 				RA::Debug(FN, "applet upgrade failed");
 				/**
@@ -1423,6 +1424,7 @@ bool RA_Enroll_Processor::CheckAndUpgradeSymKeys(
 	RA_Session *a_session,
 	NameValueSet* a_extensions,
 	char *a_cuid,
+	Buffer &CUID,
 	const char *a_tokenType,
 	char *a_msn,
         const char *a_applet_version,
@@ -1482,7 +1484,7 @@ bool RA_Enroll_Processor::CheckAndUpgradeSymKeys(
         int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0);
 		o_channel = SetupSecureChannel(a_session, 
 				requiredV,
-				defKeyIndex  /* default key index */, tksid);
+				defKeyIndex  /* default key index */, tksid, CUID, OP_PREFIX, a_tokenType);
 
 		// If that failed, we need to find out what version of keys 
 		// are on the token
@@ -1515,7 +1517,7 @@ bool RA_Enroll_Processor::CheckAndUpgradeSymKeys(
         int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0);
 			o_channel = SetupSecureChannel(a_session, 
 					defKeyVer,  /* default key version */
-					defKeyIndex  /* default key index */, tksid);
+					defKeyIndex  /* default key index */, tksid, CUID, OP_PREFIX, a_tokenType);
 
 			if (o_channel == NULL) {
                                 PR_snprintf(audit_msg, 512, "enrollment processing, failed to create secure channel"); 
@@ -1556,10 +1558,11 @@ bool RA_Enroll_Processor::CheckAndUpgradeSymKeys(
 			connid = RA::GetConfigStore()->GetConfigAsString(configname);
 
 			rc = CreateKeySetData(
+			        CUID,
 					o_channel->GetKeyDiversificationData(), 
 					curKeyInfo,
 					newVersion,
-					key_data_set, connid);
+					key_data_set, connid, OP_PREFIX, a_tokenType);
 			if (rc != 1) {
 				RA::Error(FN, "failed to create new key set");
 				o_status = STATUS_ERROR_CREATE_CARDMGR;
@@ -1596,6 +1599,11 @@ bool RA_Enroll_Processor::CheckAndUpgradeSymKeys(
                             newVer[0] = 0;
                         }
 
+                        /**
+                         * PAS Modification
+                         * Removed this check of return code and replaced with additional logging and token activity database update
+                         */
+                        /**
                         if (rc!=0) {
                             RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER,
                               a_userid != NULL ? a_userid : "", a_cuid != NULL ? a_cuid : "",  a_msn != NULL ? a_msn : "", "Failure", "enrollment",
@@ -1618,6 +1626,64 @@ bool RA_Enroll_Processor::CheckAndUpgradeSymKeys(
                               a_applet_version != NULL ? a_applet_version : "", curVer, newVer,
                               "key changeover");
                         }
+                        */
+
+
+
+                        /**
+                         * PAS Modification
+                         * Previously the return code from put keys was not evaluated or recorded on failure
+                         * Prior comment block identified the necessity of evaluation and audit logging on failure
+                         */
+
+                        if(rc < 0){
+                            RA::Debug("RA_Processor::Format", "Failed to Put Keys for token %s", a_cuid);
+                            o_status = STATUS_ERROR_KEY_CHANGE_OVER;
+
+                            RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER,
+                                                a_userid != NULL ? a_userid : "", a_cuid != NULL ? a_cuid : "", a_msn != NULL ? a_msn : "", "failure", "format",
+                                                        a_applet_version != NULL ? a_applet_version : "", curKeyInfoStr, newVersionStr,
+                                                                "failed to put new GP key set to token");
+
+                            // update activity database with entry about put key event
+                            RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, OP_PREFIX, "failure", "Failed to send new GP Key Set to token", (a_userid == NULL) ? "" : a_userid, a_tokenType);
+
+                            /**
+                             * PAS Modification
+                             * New configuration value to permit rollback of KeyInfo in Token DB, default disabled
+                             *
+                             */
+                            snprintf((char *)configname, 256, "%s.%s.rollbackKeyVersionOnPutKeyFailure", OP_PREFIX, a_tokenType);
+                            if(RA::GetConfigStore()->GetConfigAsBool(configname, 0)){
+                                rc = RA::tdb_update(NULL, a_cuid, NULL, curKeyInfoStr, NULL, NULL, NULL);
+                                if (rc < 0) {
+                                    RA::Debug(LL_PER_PDU, "RA_Processor::Format","Failed to update the token database with current key version");
+                                    o_status = STATUS_ERROR_UPDATE_TOKENDB_FAILED;  //clobbers the previous failure message :-(
+
+                                    RA::Audit(EV_TOKENDB_UPDATE, AUDIT_MSG_TOKENDB_UPDATE, "", a_cuid, "", curKeyInfoStr, "", "", "", "failed to update tokenDB to current key version");
+
+                                    goto loser;
+                                }else{
+
+                                    RA::Debug(LL_PER_PDU, "RA_Processor::Format","Successfully updated the token database with current key version");
+                                    RA::Audit(EV_TOKENDB_UPDATE, AUDIT_MSG_TOKENDB_UPDATE, "", a_cuid, "", curKeyInfoStr, "", "", "", "successfully updated tokenDB to current key version");
+
+                                }
+                            }
+                            goto loser;
+                        }else {
+
+
+                            RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER,
+                                                a_userid != NULL ? a_userid : "", a_cuid != NULL ? a_cuid : "", a_msn != NULL ? a_msn : "", "success", "format",
+                                                        a_applet_version != NULL ? a_applet_version : "", curKeyInfoStr, newVersionStr,
+                                                                "put new GP key set to token");
+
+                            RA::tdb_activity(a_session->GetRemoteIP(), a_cuid, OP_PREFIX, "success", "Sent new GP Key Set to token", (a_userid == NULL) ? "" : a_userid, a_tokenType);
+
+                        }
+
+
 
 			/**
 			 * Re-select the Applet.
@@ -1630,7 +1696,7 @@ bool RA_Enroll_Processor::CheckAndUpgradeSymKeys(
 
 			// Make a new secure channel with the new symmetric keys
 			o_channel = SetupSecureChannel(a_session, requiredV,
-					defKeyIndex  /* default key index */, tksid);
+					defKeyIndex  /* default key index */, tksid, CUID, OP_PREFIX, a_tokenType);
 			if (o_channel == NULL) {
 				RA::Error(FN, "failed to establish secure channel after reselect");
 				o_status = STATUS_ERROR_CREATE_CARDMGR;
@@ -1661,7 +1727,7 @@ bool RA_Enroll_Processor::CheckAndUpgradeSymKeys(
         int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0);
 		o_channel = SetupSecureChannel(a_session, 
 				defKeyVer,
-				defKeyIndex  /* default key index */, tksid);
+				defKeyIndex  /* default key index */, tksid, CUID, OP_PREFIX, a_tokenType);
 		r = true;	  // Sucess!!
                 RA::Audit(EV_ENROLLMENT, AUDIT_MSG_PROC,
                   a_userid, a_cuid, a_msn, "success", "enrollment", a_applet_version, 
@@ -2011,6 +2077,7 @@ TPS_PUBLIC RA_Status RA_Enroll_Processor::Process(RA_Session *session, NameValue
 		    session,
 		    extensions,
 		    cuid,
+		    token_cuid,
 		    tokenType,
 		    final_applet_version,
 		    app_major_version, app_minor_version,
@@ -2043,6 +2110,7 @@ TPS_PUBLIC RA_Status RA_Enroll_Processor::Process(RA_Session *session, NameValue
 		session,
 		extensions,
 		cuid,
+		token_cuid,
 		tokenType,
 		msn,
                 final_applet_version,
@@ -2197,7 +2265,7 @@ TPS_PUBLIC RA_Status RA_Enroll_Processor::Process(RA_Session *session, NameValue
     PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType);
     connid = RA::GetConfigStore()->GetConfigAsString(configname);
     /* wrap challenge with KEK key */
-    rc = EncryptData(kdd,
+    rc = EncryptData(token_cuid, kdd,
       channel->GetKeyInfoData(), *plaintext_challenge, *wrapped_challenge, connid);
     if (rc == -1) {
 	RA::Error("RA_Enroll_Processor::Process",
diff --git a/src/processor/RA_Pin_Reset_Processor.cpp b/src/processor/RA_Pin_Reset_Processor.cpp
index af341f0..18d74eb 100755
--- a/src/processor/RA_Pin_Reset_Processor.cpp
+++ b/src/processor/RA_Pin_Reset_Processor.cpp
@@ -354,7 +354,7 @@ if (isExternalReg) {
             PR_snprintf((char *)configname, 256, "%s.%s.tks.conn", OP_PREFIX, tokenType);
             connid = RA::GetConfigStore()->GetConfigAsString(configname);
             int upgrade_rc = UpgradeApplet(session, OP_PREFIX, (char*)tokenType, major_version, minor_version, 
-                expected_version, applet_dir, security_level, connid, extensions, 30, 70, &keyVersion);
+                expected_version, applet_dir, security_level, connid, extensions, 30, 70, &keyVersion, token_cuid);
 	    if (upgrade_rc != 1) {
                RA::Error("RA_Pin_Reset_Processor::Process", 
 			"upgrade failure");
@@ -410,14 +410,14 @@ if (isExternalReg) {
           channel = NULL;
       }
       channel = SetupSecureChannel(session, requiredVersion, 
-                  0x00  /* default key index */, connId);
+                  0x00  /* default key index */, connId, token_cuid, OP_PREFIX, tokenType);
       if (channel == NULL) {
 
         /* if version 0x02 key not found, create them */
         SelectApplet(session, 0x04, 0x00, CardManagerAID);
         channel = SetupSecureChannel(session,
                   0x00,  /* default key version */
-                  0x00  /* default key index */, connId);
+                  0x00  /* default key index */, connId, token_cuid, OP_PREFIX, tokenType);
 
         if (channel == NULL) {
             RA::Error("RA_Pin_Reset_Processor::Process", 
@@ -444,10 +444,11 @@ if (isExternalReg) {
         PR_snprintf((char *)configname,  256,"%s.%s.tks.conn", OP_PREFIX, tokenType);
         connid = RA::GetConfigStore()->GetConfigAsString(configname);
         rc = CreateKeySetData(
+             token_cuid,
              channel->GetKeyDiversificationData(),
              curKeyInfo,
              newVersion,
-             key_data_set, connid);
+             key_data_set, connid, OP_PREFIX, tokenType);
         if (rc != 1) {
             RA::Error("RA_Pin_Reset_Processor::Process",
                         "failed to create new key set");
@@ -480,13 +481,72 @@ if (isExternalReg) {
             newVer[0] = 0;
         }
 
+        /**
+         * PAS Modification
+         * Removed only audit log entry for put key failure and replaced with additional logging and token activity database update.  ABOVE ^^^
+         */
+
+        /**
         if (rc!=0) {
             RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER,
                 userid != NULL ? userid : "", cuid != NULL ? cuid : "", msn != NULL ? msn : "", "Failure", "pin_reset",
                 final_applet_version != NULL ? final_applet_version : "", curVer, newVer,
                 "key changeover failed");
         }
+         */
+
+        /**
+         * PAS Modification
+         * Previously the return code from put keys was not evaluated or recorded on failure
+         * Prior comment block identified the necessity of evaluation and audit logging on failure
+         */
+
+        if(rc < 0){
+            RA::Debug("RA_Processor::Format", "Failed to Put Keys for token %s", cuid);
+            status = STATUS_ERROR_KEY_CHANGE_OVER;
+
+            RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER,
+                                userid != NULL ? userid : "", cuid != NULL ? cuid : "", msn != NULL ? msn : "", "failure", "format",
+                                        final_applet_version != NULL ? final_applet_version : "", curKeyInfoStr, newVersionStr,
+                                                "failed to put new GP key set to token");
+
+            // update activity database with entry about put key event
+            RA::tdb_activity(session->GetRemoteIP(), cuid, OP_PREFIX, "failure", "Failed to send new GP Key Set to token", (userid == NULL) ? "" : userid, tokenType);
+
+            /**
+             * PAS Modification
+             * New configuration value to permit rollback of KeyInfo in Token DB, default disabled
+             *
+             */
+            snprintf((char *)configname, 256, "%s.%s.rollbackKeyVersionOnPutKeyFailure", OP_PREFIX, tokenType);
+            if(RA::GetConfigStore()->GetConfigAsBool(configname, 0)){
+                rc = RA::tdb_update(NULL, cuid, NULL, curKeyInfoStr, NULL, NULL, NULL);
+                if (rc < 0) {
+                    RA::Debug(LL_PER_PDU, "RA_Processor::Format","Failed to update the token database with current key version");
+                    status = STATUS_ERROR_UPDATE_TOKENDB_FAILED;  //clobbers the previous failure message :-(
+
+                    RA::Audit(EV_TOKENDB_UPDATE, AUDIT_MSG_TOKENDB_UPDATE, "", cuid, "", curKeyInfoStr, "", "", "", "failed to update tokenDB to current key version");
+
+                    goto loser;
+                }else{
 
+                    RA::Debug(LL_PER_PDU, "RA_Processor::Format","Successfully updated the token database with current key version");
+                    RA::Audit(EV_TOKENDB_UPDATE, AUDIT_MSG_TOKENDB_UPDATE, "", cuid, "", curKeyInfoStr, "", "", "", "successfully updated tokenDB to current key version");
+
+                }
+            }
+            goto loser;
+        }else {
+
+
+            RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER,
+                                userid != NULL ? userid : "", cuid != NULL ? cuid : "", msn != NULL ? msn : "", "success", "format",
+                                        final_applet_version != NULL ? final_applet_version : "", curKeyInfoStr, newVersionStr,
+                                                "put new GP key set to token");
+
+            RA::tdb_activity(session->GetRemoteIP(), cuid, OP_PREFIX, "success", "Sent new GP Key Set to token", (userid == NULL) ? "" : userid, tokenType);
+
+        }
          SelectApplet(session, 0x04, 0x00, NetKeyAID);
         PR_snprintf((char *)configname, 256, "%s.%s.update.symmetricKeys.requiredVersion", OP_PREFIX, tokenType);
         if( channel != NULL ) {
@@ -498,7 +558,7 @@ if (isExternalReg) {
         connId = RA::GetConfigStore()->GetConfigAsString(configname);
          channel = SetupSecureChannel(session, 
                   RA::GetConfigStore()->GetConfigAsInt(configname, 0x00),
-                  0x00  /* default key index */, connId);
+                  0x00  /* default key index */, connId, token_cuid, OP_PREFIX, tokenType);
          if (channel == NULL) {
             RA::Error("RA_Pin_Reset_Processor::Process", 
 			"setup secure channel failure");
@@ -522,7 +582,7 @@ if (isExternalReg) {
       }
       channel = SetupSecureChannel(session,
                   0x00,
-                  0x00  /* default key index */, connId);
+                  0x00  /* default key index */, connId, token_cuid, OP_PREFIX, tokenType);
     }
 
     /* we should have a good channel here */
diff --git a/src/processor/RA_Processor.cpp b/src/processor/RA_Processor.cpp
index 9393411..a8b7c77 100755
--- a/src/processor/RA_Processor.cpp
+++ b/src/processor/RA_Processor.cpp
@@ -97,6 +97,9 @@ extern "C"
 #endif
 #endif
 
+#define MAX_OP_PREFIX_LENGTH 50
+#define MAX_TOKEN_TYPE_LENGTH 50
+
 /**
  * Constructs a base processor.
  */
@@ -302,7 +305,7 @@ int RA_Processor::UpgradeApplet(RA_Session *session, char *prefix, char *tokenTy
 		NameValueSet *extensions,
 		int start_progress,
 		int end_progress, 
-                char **key_version)
+                char **key_version, Buffer &CUID)
 {
         Buffer *NetKeyAID = RA::GetConfigStore()->GetConfigAsBuffer(
 			RA::CFG_APPLET_NETKEY_INSTANCE_AID,
@@ -390,7 +393,7 @@ int RA_Processor::UpgradeApplet(RA_Session *session, char *prefix, char *tokenTy
     defKeyVer = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0);
     PR_snprintf((char *)configname, 256,"channel.defKeyIndex");
     defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0);
-	channel = SetupSecureChannel(session, defKeyVer, defKeyIndex, security_level, connid);
+	channel = SetupSecureChannel(session, defKeyVer, defKeyIndex, security_level, connid, CUID, prefix, tokenType);
 	if (channel == NULL) {
              RA::Error(LL_PER_PDU, "RA_Processor::UpgradeApplet", 
 		  "channel creation failure");
@@ -1395,11 +1398,19 @@ loser:
 /*
  * this one sets the security level
  */
+
+/**
+ * PAS Modification
+ *
+ * Added Buffer CUID
+ * Added const char *opPrefix
+ * Added const char *tokenType
+ */
 Secure_Channel *RA_Processor::SetupSecureChannel(RA_Session *session, 
      BYTE key_version, BYTE key_index, SecurityLevel security_level,
-     const char *connId)
+     const char *connId, Buffer &CUID, const char *opPrefix, const char *tokenType)
 {
-    Secure_Channel *channel = SetupSecureChannel(session, key_version, key_index, connId);
+    Secure_Channel *channel = SetupSecureChannel(session, key_version, key_index, connId, CUID, opPrefix, tokenType);
     RA::Debug(LL_PER_PDU, "RA_Processor::Setup_Secure_Channel","Resetting security level ...");
 
     /* Bugscape Bug #55774: Prevent NetKey RA from crashing . . . */
@@ -1534,8 +1545,16 @@ loser:
 /**
  * Setup secure channel between RA and the token.
  */
+
+/**
+ * PAS Modification
+ *
+ * Added Buffer CUID
+ * Added const char *opPrefix
+ * Added const char *tokenType
+ */
 Secure_Channel *RA_Processor::SetupSecureChannel(RA_Session *session, 
-     BYTE key_version, BYTE key_index, const char *connId)
+     BYTE key_version, BYTE key_index, const char *connId, Buffer &CUID, const char *opPrefix, const char *tokenType)
 {
     Secure_Channel *channel = NULL;
     APDU_Response *initialize_update_response = NULL;
@@ -1648,11 +1667,12 @@ Secure_Channel *RA_Processor::SetupSecureChannel(RA_Session *session,
 
     channel = GenerateSecureChannel(
         session, connId,
+        CUID,
         key_diversification_data,
         key_info_data,
         card_challenge,
         card_cryptogram,
-        host_challenge);
+        host_challenge, opPrefix, tokenType);
 
 loser:
     if( initialize_update_request_msg != NULL ) {
@@ -1853,11 +1873,14 @@ loser:
  */
 Secure_Channel *RA_Processor::GenerateSecureChannel(
     RA_Session *session, const char *connId,
-    Buffer &key_diversification_data, /* CUID */
+    Buffer &CUID, /* CUID */
+    Buffer &key_diversification_data, /* KDD */
     Buffer &key_info_data,
     Buffer &card_challenge,
     Buffer &card_cryptogram,
-    Buffer &host_challenge)
+    Buffer &host_challenge,
+    const char *opPrefix,
+    const char *tokenType)
 {
     PK11SymKey *session_key = NULL;
     Buffer *host_cryptogram = NULL;
@@ -1874,7 +1897,67 @@ Secure_Channel *RA_Processor::GenerateSecureChannel(
     char *kek_desKey_s = NULL;
     char *keycheck_s = NULL;
 
-    session_key = RA::ComputeSessionKey(session, key_diversification_data, 
+    /**
+     * PAS modification
+     * New configuration value to enable verification that the CUID matches the KDD, default disabled
+     * Return with NULL if CUID does not match KDD
+     */
+
+
+      PR_snprintf(configname, 256, "%s.%s.cuidMustMatchKDD", opPrefix, tokenType);
+      if(RA::GetConfigStore()->GetConfigAsBool(configname, 0)){
+          if(checkCUIDMatchesKDD(CUID, key_diversification_data, opPrefix) < 0){
+              return NULL;
+          }
+      }
+
+      /**
+       * PAS modification
+       * New configuration values to enforce a bound/range for GP key version for put key operation.
+       * Return with NULL if the cards current key version is not inside the GPKeyVersion range
+       */
+
+      PR_snprintf(configname, 256, "%s.%s.enableBoundedGPKeyVersion", opPrefix, tokenType);
+      if(RA::GetConfigStore()->GetConfigAsBool(configname, 1)){
+
+          if(checkCardGPKeyVersionIsInRange(CUID, key_diversification_data, key_info_data, opPrefix, tokenType) < 0){
+              return NULL;
+          }
+
+
+      }
+
+      /**
+       * PAS modification
+       * New configuration value to validate the KeyInfo value obtained from INITIALIZE UPDATE RESPONSE matches what is in the Token DB for a known token, default enabled
+       * Return with NULL if the KeyInfo value does not match what is in the Token DB
+       *
+       */
+
+
+      PR_snprintf(configname, 256, "%s.%s.validateCardKeyInfoAgainstTokenDB", opPrefix, tokenType);
+
+      if(RA::GetConfigStore()->GetConfigAsBool(configname, 1)){
+
+          if(checkCardGPKeyVersionMatchesTokenDB(CUID, key_diversification_data, key_info_data, opPrefix, tokenType) < 0){
+              return NULL;
+          }
+      }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    session_key = RA::ComputeSessionKey(session, CUID, key_diversification_data,
                                         key_info_data, card_challenge,
                                         host_challenge, &host_cryptogram, 
 		                                card_cryptogram, &enc_session_key,
@@ -1964,8 +2047,30 @@ Secure_Channel *RA_Processor::GenerateSecureChannel(
     return channel;
 } /* GenerateSecureChannel */
 
-int RA_Processor::CreateKeySetData(Buffer &CUID, Buffer &version, 
-  Buffer &NewMasterVer, Buffer &out, const char *connid)
+/**
+ *
+ * CreateKeySetData
+ * Try to create a new GP key set for the token
+ * This function can check that the CUID from GET DATA and KDD from INITIALIZE UPDATE RESPONSE are the same, by default this is disabled
+ * This function can check that the KeyInfo from INITIALIZE UPDATE RESPONSE matches the KeyInfo stored in the Token DB for a known token, by default this is enabled
+ * On successful key set creation, this function will update the Token DB with the new KeyInfo information for the token.
+ * If an entry in the database does not exist, the Token DB update function adds a new record.
+ * Only KeyInfo information is added or updated in this function
+ * Returns < 0 on failure for keyset creation or token DB update
+ *
+ */
+
+/**
+ * PAS modifications
+ * Added arguments opPrefix and tokenType to support per operation and per card configuration settings.
+ * Added argument KDD to fix communication semantics with TKS.  previously TKS received a CUID HTTP parameter which was actually the KDD.  This function now sends both CUID and KDD to TKS.
+ * New configuration value [opPrefix].[tokenType].cuidMustMatchKDD, default to false
+ * New configuration value [opPrefix].[tokenType].validateCardKeyInfoAgainstTokenDB, default to true
+ * New configuration value [opPrefix].[tokenType].enableBoundedGPKeyVersion, default to true
+ */
+
+int RA_Processor::CreateKeySetData(Buffer &CUID, Buffer &KDD, Buffer &version,
+  Buffer &NewMasterVer, Buffer &out, const char *connid, const char *opPrefix, const char *tokenType)
 {
     char body[5000];
     char configname[256];
@@ -1976,10 +2081,60 @@ int RA_Processor::CreateKeySetData(Buffer &CUID, Buffer &version,
         RA::Error(LL_PER_PDU, "RA_Processor::CreateKeySetData", "Failed to get TKSConnection %s", connid);
         return -1;
     } else {
+
+        /**
+         * PAS modification
+         * New configuration value to enable verification that the CUID matches the KDD, default disabled
+         * Return with -1 if CUID does not match KDD
+         */
+
+
+        PR_snprintf(configname, 256, "%s.%s.cuidMustMatchKDD", opPrefix, tokenType);
+        if(RA::GetConfigStore()->GetConfigAsBool(configname, 0)){
+            if(checkCUIDMatchesKDD(CUID, KDD, opPrefix) < 0){
+                return -1;
+            }
+        }
+
+        /**
+         * PAS modification
+         * New configuration values to enforce a bound/range for GP key version for put key operation.
+         * Return with -1 if the cards current key version is not inside the GPKeyVersion range
+         */
+
+        PR_snprintf(configname, 256, "%s.%s.enableBoundedGPKeyVersion", opPrefix, tokenType);
+        if(RA::GetConfigStore()->GetConfigAsBool(configname, 1)){
+
+            if(checkCardGPKeyVersionIsInRange(CUID, KDD, version, opPrefix, tokenType) < 0){
+                return -1;
+            }
+
+
+        }
+
+        /**
+         * PAS modification
+         * New configuration value to validate the KeyInfo value obtained from INITIALIZE UPDATE RESPONSE matches what is in the Token DB for a known token, default enabled
+         * Return with -1 if the KeyInfo value from KDD does not match what is in the Token DB
+         *
+         */
+
+
+        PR_snprintf(configname, 256, "%s.%s.validateCardKeyInfoAgainstTokenDB", opPrefix, tokenType);
+
+        if(RA::GetConfigStore()->GetConfigAsBool(configname, 1)){
+
+            if(checkCardGPKeyVersionMatchesTokenDB(CUID, KDD, version, opPrefix, tokenType) < 0){
+                return -1;
+            }
+        }
+
+
         // PRLock *tks_lock = RA::GetTKSLock();
         int tks_curr = RA::GetCurrentIndex(tksConn);
         int currRetries = 0;
         char *cuid = Util::SpecialURLEncode(CUID);
+        char *kdd = Util::SpecialURLEncode(KDD);
         char *versionID = Util::SpecialURLEncode(version);
         char *masterV = Util::SpecialURLEncode(NewMasterVer);
 
@@ -1987,7 +2142,7 @@ int RA_Processor::CreateKeySetData(Buffer &CUID, Buffer &version,
         const char *keySet = RA::GetConfigStore()->GetConfigAsString(configname);
 
         PR_snprintf((char *)body, 5000,
-           "newKeyInfo=%s&CUID=%s&KeyInfo=%s&keySet=%s", masterV, cuid, versionID,keySet);
+           "newKeyInfo=%s&CUID=%s&KDD=%s&KeyInfo=%s&keySet=%s", masterV, cuid, kdd, versionID, keySet);
 
         PR_snprintf((char *)configname, 256, "conn.%s.servlet.createKeySetData", connid);
         const char *servletID = RA::GetConfigStore()->GetConfigAsString(configname);
@@ -1996,6 +2151,10 @@ int RA_Processor::CreateKeySetData(Buffer &CUID, Buffer &version,
             PR_Free( cuid );
             cuid = NULL;
         }
+        if( kdd != NULL ){
+            PR_Free( kdd );
+            kdd = NULL;
+        }
         if( versionID != NULL ) {
             PR_Free( versionID );
             versionID = NULL;
@@ -2107,8 +2266,60 @@ int RA_Processor::CreateKeySetData(Buffer &CUID, Buffer &version,
 	if (tksConn != NULL) {
             RA::ReturnTKSConn(tksConn);
 	}
+
+
+    /**
+     * PAS modification
+     * If creating a new keyset is successful. Prior to returning, update the Token DB with the new KeyInfo data.
+     * The thought here is to record that TPS/TKS has generated cryptographic keys for a token and record this fact prior to sending the keys over the wire to the token
+     *
+     */
+
+
+    int rc = 0;
+
+    char *pcharCUID = Util::Buffer2String(CUID);
+
+    char *pcharNewMasterVersion = Util::Buffer2String(NewMasterVer);
+
+    rc = RA::tdb_update(NULL, pcharCUID, NULL, pcharNewMasterVersion, NULL, NULL, NULL);
+
+    RA::Audit(EV_TOKENDB_UPDATE, AUDIT_MSG_TOKENDB_UPDATE, "", pcharCUID, "", pcharNewMasterVersion, "", "", "", "successfully updated tokenDB to new key version");
+
+    if (rc < 0) {
+        RA::Debug(LL_PER_PDU, "RA_Processor::CreateKeySetData","Failed to update the token database with new key version");
+
+        RA::Audit(EV_TOKENDB_UPDATE, AUDIT_MSG_TOKENDB_UPDATE, "", pcharCUID, "", pcharNewMasterVersion, "", "", "", "failed to update tokenDB to new key version");
+
+        if( pcharNewMasterVersion != NULL){
+            PR_Free(pcharNewMasterVersion);
+            pcharNewMasterVersion = NULL;
+        }
+
+        if ( pcharCUID != NULL){
+            PR_Free(pcharCUID);
+            pcharCUID = NULL;
+        }
+
+        return -1;
+    }
+
+    if( pcharNewMasterVersion != NULL){
+        PR_Free(pcharNewMasterVersion);
+        pcharNewMasterVersion = NULL;
+    }
+
+    if ( pcharCUID != NULL){
+        PR_Free(pcharCUID);
+        pcharCUID = NULL;
+    }
+
+
+
         return 1;
     }
+
+    /**
         BYTE kek_key[] = {
                 0x40, 0x41, 0x42, 0x43,
                 0x44, 0x45, 0x46, 0x47,
@@ -2138,14 +2349,576 @@ int RA_Processor::CreateKeySetData(Buffer &CUID, Buffer &version,
 	if (tksConn != NULL) {
 		RA::ReturnTKSConn(tksConn);
 	}
+
+
+
+
    return 1;
+
+   */
+}
+
+
+/**
+ * PAS modification
+ * New function to enable verification that the CUID matches the KDD, default disabled
+ * Return with -1 if CUID does not match KDD, pcharOpPrefix is NULL, or pcharOpPrefix is character count is greater than 50
+ */
+int RA_Processor::checkCUIDMatchesKDD(Buffer &bufCUID, Buffer &bufKDD, const char* pcharOpPrefix){
+
+    char *pcharCUID = NULL;
+    char *pcharKDD = NULL;
+    char charArrayAuditMsg[500];
+
+
+    if(pcharOpPrefix == NULL){
+
+    	RA::Debug("RA_Processor::checkCUIDMatchesKDD", "Argument pcharOpPrefix is NULL.");
+
+    	return -1;
+
+    }
+
+
+    if(PL_strlen(pcharOpPrefix) > MAX_OP_PREFIX_LENGTH){
+
+ 	   RA::Debug("RA_Processor::checkCUIDMatchesKDD", "opPrefix is longer than 50 characters.");
+
+ 	   return -1;
+
+    }
+
+
+    if(bufCUID != bufKDD){
+
+        pcharCUID = Util::Buffer2String(bufCUID);
+        pcharKDD = Util::Buffer2String(bufKDD);
+
+        PR_snprintf(charArrayAuditMsg, 500, "CUID: %s does not equal KDD: %s", pcharCUID, pcharKDD);
+        RA::Debug("RA_Processor::checkCUIDMatchesKDD", charArrayAuditMsg);
+        RA::Audit(EV_KEY_SANITY_CHECK, AUDIT_MSG_KEY_SANITY_CHECK, pcharCUID, pcharKDD, "failure", pcharOpPrefix, "", "", "", charArrayAuditMsg);
+        RA::tdb_activity("", pcharCUID, pcharOpPrefix, "failure", charArrayAuditMsg, "", "");
+
+        if (pcharCUID != NULL){
+            PR_Free(pcharCUID);
+            pcharCUID = NULL;
+        }
+
+        if (pcharKDD != NULL){
+            PR_Free(pcharKDD);
+            pcharKDD = NULL;
+        }
+
+        return -1;
+
+    }
+
+    return 0;
+
+}
+
+/**
+ * PAS modification
+ * New function to validate the KeyInfo value obtained from INITIALIZE UPDATE RESPONSE matches what is in the Token DB for a known token
+ * Return with -1 if the KeyInfo value from KDD does not match what is in the Token DB
+ */
+int RA_Processor::checkCardGPKeyVersionMatchesTokenDB(Buffer &bufCUID, Buffer &bufKDD, Buffer &bufCardSuppliedKeyInfo, const char *pcharOpPrefix, const char *pcharTokenType){
+
+    char *pcharCardSuppliedKeyInfo = NULL;
+    char *pcharCUID = NULL;
+    char *pcharKDD = NULL;
+    char *pcharNewMasterVersion = NULL;
+    char *pcharCardDatabaseKeyInfo = NULL;
+    char charArrayAuditMsg[500];
+    Buffer *pbufCardDatabaseKeyInfo = NULL;
+
+
+    if(pcharOpPrefix == NULL){
+
+    	RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", "Argument pcharOpPrefix is NULL.");
+
+    	return -1;
+
+    }
+
+
+    if(PL_strlen(pcharOpPrefix) > MAX_OP_PREFIX_LENGTH){
+
+ 	   RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", "opPrefix is longer than 50 characters.");
+
+ 	   return -1;
+
+    }
+
+
+    if(pcharTokenType == NULL){
+
+    	RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", "Argument pcharTokenType is NULL.");
+
+    	return -1;
+
+    }
+
+   if(PL_strlen(pcharTokenType) > MAX_TOKEN_TYPE_LENGTH){
+
+	   RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", "TokenType is longer than 50 characters.  Check configuration file for token type %s", pcharTokenType);
+
+	   return -1;
+
+   }
+
+
+
+                pcharCUID = Util::Buffer2String(bufCUID);
+
+                if(RA::ra_is_token_present(pcharCUID)){ //is token present?
+
+                    if((pcharCardDatabaseKeyInfo = RA::ra_get_key_info(pcharCUID)) == NULL){ //get key info from database as char *
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", "RA::ra_get_key_info returned NULL for %s but %s is present in database", pcharCUID);
+                        RA::Audit(EV_KEY_SANITY_CHECK, AUDIT_MSG_KEY_SANITY_CHECK, pcharCUID, "", "failure", pcharOpPrefix, "", "", "", "RA::ra_get_key_info returned NULL but token CUID is present in database");
+
+
+                        if(pcharCUID != NULL)
+                            PR_Free(pcharCUID);
+                        pcharCUID = NULL;
+
+                        return -1;
+
+                    }
+
+
+                    if((pcharCardSuppliedKeyInfo = Util::Buffer2String(bufCardSuppliedKeyInfo)) == NULL){ //convert what was supplied from the card to a char * for printing to various log messages
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", "Converting cardSuppliedKeyInfo to char * failed");
+
+
+                        if(pcharCUID != NULL){
+                            PR_Free(pcharCUID);
+                            pcharCUID = NULL;
+                        }
+
+                        if(pcharCardDatabaseKeyInfo != NULL){
+                            PL_strfree(pcharCardDatabaseKeyInfo);
+                            pcharCardDatabaseKeyInfo = NULL;
+                        }
+
+                        return -1;
+
+                    }
+
+                    RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", "Card %s claims keyinfo of: %s, tokenDB has %s", pcharCUID, pcharCardSuppliedKeyInfo, pcharCardDatabaseKeyInfo);
+
+
+                    if((pbufCardDatabaseKeyInfo = Util::Str2Buf(pcharCardDatabaseKeyInfo)) == NULL){ //this uses hex2bin to convert a char * of hex values to a buffer
+
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", "Converting pcharCardDatabaseKeyInfo to buffer failed");
+
+                        if(pcharCUID != NULL){
+                            PR_Free(pcharCUID);
+                            pcharCUID = NULL;
+                        }
+
+                        if(pcharCardSuppliedKeyInfo != NULL){
+                            PR_Free(pcharCardSuppliedKeyInfo);
+                            pcharCardSuppliedKeyInfo = NULL;
+                        }
+
+                        if(pcharCardDatabaseKeyInfo != NULL){
+                            PL_strfree(pcharCardDatabaseKeyInfo);
+                            pcharCardDatabaseKeyInfo = NULL;
+                        }
+
+                        return -1;
+                    }
+
+
+
+
+
+                    if((*pbufCardDatabaseKeyInfo) != bufCardSuppliedKeyInfo){
+
+                        PR_snprintf(charArrayAuditMsg, 500, "Card claimed key info: %s does not match Card DB key info: %s", pcharCardSuppliedKeyInfo, pcharCardDatabaseKeyInfo);
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", charArrayAuditMsg);
+                        RA::Audit(EV_KEY_SANITY_CHECK, AUDIT_MSG_KEY_SANITY_CHECK, pcharCUID, "", "failure", pcharOpPrefix, pcharCardSuppliedKeyInfo, "", pcharCardDatabaseKeyInfo, charArrayAuditMsg);
+                        RA::tdb_activity("", pcharCUID, pcharOpPrefix, "failure", charArrayAuditMsg, "", pcharTokenType);
+
+
+                        if(pcharCUID != NULL){
+                            PR_Free(pcharCUID);
+                            pcharCUID = NULL;
+                        }
+
+                        if(pcharCardSuppliedKeyInfo != NULL){
+                            PR_Free(pcharCardSuppliedKeyInfo);
+                            pcharCardSuppliedKeyInfo = NULL;
+                        }
+
+                        if(pcharCardDatabaseKeyInfo != NULL){
+                            PL_strfree(pcharCardDatabaseKeyInfo);
+                            pcharCardDatabaseKeyInfo = NULL;
+                        }
+
+                        if(pbufCardDatabaseKeyInfo != NULL){
+                            delete pbufCardDatabaseKeyInfo;
+                            pbufCardDatabaseKeyInfo = NULL;
+                        }
+
+                        return -1;
+
+                    }else{
+
+
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionMatchesTokenDB", "Card %s claimed key info: %s matches tokenDB key info: %s", pcharCUID, pcharCardSuppliedKeyInfo, pcharCardDatabaseKeyInfo);
+                        RA::Audit(EV_KEY_SANITY_CHECK, AUDIT_MSG_KEY_SANITY_CHECK, pcharCUID, "", "success", pcharOpPrefix, pcharCardSuppliedKeyInfo, "", pcharCardDatabaseKeyInfo, "Card GP key info matches TokenDB GP key info.");
+
+
+
+                    }
+
+                    if(pcharCUID != NULL){
+                        PR_Free(pcharCUID);
+                        pcharCUID = NULL;
+                    }
+
+                    if(pcharCardSuppliedKeyInfo != NULL){
+                        PR_Free(pcharCardSuppliedKeyInfo);
+                        pcharCardSuppliedKeyInfo = NULL;
+                    }
+
+                    if(pcharCardDatabaseKeyInfo != NULL){
+                        PL_strfree(pcharCardDatabaseKeyInfo);
+                        pcharCardDatabaseKeyInfo = NULL;
+                    }
+
+                    if(pbufCardDatabaseKeyInfo != NULL){
+                        delete pbufCardDatabaseKeyInfo;
+                        pbufCardDatabaseKeyInfo = NULL;
+                    }
+
+
+                }
+
+                return 0;
+
+}
+
+/**
+ * PAS modificationconfiguration values
+ * New function to enforce a bound/range for GP key version.
+ * Return with -1 if the cards current key version is not inside the GPKeyVersion range, or on error
+ */
+int RA_Processor::checkCardGPKeyVersionIsInRange(Buffer &bufCUID, Buffer &bufKDD, Buffer &bufCardSuppliedKeyInfo, const char *pcharOpPrefix, const char *pcharTokenType){
+
+    char configname[256];
+    char charArrayAuditMsg[500];
+    char *pcharCardSuppliedKeyInfo = NULL;
+    char *pcharCUID = NULL;
+    char *pcharKDD = NULL;
+    char *pcharNewMasterVersion = NULL;
+    char *pcharCardDatabaseKeyInfo = NULL;
+    Buffer *pbufCfgMinGPKeyVersion = NULL;
+    Buffer *pbufCfgMaxGPKeyVersion = NULL;
+    Buffer *pbufCardDatabaseKeyInfo = NULL;
+    unsigned char charCfgMinGPKeyVersion;
+    unsigned char charCfgMaxGPKeyVersion;
+    unsigned char charCardGPKeyVersion;
+
+
+    if(pcharOpPrefix == NULL){
+
+    	RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", "Argument pcharOpPrefix is NULL.");
+
+    	return -1;
+
+    }
+
+
+    if(PL_strlen(pcharOpPrefix) > MAX_OP_PREFIX_LENGTH){
+
+ 	   RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", "opPrefix is longer than 50 characters.");
+
+ 	   return -1;
+
+    }
+
+
+    if(pcharTokenType == NULL){
+
+    	RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", "Argument pcharTokenType is NULL.");
+
+    	return -1;
+
+    }
+
+    if(PL_strlen(pcharTokenType) > MAX_TOKEN_TYPE_LENGTH){
+
+    	RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", "TokenType is longer than 50 characters.  Check configuration file for token type %s", pcharTokenType);
+
+    	return -1;
+
+    }
+
+
+
+                //read min/maxGPKeyVersion configuration value in as a buffer.  This supports defining key version values hex values to align with how key version is sent by cards.
+                PR_snprintf(configname, 256, "%s.%s.minimumGPKeyVersion", pcharOpPrefix, pcharTokenType);
+                pbufCfgMinGPKeyVersion = RA::GetConfigStore()->GetConfigAsBuffer(configname, "01");
+
+                PR_snprintf(configname, 256, "%s.%s.maximumGPKeyVersion", pcharOpPrefix, pcharTokenType);//a hack to support safenet's 0xFF initial key version
+                pbufCfgMaxGPKeyVersion = RA::GetConfigStore()->GetConfigAsBuffer(configname, "FF");
+
+                if(pbufCfgMinGPKeyVersion != NULL && pbufCfgMaxGPKeyVersion != NULL){
+
+                    if(pbufCfgMinGPKeyVersion->size() != 1){ //the buffer returned from the config file is larger than expected.  we expect [KeyVersion] only, so 1 byte
+
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", "minimumGPKeyVersion defined in %s.%s.minimumGPKeyVersion appears to be %i bytes, should be only 1 byte (2 asciihex characters)", pcharOpPrefix, pcharTokenType, pbufCfgMinGPKeyVersion->size());
+
+                        if (pbufCfgMinGPKeyVersion != NULL){
+                            delete pbufCfgMinGPKeyVersion;
+                            pbufCfgMinGPKeyVersion = NULL;
+                        }
+
+                        if (pbufCfgMaxGPKeyVersion != NULL){
+                            delete pbufCfgMaxGPKeyVersion;
+                            pbufCfgMaxGPKeyVersion = NULL;
+                        }
+
+                        return -1;
+                    }
+
+                    if(pbufCfgMaxGPKeyVersion->size() != 1){ //the buffer returned from the config file is larger than expected.  we expect [KeyVersion] only, so 1 byte
+
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", "maximumGPKeyVersion defined in %s.%s.maximumGPKeyVersion appears to be %i bytes, should be only 1 byte (2 asciihex characters)", pcharOpPrefix, pcharTokenType, pbufCfgMaxGPKeyVersion->size());
+
+
+                        if (pbufCfgMinGPKeyVersion != NULL){
+                            delete pbufCfgMinGPKeyVersion;
+                            pbufCfgMinGPKeyVersion = NULL;
+                        }
+
+                        if (pbufCfgMaxGPKeyVersion != NULL){
+                            delete pbufCfgMaxGPKeyVersion;
+                            pbufCfgMaxGPKeyVersion = NULL;
+                        }
+
+                        return -1;
+                    }
+
+                    //initial cuid for printing (yet again)
+                    pcharCUID = Util::Buffer2String(bufCUID);
+
+                    //min/max and card Key Version as a byte
+                    charCfgMinGPKeyVersion = ((BYTE *)(*pbufCfgMinGPKeyVersion))[0];
+                    charCfgMaxGPKeyVersion = ((BYTE *)(*pbufCfgMaxGPKeyVersion))[0];
+                    charCardGPKeyVersion = ((BYTE *)bufCardSuppliedKeyInfo)[0];
+
+                    if(charCardGPKeyVersion < charCfgMinGPKeyVersion){
+
+                        if((pcharCardSuppliedKeyInfo = Util::Buffer2String(bufCardSuppliedKeyInfo)) == NULL){
+                            if (pbufCfgMinGPKeyVersion != NULL){
+                                delete pbufCfgMinGPKeyVersion;
+                                pbufCfgMinGPKeyVersion = NULL;
+                            }
+
+                            if (pbufCfgMaxGPKeyVersion != NULL){
+                                delete pbufCfgMaxGPKeyVersion;
+                                pbufCfgMaxGPKeyVersion = NULL;
+                            }
+
+                            if (pcharCUID != NULL){
+                                PR_Free(pcharCUID);
+                                pcharCUID = NULL;
+
+                            }
+
+                            return -1;
+                        }
+
+                        PR_snprintf(charArrayAuditMsg, 500, "Token %s is less than minimum GP key version %x, token key version is %x", pcharCUID, charCfgMinGPKeyVersion, charCardGPKeyVersion);
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", charArrayAuditMsg);
+                        RA::Audit(EV_KEY_SANITY_CHECK, AUDIT_MSG_KEY_SANITY_CHECK, pcharCUID, "", "failure", pcharOpPrefix, pcharCardSuppliedKeyInfo, "", "", charArrayAuditMsg);
+                        RA::tdb_activity("", pcharCUID, pcharOpPrefix, "failure", charArrayAuditMsg, "", pcharTokenType);
+
+                        if(pcharCardSuppliedKeyInfo != NULL){
+                            PR_Free(pcharCardSuppliedKeyInfo);
+                            pcharCardSuppliedKeyInfo = NULL;
+                        }
+
+                        if (pbufCfgMinGPKeyVersion != NULL){
+                            delete pbufCfgMinGPKeyVersion;
+                            pbufCfgMinGPKeyVersion = NULL;
+                        }
+
+                        if (pbufCfgMaxGPKeyVersion != NULL){
+                            delete pbufCfgMaxGPKeyVersion;
+                            pbufCfgMaxGPKeyVersion = NULL;
+                        }
+
+                        if (pcharCUID != NULL){
+                            PR_Free(pcharCUID);
+                            pcharCUID = NULL;
+
+                        }
+
+
+                        return -1;
+
+                    }else{
+
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", "Token %s is greater than minimum key version %x, and is at key version %x ", pcharCUID, charCfgMinGPKeyVersion, charCardGPKeyVersion);
+
+
+                    }
+
+
+                    if(charCardGPKeyVersion > charCfgMaxGPKeyVersion){
+
+
+                        if((pcharCardSuppliedKeyInfo = Util::Buffer2String(bufCardSuppliedKeyInfo)) == NULL){
+                            if (pbufCfgMinGPKeyVersion != NULL){
+                                delete pbufCfgMinGPKeyVersion;
+                                pbufCfgMinGPKeyVersion = NULL;
+                            }
+
+                            if (pbufCfgMaxGPKeyVersion != NULL){
+                                delete pbufCfgMaxGPKeyVersion;
+                                pbufCfgMaxGPKeyVersion = NULL;
+                            }
+
+                            if (pcharCUID != NULL){
+                                PR_Free(pcharCUID);
+                                pcharCUID = NULL;
+
+                            }
+
+                            return -1;
+                        }
+
+                        PR_snprintf(charArrayAuditMsg, 500, "Token %s is greater than maximum key version %x, token key version is %x", pcharCUID, charCfgMaxGPKeyVersion, charCardGPKeyVersion);
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", charArrayAuditMsg);
+                        RA::Audit(EV_KEY_SANITY_CHECK, AUDIT_MSG_KEY_SANITY_CHECK, pcharCUID, "", "failure", pcharOpPrefix, pcharCardSuppliedKeyInfo, "", "", charArrayAuditMsg);
+                        RA::tdb_activity("", pcharCUID, pcharOpPrefix, "failure", charArrayAuditMsg, "", pcharTokenType);
+
+                        if (pbufCfgMinGPKeyVersion != NULL){
+                            delete pbufCfgMinGPKeyVersion;
+                            pbufCfgMinGPKeyVersion = NULL;
+                        }
+
+                        if (pbufCfgMaxGPKeyVersion != NULL){
+                            delete pbufCfgMaxGPKeyVersion;
+                            pbufCfgMaxGPKeyVersion = NULL;
+                        }
+
+
+                        if(pcharCardSuppliedKeyInfo != NULL){
+                            PR_Free(pcharCardSuppliedKeyInfo);
+                            pcharCardSuppliedKeyInfo = NULL;
+                        }
+
+                        if (pcharCUID != NULL){
+                            PR_Free(pcharCUID);
+                            pcharCUID = NULL;
+
+                        }
+
+                        return -1;
+
+                    }else{
+
+                        RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange", "Token %s is not greater than maximum key version %x, and is at key version %x ", pcharCUID, charCfgMaxGPKeyVersion, charCardGPKeyVersion);
+
+                    }
+
+                    if((pcharCardSuppliedKeyInfo = Util::Buffer2String(bufCardSuppliedKeyInfo)) == NULL){
+                        if (pbufCfgMinGPKeyVersion != NULL){
+                            delete pbufCfgMinGPKeyVersion;
+                            pbufCfgMinGPKeyVersion = NULL;
+                        }
+
+                        if (pbufCfgMaxGPKeyVersion != NULL){
+                            delete pbufCfgMaxGPKeyVersion;
+                            pbufCfgMaxGPKeyVersion = NULL;
+                        }
+
+                        if (pcharCUID != NULL){
+                            PR_Free(pcharCUID);
+                            pcharCUID = NULL;
+
+                        }
+
+                        return -1;
+                    }
+
+
+                    RA::Audit(EV_KEY_SANITY_CHECK, AUDIT_MSG_KEY_SANITY_CHECK, pcharCUID, "", "success", pcharOpPrefix, pcharCardSuppliedKeyInfo, "", "", "Token GP key version is within GP key version range.");
+
+
+                    if(pcharCardSuppliedKeyInfo != NULL){
+                        PR_Free(pcharCardSuppliedKeyInfo);
+                        pcharCardSuppliedKeyInfo = NULL;
+                    }
+
+                    if (pbufCfgMinGPKeyVersion != NULL){
+                        delete pbufCfgMinGPKeyVersion;
+                        pbufCfgMinGPKeyVersion = NULL;
+                    }
+
+                    if (pbufCfgMaxGPKeyVersion != NULL){
+                        delete pbufCfgMaxGPKeyVersion;
+                        pbufCfgMaxGPKeyVersion = NULL;
+                    }
+
+                    if (pcharCUID != NULL){
+                        PR_Free(pcharCUID);
+                        pcharCUID = NULL;
+
+                    }
+
+
+                }else{
+
+                    //either minKeyVerion or bufCfgMaxGPKeyVersion was not correctly retrieved from RA::ConfigStore
+
+                    RA::Debug("RA_Processor::checkCardGPKeyVersionIsInRange","pbufCfgMinGPKeyVersion is %s and pbufCfgMaxGPKeyVersion is %s", (pbufCfgMinGPKeyVersion == NULL)? "null":"not null", (pbufCfgMaxGPKeyVersion == NULL)?"null":"not null");
+
+                    if (pbufCfgMinGPKeyVersion != NULL){
+                        delete pbufCfgMinGPKeyVersion;
+                        pbufCfgMinGPKeyVersion = NULL;
+                    }
+
+                    if (pbufCfgMaxGPKeyVersion != NULL){
+                        delete pbufCfgMaxGPKeyVersion;
+                        pbufCfgMaxGPKeyVersion = NULL;
+                    }
+
+                    if (pcharCUID != NULL){
+                        PR_Free(pcharCUID);
+                        pcharCUID = NULL;
+
+                    }
+
+                    return -1;
+
+                }
+
+
+        return 0;
+
+
+
 }
 
 
 /**
  * Input data wrapped by KEK key in TKS.
  */
-int RA_Processor::EncryptData(Buffer &CUID, Buffer &version, Buffer &in, Buffer &out, const char *connid)
+
+/**
+ * PAS Modification
+ * Added KDD argument to allow TKS the ability to decide between CUID or KDD for KDF seed
+ * Added CUID and KDD http parameters to send to TKS
+ *
+ */
+int RA_Processor::EncryptData(Buffer &CUID, Buffer &KDD, Buffer &version, Buffer &in, Buffer &out, const char *connid)
 {
     char body[5000];
     char configname[256];
@@ -2181,13 +2954,14 @@ int RA_Processor::EncryptData(Buffer &CUID, Buffer &version, Buffer &in, Buffer
         }
 
         char *cuid = Util::SpecialURLEncode(CUID);
+        char *kdd = Util::SpecialURLEncode(KDD);
         char *versionID = Util::SpecialURLEncode(version);
 
         PR_snprintf((char *)configname, 256, "conn.%s.keySet", connid);
         const char *keySet = RA::GetConfigStore()->GetConfigAsString(configname);
 
-        PR_snprintf((char *)body, 5000, "data=%s&CUID=%s&KeyInfo=%s&keySet=%s",
-          ((data != NULL)? data:""), cuid, versionID,keySet);
+        PR_snprintf((char *)body, 5000, "data=%s&CUID=%s&KDD=%s&KeyInfo=%s&keySet=%s",
+          ((data != NULL)? data:""), cuid, kdd, versionID, keySet);
         PR_snprintf((char *)configname, 256, "conn.%s.servlet.encryptData", connid);
         const char *servletID = RA::GetConfigStore()->GetConfigAsString(configname);
 
@@ -2195,6 +2969,10 @@ int RA_Processor::EncryptData(Buffer &CUID, Buffer &version, Buffer &in, Buffer
             PR_Free( cuid );
             cuid = NULL;
         }
+        if( kdd != NULL ) {
+            PR_Free( kdd );
+            kdd = NULL;
+        }
         if( versionID != NULL ) {
             PR_Free( versionID );
             versionID = NULL;
@@ -3441,7 +4219,7 @@ RA_Status RA_Processor::Format(RA_Session *session, NameValueSet *extensions, bo
     connid = RA::GetConfigStore()->GetConfigAsString(configname);
     upgrade_rc = UpgradeApplet(session,(char *) OP_PREFIX, (char*)tokenType, major_version, 
       minor_version, expected_version, applet_dir, security_level, connid,
-			       extensions, 10, 90, &keyVersion);
+			       extensions, 10, 90, &keyVersion, token_cuid);
     if (upgrade_rc != 1) {
         RA::Debug("RA_Processor::Format", 
           "applet upgrade failed");
@@ -3500,7 +4278,7 @@ RA_Status RA_Processor::Format(RA_Session *session, NameValueSet *extensions, bo
         PR_snprintf((char *)configname, 256,"channel.defKeyIndex");
         int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0);
         channel = SetupSecureChannel(session, 0x00,
-                  defKeyIndex  /* default key index */, connid);
+                  defKeyIndex  /* default key index */, connid, token_cuid, OP_PREFIX, tokenType);
 
         if (channel != NULL) {
             char issuer[224];
@@ -3539,7 +4317,7 @@ RA_Status RA_Processor::Format(RA_Session *session, NameValueSet *extensions, bo
         PR_snprintf((char *)configname, 256,"channel.defKeyIndex");
         int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0);
         channel = SetupSecureChannel(session, requiredV,
-                   defKeyIndex  /* default key index */, tksid);
+                   defKeyIndex  /* default key index */, tksid, token_cuid, OP_PREFIX, tokenType);
         if (channel == NULL) {
             /**
              * Select Card Manager for Put Key operation.
@@ -3560,7 +4338,7 @@ RA_Status RA_Processor::Format(RA_Session *session, NameValueSet *extensions, bo
         int defKeyIndex = RA::GetConfigStore()->GetConfigAsInt(configname, 0x0);
             channel = SetupSecureChannel(session, 
                   defKeyVer,  /* default key version */
-                  defKeyIndex  /* default key index */, tksid);
+                  defKeyIndex  /* default key index */, tksid, token_cuid, OP_PREFIX, tokenType);
  
             if (channel == NULL) {
                 RA::Error("RA_Upgrade_Processor::Process", 
@@ -3587,10 +4365,11 @@ RA_Status RA_Processor::Format(RA_Session *session, NameValueSet *extensions, bo
             PR_snprintf((char *)configname,  256,"%s.%s.tks.conn", OP_PREFIX, tokenType);
             connid = RA::GetConfigStore()->GetConfigAsString(configname);
             rc = CreateKeySetData(
+                    token_cuid,
               channel->GetKeyDiversificationData(), 
               curKeyInfo,
               newVersion,
-              key_data_set, connid);
+              key_data_set, connid, OP_PREFIX, tokenType);
             if (rc != 1) {
                 RA::Error("RA_Format_Processor::Process", 
                   "failed to create new key set");
@@ -3622,6 +4401,62 @@ RA_Status RA_Processor::Format(RA_Session *session, NameValueSet *extensions, bo
             curKeyInfoStr = Util::Buffer2String(curKeyInfo);
             newVersionStr = Util::Buffer2String(newVersion);
     
+            /**
+             * PAS Modification
+             * Previously the return code from put keys was not evaluated or recorded on failure
+             * Prior comment block identified the necessity of evaluation and audit logging on failure
+             */
+
+            if(rc < 0){
+                RA::Debug("RA_Processor::Format", "Failed to Put Keys for token %s", cuid);
+                status = STATUS_ERROR_KEY_CHANGE_OVER;
+
+                RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER,
+                                    userid != NULL ? userid : "", cuid != NULL ? cuid : "", msn != NULL ? msn : "", "failure", "format",
+                                            final_applet_version != NULL ? final_applet_version : "", curKeyInfoStr, newVersionStr,
+                                                    "failed to put new GP key set to token");
+
+                // update activity database with entry about put key event
+                RA::tdb_activity(session->GetRemoteIP(), cuid, OP_PREFIX, "failure", "Failed to send new GP Key Set to token", (userid == NULL) ? "" : userid, tokenType);
+
+                /**
+                 * PAS Modification
+                 * New configuration value to permit rollback of KeyInfo in Token DB, default disabled
+                 *
+                 */
+                snprintf((char *)configname, 256, "%s.%s.rollbackKeyVersionOnPutKeyFailure", OP_PREFIX, tokenType);
+                if(RA::GetConfigStore()->GetConfigAsBool(configname, 0)){
+                    rc = RA::tdb_update(NULL, cuid, NULL, curKeyInfoStr, NULL, NULL, NULL);
+                    if (rc < 0) {
+                        RA::Debug(LL_PER_PDU, "RA_Processor::Format","Failed to update the token database with current key version");
+                        status = STATUS_ERROR_UPDATE_TOKENDB_FAILED;  //clobbers the previous failure message :-(
+
+                        RA::Audit(EV_TOKENDB_UPDATE, AUDIT_MSG_TOKENDB_UPDATE, "", cuid, "", curKeyInfoStr, "", "", "", "failed to update tokenDB to current key version");
+
+                        goto loser;
+                    }else{
+
+                        RA::Debug(LL_PER_PDU, "RA_Processor::Format","Successfully updated the token database with current key version");
+                        RA::Audit(EV_TOKENDB_UPDATE, AUDIT_MSG_TOKENDB_UPDATE, "", cuid, "", curKeyInfoStr, "", "", "", "successfully updated tokenDB to current key version");
+
+                    }
+                }
+                goto loser;
+            }else {
+
+
+                RA::Audit(EV_KEY_CHANGEOVER, AUDIT_MSG_KEY_CHANGEOVER,
+                                    userid != NULL ? userid : "", cuid != NULL ? cuid : "", msn != NULL ? msn : "", "success", "format",
+                                            final_applet_version != NULL ? final_applet_version : "", curKeyInfoStr, newVersionStr,
+                                                    "put new GP key set to token");
+
+                RA::tdb_activity(session->GetRemoteIP(), cuid, OP_PREFIX, "success", "Sent new GP Key Set to token", (userid == NULL) ? "" : userid, tokenType);
+
+            }
+
+
+
+
             char curVer[10];
             char newVer[10];
             
@@ -3669,7 +4504,7 @@ RA_Status RA_Processor::Format(RA_Session *session, NameValueSet *extensions, bo
 
 
             channel = SetupSecureChannel(session, requiredV,
-              defKeyIndex  /* default key index */, tksid);
+              defKeyIndex  /* default key index */, tksid, token_cuid, OP_PREFIX, tokenType);
             if (channel == NULL) {
                 RA::Error("RA_Format_Processor::Process", 
 			      "failed to establish secure channel after reselect");
diff --git a/src/tus/tus_db.c b/src/tus/tus_db.c
index 7c923a8..d7868c2 100755
--- a/src/tus/tus_db.c
+++ b/src/tus/tus_db.c
@@ -1356,12 +1356,21 @@ TPS_PUBLIC int update_tus_db_entry (const char *agentid, char *cn, const char *u
     if (PR_snprintf(dn, 255, "cn=%s,%s", cn, baseDN) < 0)
         return -1;
 
+    /**
+     * PAS Modification
+     *
+     * Updated the function to update the LDAP directory entry with only non-NULL argument values
+     * Increased each allocate_modifications by 1, so 5->6, 6->7, and 7->8.  These will probably all result in over allocation
+     * The increase was necessary to assign a NULL to the element in the array immediately following the last populated LDAPMod structure in the event that all LDAPMods were actually populated.
+     */
+
+
         if (keyInfo == NULL && token_type == NULL)
-            mods = allocate_modifications(5);
+            mods = allocate_modifications(6); //increase from 5 to 6
         else if (keyInfo == NULL || token_type == NULL)
-            mods = allocate_modifications(6);
+            mods = allocate_modifications(7); //increase from 6 to 7
         else
-            mods = allocate_modifications(7);
+            mods = allocate_modifications(8);  //increase from 7 to 8
         if (mods == NULL)
             return -1;
 
@@ -1377,6 +1386,8 @@ TPS_PUBLIC int update_tus_db_entry (const char *agentid, char *cn, const char *u
         mods[0]->mod_type = tokenAttributes[I_TOKEN_M_DATE];
         mods[0]->mod_values = v;
         k = 1;
+
+
         if (applet_version != NULL && PL_strlen(applet_version) > 0) {
             len = PL_strlen(applet_version);
             if ((v = allocate_values(1, len+1)) == NULL) {
@@ -1395,25 +1406,28 @@ TPS_PUBLIC int update_tus_db_entry (const char *agentid, char *cn, const char *u
         }
 
     /* for userid */
-    if (uid != NULL && PL_strlen(uid) > 0)
-        len = PL_strlen(uid);
-    else
-        len = 0;
-    if ((v = allocate_values(1, len+1)) == NULL) {
-        if( mods != NULL ) {
-            free_modifications( mods, 0 );
-            mods = NULL;
+        if(uid != NULL){
+            if (uid != NULL && PL_strlen(uid) > 0)
+                len = PL_strlen(uid);
+            else
+                len = 0;
+            if ((v = allocate_values(1, len+1)) == NULL) {
+                if( mods != NULL ) {
+                    free_modifications( mods, 0 );
+                    mods = NULL;
+                }
+                return -1;
+            }
+            mods[k]->mod_op = LDAP_MOD_REPLACE;
+            mods[k]->mod_type = "tokenUserID";
+            if (uid != NULL && PL_strlen(uid) > 0)
+                PL_strcpy(v[0], uid);
+            else
+                v[0] = "";
+            mods[k]->mod_values = v;
+            k++;
         }
-        return -1;
-    }
-    mods[k]->mod_op = LDAP_MOD_REPLACE;
-    mods[k]->mod_type = "tokenUserID";
-    if (uid != NULL && PL_strlen(uid) > 0)
-        PL_strcpy(v[0], uid);
-    else
-        v[0] = "";
-    mods[k]->mod_values = v;
-    k++;
+
 
         if (status != NULL && PL_strlen(status) > 0) {
             len = PL_strlen(status);
@@ -1433,6 +1447,7 @@ TPS_PUBLIC int update_tus_db_entry (const char *agentid, char *cn, const char *u
         }
 
     /* for tokenReason */
+        if (reason != NULL){
     if (reason != NULL && PL_strlen(reason) > 0)
         len = PL_strlen(reason);
     else
@@ -1452,7 +1467,7 @@ TPS_PUBLIC int update_tus_db_entry (const char *agentid, char *cn, const char *u
         v[0] = "";
     mods[k]->mod_values = v;
     k++;
-
+        }
     /* for keyinfo */
     if (keyInfo != NULL) {
         if (keyInfo != NULL && PL_strlen(keyInfo) > 0)
@@ -1499,6 +1514,8 @@ TPS_PUBLIC int update_tus_db_entry (const char *agentid, char *cn, const char *u
         k++;
     }
 
+        mods[k] = NULL;
+
         for (tries = 0; tries < MAX_RETRIES; tries++) {
             if ((rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL)) == LDAP_SUCCESS) {
                 break;
@@ -2058,10 +2075,15 @@ int add_new_tus_db_entry (const char *userid, char *cn, const char *uid, int fla
     policy_values[0] = defaultPolicy;
     policy_values[1] = NULL;
 
+    /**
+     * PAS Modification
+     * Wrapped all input values with null test to prevent LDAP errors
+     *
+     */
     if (uid != NULL) uid_values[0] = ( char * ) uid;
     if (key_info != NULL) key_info_values[0] = key_info;
-    status_values[0] = ( char * ) status;
-    token_type_values[0] = ( char *) token_type;
+    if (status != NULL) status_values[0] = ( char * ) status;
+    if (token_type != NULL) token_type_values[0] = ( char *) token_type;
 
     a01.mod_op = 0;
     a01.mod_type = TOKEN_ID;
