diff options
Diffstat (limited to 'base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java')
-rw-r--r-- | base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java | 2789 |
1 files changed, 2789 insertions, 0 deletions
diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java new file mode 100644 index 000000000..cff615752 --- /dev/null +++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java @@ -0,0 +1,2789 @@ +package org.dogtagpki.server.tps.processor; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Random; +import java.util.zip.DataFormatException; + +import netscape.security.provider.RSAPublicKey; +//import org.mozilla.jss.pkcs11.PK11ECPublicKey; +import netscape.security.util.BigInt; +import netscape.security.x509.X509CertImpl; + +import org.dogtagpki.server.tps.TPSSession; +import org.dogtagpki.server.tps.TPSSubsystem; +import org.dogtagpki.server.tps.TPSTokenPolicy; +import org.dogtagpki.server.tps.authentication.TPSAuthenticator; +import org.dogtagpki.server.tps.channel.SecureChannel; +import org.dogtagpki.server.tps.channel.SecureChannel.TokenKeyType; +import org.dogtagpki.server.tps.cms.CAEnrollCertResponse; +import org.dogtagpki.server.tps.cms.CARemoteRequestHandler; +import org.dogtagpki.server.tps.cms.CARenewCertResponse; +import org.dogtagpki.server.tps.cms.CARetrieveCertResponse; +import org.dogtagpki.server.tps.cms.CARevokeCertResponse; +import org.dogtagpki.server.tps.cms.KRARecoverKeyResponse; +import org.dogtagpki.server.tps.cms.KRAServerSideKeyGenResponse; +import org.dogtagpki.server.tps.dbs.ActivityDatabase; +import org.dogtagpki.server.tps.dbs.TPSCertRecord; +import org.dogtagpki.server.tps.dbs.TokenRecord; +import org.dogtagpki.server.tps.engine.TPSEngine; +import org.dogtagpki.server.tps.engine.TPSEngine.ENROLL_MODES; +import org.dogtagpki.server.tps.main.ObjectSpec; +import org.dogtagpki.server.tps.main.PKCS11Obj; +import org.dogtagpki.tps.apdu.ExternalAuthenticateAPDU.SecurityLevel; +import org.dogtagpki.tps.main.TPSBuffer; +import org.dogtagpki.tps.main.TPSException; +import org.dogtagpki.tps.main.Util; +import org.dogtagpki.tps.msg.BeginOpMsg; +import org.dogtagpki.tps.msg.EndOpMsg; +import org.dogtagpki.tps.msg.EndOpMsg.TPSStatus; +import org.mozilla.jss.asn1.InvalidBERException; +import org.mozilla.jss.crypto.InvalidKeyFormatException; +import org.mozilla.jss.pkcs11.PK11PubKey; +import org.mozilla.jss.pkcs11.PK11RSAPublicKey; +import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.IAuthCredentials; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.EPropertyNotFound; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.tps.token.TokenStatus; +import com.netscape.cmsutil.util.Utils; + +public class TPSEnrollProcessor extends TPSProcessor { + + public TPSEnrollProcessor(TPSSession session) { + super(session); + } + + @Override + public void process(BeginOpMsg beginMsg) throws TPSException, IOException { + if (beginMsg == null) { + throw new TPSException("TPSEnrollrocessor.process: invalid input data, not beginMsg provided.", + TPSStatus.STATUS_ERROR_CONTACT_ADMIN); + } + setBeginMessage(beginMsg); + setCurrentTokenOperation("enroll"); + checkIsExternalReg(); + + enroll(); + + } + + private void enroll() throws TPSException, IOException { + CMS.debug("TPSEnrollProcessor enroll: entering..."); + String auditMsg = null; + TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID); + TPSTokenPolicy tokenPolicy = new TPSTokenPolicy(tps); + + AppletInfo appletInfo = null; + TokenRecord tokenRecord = null; + try { + appletInfo = getAppletInfo(); + } catch (TPSException e) { + auditMsg = e.toString(); + tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg, + "failure"); + + throw e; + } + appletInfo.setAid(getCardManagerAID()); + + CMS.debug("TPSEnrollProcessor.enroll: token cuid: " + appletInfo.getCUIDhexStringPlain()); + boolean isTokenPresent = false; + + tokenRecord = isTokenRecordPresent(appletInfo); + + if (tokenRecord != null) { + CMS.debug("TPSEnrollProcessor.enroll: found token..."); + isTokenPresent = true; + } else { + CMS.debug("TPSEnrollProcessor.enroll: token does not exist in tokendb... create one in memory"); + tokenRecord = new TokenRecord(); + tokenRecord.setId(appletInfo.getCUIDhexStringPlain()); + } + + fillTokenRecord(tokenRecord, appletInfo); + session.setTokenRecord(tokenRecord); + + String resolverInstName = getResolverInstanceName(); + + String tokenType = null; + + tokenType = resolveTokenProfile(resolverInstName, appletInfo.getCUIDhexString(), appletInfo.getMSNString(), + appletInfo.getMajorVersion(), appletInfo.getMinorVersion()); + CMS.debug("TPSEnrollProcessor.enroll: resolved tokenType: " + tokenType); + + checkProfileStateOK(); + String cuid = appletInfo.getCUIDhexStringPlain(); + + boolean do_force_format = false; + if (isTokenPresent) { + CMS.debug("TPSEnrollProcessor.enroll: token exists in tokendb"); + + TokenStatus newState = TokenStatus.ACTIVE; + // Check for transition to ACTIVE status. + + if (!tps.engine.isOperationTransitionAllowed(tokenRecord.getTokenStatus(), newState)) { + CMS.debug("TPSEnrollProcessor.enroll: token transition disallowed " + + tokenRecord.getTokenStatus() + + " to " + newState); + auditMsg = "Operation for CUID " + cuid + + " Disabled, illegal transition attempted " + tokenRecord.getTokenStatus() + + " to " + newState; + tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg, + "failure"); + + throw new TPSException(auditMsg, + TPSStatus.STATUS_ERROR_DISABLED_TOKEN); + } else { + CMS.debug("TPSPEnrollrocessor.enroll: token transition allowed " + + tokenRecord.getTokenStatus() + + " to " + newState); + } + + do_force_format = tokenPolicy.isForceTokenFormat(cuid); + + if (!tokenPolicy.isAllowdTokenReenroll(cuid) && + !tokenPolicy.isAllowdTokenRenew(cuid)) { + CMS.debug("TPSEnrollProcessor.enroll: token renewal or reEnroll disallowed "); + auditMsg = "Operation renewal or reEnroll for CUID " + cuid + + " Disabled"; + tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg, + "failure"); + + throw new TPSException(auditMsg, + TPSStatus.STATUS_ERROR_DISABLED_TOKEN); + } + } else { + CMS.debug("TPSEnrollProcessor.enroll: token does not exist"); + tokenRecord.setStatus("uninitialized"); + + checkAllowUnknownToken(TPSEngine.OP_FORMAT_PREFIX); + } + checkAndAuthenticateUser(appletInfo, tokenType); + + if (do_force_format) { + CMS.debug("TPSEnrollProcessor.enroll: About to force format first due to policy."); + //We will skip the auth step inside of format + format(true); + } else { + checkAndUpgradeApplet(appletInfo); + //Get new applet info + appletInfo = getAppletInfo(); + } + + CMS.debug("TPSEnrollProcessor.enroll: Finished updating applet if needed."); + + //Check and upgrade keys if called for + + SecureChannel channel = checkAndUpgradeSymKeys(); + channel.externalAuthenticate(); + + //Reset the token's pin, create one if we don't have one already + + checkAndHandlePinReset(channel); + tokenRecord.setKeyInfo(channel.getKeyInfoData().toHexStringPlain()); + String tksConnId = getTKSConnectorID(); + TPSBuffer plaintextChallenge = computeRandomData(16, tksConnId); + + //These will be used shortly + TPSBuffer wrappedChallenge = encryptData(appletInfo, channel.getKeyInfoData(), plaintextChallenge, tksConnId); + PKCS11Obj pkcs11objx = null; + + try { + pkcs11objx = getCurrentObjectsOnToken(channel); + } catch (DataFormatException e) { + auditMsg = "TPSEnrollProcessor.enroll: Failed to parse original token data: " + e.toString(); + tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg, + "failure"); + + throw new TPSException(auditMsg); + } + + pkcs11objx.setCUID(appletInfo.getCUID()); + + if (!isTokenPresent) { + try { + tps.tdb.tdbAddTokenEntry(tokenRecord, "uninitialized"); + } catch (Exception e) { + String failMsg = "add token failure"; + auditMsg = failMsg + ":" + e.toString(); + throw new TPSException(auditMsg); + } + } + + statusUpdate(10, "PROGRESS_PROCESS_PROFILE"); + + EnrolledCertsInfo certsInfo = new EnrolledCertsInfo(); + certsInfo.setWrappedChallenge(wrappedChallenge); + certsInfo.setPlaintextChallenge(plaintextChallenge); + certsInfo.setPKCS11Obj(pkcs11objx); + certsInfo.setStartProgress(15); + certsInfo.setEndProgress(90); + + boolean renewed = false; + TPSStatus status = generateCertsAfterRenewalRecoveryPolicy(certsInfo, channel, appletInfo); + //most failed would have thrown an exception + String statusString = "Unknown"; // gives some meaningful debug message + if (status == TPSStatus.STATUS_NO_ERROR) + statusString = "Enrollment to follow"; + else if (status == TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED) + statusString = "Recovery processed"; + else if (status == TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED) + statusString = "Renewal processed"; + else { + auditMsg = " generateCertsAfterRenewalRecoveryPolicy returned status=" + status; + CMS.debug("TPSEnrollProcessor.enroll:" + auditMsg); + throw new TPSException(auditMsg); + } + auditMsg = "generateCertsAfterRenewalRecoveryPolicy returns status:" + + EndOpMsg.statusToInt(status) + " : " + statusString; + CMS.debug("TPSEnrollProcessor.enroll: " + auditMsg); + if (status == TPSStatus.STATUS_NO_ERROR) { + if (!generateCertificates(certsInfo, channel, appletInfo)) { + CMS.debug("TPSEnrollProcessor.enroll:generateCertificates returned false means some certs failed enrollment; clean up (format) the token"); + format(true /*skipAuth*/); + throw new TPSException("generateCertificates failed"); + } else { + CMS.debug("TPSEnrollProcessor.enroll:generateCertificates returned true means cert enrollment successful"); + } + } + // at this point, enrollment, renewal, or recovery have been processed accordingly; + if (status == TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED && + tokenPolicy.isAllowdTokenRenew(cuid)) { + renewed = true; + CMS.debug("TPSEnrollProcessor.enroll: renewal happened.. "); + } + /* + * TODO: + * find the point to do the following... + * when total available memory is exceeded on the token ... + * if(!renewed) //Renewal should leave what they have on the token. + * format(true); + */ + String tokenLabel = buildTokenLabel(certsInfo, appletInfo); + + pkcs11objx.setTokenName(new TPSBuffer(tokenLabel.getBytes())); + + int lastObjVer = pkcs11objx.getOldObjectVersion(); + + CMS.debug("TPSEnrollProcessor.enroll: getOldObjectVersion: returning: " + lastObjVer); + + if (lastObjVer != 0) { + while (lastObjVer == 0xff) { + Random randomGenerator = new Random(); + lastObjVer = randomGenerator.nextInt(1000); + } + + lastObjVer = lastObjVer + 1; + CMS.debug("TPSEnrollProcessor.enroll: Setting objectVersion to: " + lastObjVer); + pkcs11objx.setObjectVersion(lastObjVer); + + } + + pkcs11objx.setFormatVersion(pkcs11objx.getOldFormatVersion()); + + // Make sure we have a good secure channel before writing out the final objects + channel = setupSecureChannel(); + + statusUpdate(92, "PROGRESS_WRITE_OBJECTS"); + + writeFinalPKCS11ObjectToToken(pkcs11objx, appletInfo, channel); + statusUpdate(98, "PROGRESS_ISSUER_INFO"); + writeIssuerInfoToToken(channel); + + statusUpdate(99, "PROGRESS_SET_LIFECYCLE"); + channel.setLifeycleState((byte) 0x0f); + + try { + tokenRecord.setStatus("active"); + tps.tdb.tdbUpdateTokenEntry(tokenRecord); + } catch (Exception e) { + String failMsg = "update token failure"; + auditMsg = failMsg + ":" + e.toString(); + tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), failMsg, + "failure"); + throw new TPSException(auditMsg); + } + //update the tokendb with new certs + CMS.debug("TPSEnrollProcessor.enroll: updating tokendb with certs."); + ArrayList<TPSCertRecord> certRecords = certsInfo.toTPSCertRecords(tokenRecord.getId(), tokenRecord.getUserID()); + tps.tdb.tdbAddCertificatesForCUID(tokenRecord.getId(), certRecords); + + auditMsg = "appletVersion=" + lastObjVer + "; tokenType =" + selectedTokenType + "; userid =" + userid; + if (renewed) { + tps.tdb.tdbActivity(ActivityDatabase.OP_RENEWAL, tokenRecord, session.getIpAddress(), auditMsg, "success"); + } else { + tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), auditMsg, + "success"); + } + + CMS.debug("TPSEnrollProcessor.enroll: leaving ..."); + + statusUpdate(100, "PROGRESS_DONE_ENROLLMENT"); + } + + private void writeFinalPKCS11ObjectToToken(PKCS11Obj pkcs11objx, AppletInfo ainfo, SecureChannel channel) + throws TPSException, IOException { + if (pkcs11objx == null || ainfo == null || channel == null) { + throw new TPSException("TPSErollProcessor.writeFinalPKCS11ObjectToToken: invalid input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + CMS.debug("TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: entering..."); + + IConfigStore configStore = CMS.getConfigStore(); + + String compressConfig = "op." + currentTokenOperation + "." + selectedTokenType + "." + + "pkcs11obj.compress.enable"; + + CMS.debug("TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: config to check: " + compressConfig); + + boolean doCompress = false; + + try { + doCompress = configStore.getBoolean(compressConfig, true); + } catch (EBaseException e) { + throw new TPSException( + "TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: internal error obtaining config value " + e); + } + + CMS.debug("TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: doCompress: " + doCompress); + + TPSBuffer tokenData = null; + + if (doCompress) { + tokenData = pkcs11objx.getCompressedData(); + + } else { + tokenData = pkcs11objx.getData(); + } + + if (tokenData.size() > ainfo.getTotalMem()) { + + throw new TPSException( + "TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: NOt enough memory to write certificates!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + + } + + byte[] zobjectid = { (byte) 'z', (byte) '0', 0, 0 }; + byte[] perms = { (byte) 0xff, (byte) 0xff, 0x40, 0x00, 0x40, 0x00 }; + TPSBuffer zobjidBuf = new TPSBuffer(zobjectid); + + channel.createObject(zobjidBuf, new TPSBuffer(perms), tokenData.size()); + + channel.writeObject(zobjidBuf, tokenData); + + CMS.debug("TPSEnrollProcessor.writeFinalPKCS11ObjectToToken: leaving successfully ..."); + + } + + private void checkAndAuthenticateUser(AppletInfo appletInfo, String tokenType) throws TPSException { + IAuthCredentials userCred; + IAuthToken authToken; + TokenRecord tokenRecord = getTokenRecord(); + if (!isExternalReg) { + // authenticate per profile/tokenType configuration + String configName = TPSEngine.OP_ENROLL_PREFIX + "." + tokenType + ".auth.enable"; + IConfigStore configStore = CMS.getConfigStore(); + + TPSSubsystem tps = + (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID); + //TPSSession session = getSession(); + boolean isAuthRequired; + try { + CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser: getting config: " + configName); + isAuthRequired = configStore.getBoolean(configName, true); + } catch (EBaseException e) { + CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser: Internal Error obtaining mandatory config values. Error: " + + e); + throw new TPSException("TPS error getting config values from config store.", + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + } + if (isAuthRequired) { + try { + TPSAuthenticator userAuth = + getAuthentication(TPSEngine.OP_ENROLL_PREFIX, tokenType); + userCred = requestUserId(TPSEngine.ENROLL_OP, appletInfo.getCUIDhexString(), userAuth, + beginMsg.getExtensions()); + userid = (String) userCred.get(userAuth.getAuthCredName()); + CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser: userCred (attempted) userid=" + userid); + // initialize userid first for logging purposes in case authentication fails + tokenRecord.setUserID(userid); + authToken = authenticateUser(TPSEngine.ENROLL_OP, userAuth, userCred); + userid = authToken.getInString("userid"); + tokenRecord.setUserID(userid); + CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser: auth passed: userid: " + + authToken.get("userid")); + + } catch (Exception e) { + // all exceptions are considered login failure + CMS.debug("TPSEnrollProcessor.checkAndAuthenticateUser:: authentication exception thrown: " + e); + String msg = "TPS error user authentication failed:" + e; + tps.tdb.tdbActivity(ActivityDatabase.OP_ENROLLMENT, tokenRecord, session.getIpAddress(), msg, + "failure"); + + throw new TPSException(msg, + TPSStatus.STATUS_ERROR_LOGIN); + } + } else { + throw new TPSException( + "TPSEnrollProcessor.checkAndAuthenticateUser: TPS enrollment must have authentication enabled.", + TPSStatus.STATUS_ERROR_LOGIN); + + } + + } + } + + private void checkAndHandlePinReset(SecureChannel channel) throws TPSException, IOException { + + CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset entering..."); + + if (channel == null) { + throw new TPSException("TPSEnrollProcessor.checkAndHandlePinReset: invalid input data!", + TPSStatus.STATUS_ERROR_TOKEN_RESET_PIN_FAILED); + } + + IConfigStore configStore = CMS.getConfigStore(); + + String pinResetEnableConfig = "op." + currentTokenOperation + "." + selectedTokenType + "." + + TPSEngine.CFG_PIN_RESET_ENABLE; + + CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + pinResetEnableConfig); + + String minLenConfig = "op." + currentTokenOperation + "." + selectedTokenType + "." + + TPSEngine.CFG_PIN_RESET_MIN_LEN; + + CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + minLenConfig); + + String maxLenConfig = "op." + currentTokenOperation + "." + selectedTokenType + "." + + TPSEngine.CFG_PIN_RESET_MAX_LEN; + + CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + maxLenConfig); + + String maxRetriesConfig = "op." + currentTokenOperation + "." + selectedTokenType + "." + + TPSEngine.CFG_PIN_RESET_MAX_RETRIES; + + CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + maxRetriesConfig); + + String pinStringConfig = TPSEngine.CFG_PIN_RESET_STRING; + + CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset config to check: " + pinStringConfig); + + boolean enabled = false; + int minLen; + int maxLen; + int maxRetries; + String stringName; + + try { + + enabled = configStore.getBoolean(pinResetEnableConfig, true); + + if (enabled == false) { + CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset: Pin Reset not allowed by configuration, exiting..."); + return; + + } + + minLen = configStore.getInteger(minLenConfig, 4); + maxLen = configStore.getInteger(maxLenConfig, 10); + maxRetries = configStore.getInteger(maxRetriesConfig, 0x7f); + stringName = configStore.getString(pinStringConfig, "password"); + + CMS.debug("TPSEnrollProcessor.checkAndHandlePinReset: config vals: enabled: " + enabled + " minLen: " + + minLen + " maxLen: " + maxLen); + + } catch (EBaseException e) { + throw new TPSException( + "TPSEnrollProcessor.checkAndHandlePinReset: internal error in getting value from config."); + } + + String new_pin = requestNewPin(minLen, maxLen); + + channel.createPin(0x0, maxRetries, stringName); + + channel.resetPin(0x0, new_pin); + + } + + private void checkAndUpgradeApplet(AppletInfo appletInfo) throws TPSException, IOException { + // TODO Auto-generated method stub + + CMS.debug("checkAndUpgradeApplet: entering.."); + + SecurityLevel securityLevel = SecurityLevel.SECURE_MSG_MAC; + + boolean useEncryption = checkUpdateAppletEncryption(); + + String tksConnId = getTKSConnectorID(); + if (useEncryption) + securityLevel = SecurityLevel.SECURE_MSG_MAC_ENC; + + if (checkForAppletUpdateEnabled()) { + + String targetAppletVersion = checkForAppletUpgrade("op." + currentTokenOperation); + targetAppletVersion = targetAppletVersion.toLowerCase(); + + String currentAppletVersion = formatCurrentAppletVersion(appletInfo); + + CMS.debug("TPSEnrollProcessor.checkAndUpgradeApplet: currentAppletVersion: " + currentAppletVersion + + " targetAppletVersion: " + targetAppletVersion); + + if (targetAppletVersion.compareTo(currentAppletVersion) != 0) { + + CMS.debug("TPSEnrollProessor.checkAndUpgradeApplet: Upgrading applet to : " + targetAppletVersion); + upgradeApplet("op." + currentTokenOperation, targetAppletVersion, securityLevel, getBeginMessage() + .getExtensions(), + tksConnId, 5, 12); + } else { + CMS.debug("TPSEnrollProcessor.checkAndUpgradeApplet: applet already at correct version."); + } + } + + } + + protected boolean checkUpdateAppletEncryption() throws TPSException { + + CMS.debug("TPSEnrollProcessor.checkUpdateAppletEncryption entering..."); + + IConfigStore configStore = CMS.getConfigStore(); + + String appletEncryptionConfig = "op." + currentTokenOperation + "." + selectedTokenType + "." + + TPSEngine.CFG_UPDATE_APPLET_ENCRYPTION; + + CMS.debug("TPSEnrollProcessor.checkUpdateAppletEncryption config to check: " + appletEncryptionConfig); + + boolean appletEncryption = false; + + try { + appletEncryption = configStore.getBoolean(appletEncryptionConfig, false); + } catch (EBaseException e) { + //Default TPSException will return a "contact admin" error code. + throw new TPSException( + "TPSEnrollProcessor.checkUpdateAppletEncryption: internal error in getting value from config."); + } + + CMS.debug("TPSEnrollProcessor.checkUpdateAppletEncryption returning: " + appletEncryption); + return appletEncryption; + + } + + private PKCS11Obj getCurrentObjectsOnToken(SecureChannel channel) throws TPSException, IOException, + DataFormatException { + + byte seq = 0; + + TPSBuffer objects = null; + + int lastFormatVersion = 0x0100; + int lastObjectVersion; + Random randomGenerator = new Random(); + + lastObjectVersion = randomGenerator.nextInt(1000); + + CMS.debug("PKCS11Obj.getCurrentObjectsOnToken: Random lastObjectVersion: " + lastObjectVersion); + + PKCS11Obj pkcs11objx = new PKCS11Obj(); + pkcs11objx.setOldFormatVersion(lastFormatVersion); + pkcs11objx.setOldObjectVersion(lastObjectVersion); + + do { + + objects = listObjects(seq); + + if (objects != null) { + CMS.debug("PKCS11Obj.getCurrentObjectsOnToken: objects: " + objects.toHexString()); + } + + if (objects == null) { + pkcs11objx.setOldObjectVersion(lastObjectVersion); + seq = 0; + } else { + seq = 1; // get next entry + + TPSBuffer objectID = objects.substr(0, 4); + TPSBuffer objectLen = objects.substr(4, 4); + + long objectIDVal = objectID.getLongFrom4Bytes(0); + + long objectLenVal = objectLen.getLongFrom4Bytes(0); + + TPSBuffer obj = channel.readObject(objectID, 0, (int) objectLenVal); + + if (obj != null) { + CMS.debug("PKCS11Obj.getCurrentObjectsOnToken: obj: " + obj.toHexString()); + } + + if ((char) objectID.at(0) == (byte) 'z' && objectID.at(1) == (byte) '0') { + lastFormatVersion = obj.getIntFrom2Bytes(0); + lastObjectVersion = obj.getIntFrom2Bytes(2); + + CMS.debug("PKCS11Obj.getCurrentObjectsOnToken: Versions read from token: lastFormatVersion : " + + lastFormatVersion + + " lastObjectVersion: " + lastObjectVersion); + + pkcs11objx = PKCS11Obj.parse(obj, 0); + + pkcs11objx.setOldFormatVersion(lastFormatVersion); + pkcs11objx.setOldObjectVersion(lastObjectVersion); + seq = 0; + + } else { + ObjectSpec objSpec = ObjectSpec.parseFromTokenData(objectIDVal, obj); + pkcs11objx.addObjectSpec(objSpec); + } + + CMS.debug("TPSEnrollProcessor.getCurrentObjectsOnToken. just read object from token: " + + obj.toHexString()); + } + + } while (seq != 0); + + return pkcs11objx; + } + + /* + * generateCertsAfterRenewalRecoveryPolicy determines whether a renewal or recovery is needed; + * if recovery is needed, it determines which certificates (from which old token) + * to recover onto the new token. + * + * Note: renewal and recovery are invoked in this method; However, if a new enrollment is determined + * to be the proper course of action, it is done after this method. + */ + private TPSStatus generateCertsAfterRenewalRecoveryPolicy(EnrolledCertsInfo certsInfo, SecureChannel channel, + AppletInfo aInfo) + throws TPSException, IOException { + TPSStatus status = TPSStatus.STATUS_NO_ERROR; + String auditMsg; + final String method = "TPSEnrollProcessor.generateCertsAfterRenewalRecoveryPolicy"; + CMS.debug(method + ": begins"); + TPSSubsystem tps = + (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID); + TPSTokenPolicy tokenPolicy = new TPSTokenPolicy(tps); + + ArrayList<TokenRecord> tokenRecords = null; + try { + tokenRecords = tps.tdb.tdbFindTokenRecordsByUID(userid); + } catch (Exception e) { + // no existing record, means no "renewal" or "recovery" actions needed + auditMsg = "no token associated with user: " + userid; + CMS.debug(method + auditMsg); + throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_INACTIVE_TOKEN_NOT_FOUND); + } + CMS.debug(method + " found " + tokenRecords.size() + " tokens for user:" + userid); + boolean isRecover = false; + + TokenRecord lostToken = null; + for (TokenRecord tokenRecord : tokenRecords) { + CMS.debug(method + " token id:" + + tokenRecord.getId() + "; status=" + + tokenRecord.getStatus()); + + //Is this the same token (current token)? + if (tokenRecord.getId().equals(aInfo.getCUIDhexStringPlain())) { + //same token + auditMsg = "found current token entry"; + CMS.debug(method + ":" + auditMsg); + if (tokenRecord.getStatus().equals("uninitialized")) { + // this is the current token + if (tokenRecords.size() == 1) { + // the current token is the only token owned by the user + CMS.debug(method + ": need to do enrollment"); + // need to do enrollment outside + break; + } else { + CMS.debug(method + ": There are multiple token entries for user " + + userid); + try { + // this is assuming that the user can only have one single active token + // TODO: for future, maybe should allow multiple active tokens + tps.tdb.tdbHasActiveToken(userid); + + } catch (Exception e1) { + /* + * user has no active token, need to find a token to recover from + * there are no other active tokens for this user + */ + isRecover = true; + continue; // TODO: or break? + } + auditMsg = method + ": user already has an active token"; + CMS.debug(auditMsg); + throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_HAS_AT_LEAST_ONE_ACTIVE_TOKEN); + } + } else if (tokenRecord.getStatus().equals("active")) { + // current token is already active; renew if allowed + if (tokenPolicy.isAllowdTokenRenew(aInfo.getCUIDhexStringPlain())) { + return processRenewal(certsInfo, channel, aInfo, tokenRecord); + } else { + auditMsg = "token is already active; can't renew because renewal is not allowed; will re-enroll if allowed"; + CMS.debug(method + ":" + auditMsg); + } + break; + } else if (tokenRecord.getStatus().equals("terminated")) { + auditMsg = "terminated token cuid=" + + aInfo.getCUIDhexStringPlain() + " cannot be reused"; + CMS.debug(method + ":" + auditMsg); + throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_CONTACT_ADMIN); + } else if (tokenRecord.getStatus().equals("lost")) { + String reasonStr = tokenRecord.getReason(); + if (reasonStr.equals("keyCompromise")) { + auditMsg = "This token cannot be reused because it has been reported lost"; + CMS.debug(method + ": " + + auditMsg); + throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_UNUSABLE_TOKEN_KEYCOMPROMISE); + } else if (reasonStr.equals("onHold")) { + try { + tps.tdb.tdbHasActiveToken(userid); + auditMsg = "user already has an active token"; + CMS.debug(method + ": " + + auditMsg); + throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_HAS_AT_LEAST_ONE_ACTIVE_TOKEN); + } catch (Exception e2) { + auditMsg = "User needs to contact administrator to report lost token (it should be put on Hold)."; + CMS.debug(method + ": " + + auditMsg); + break; + } + } else if (reasonStr.equals("destroyed")) { + auditMsg = "This destroyed lost case should not be executed because the token is so damaged. It should not get here"; + CMS.debug(method + ": " + + auditMsg); + throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_TOKEN_DISABLED); + } else { + auditMsg = "No such lost reason: " + reasonStr + " for this cuid: " + + aInfo.getCUIDhexStringPlain(); + CMS.debug(method + ":" + auditMsg); + throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_NO_SUCH_LOST_REASON); + } + + } else { + auditMsg = "No such token status for this cuid=" + aInfo.getCUIDhexStringPlain(); + CMS.debug(method + ":" + auditMsg); + throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_NO_SUCH_TOKEN_STATE); + } + } else { //cuid != current token + auditMsg = "found token entry different from current token"; + CMS.debug(method + ":" + auditMsg); + if (tokenRecord.getStatus().equals("lost")) { + //lostostToken keeps track of the latest token that's lost + //last one in the look should be the latest + lostToken = tokenRecord; + auditMsg = "found a lost token: cuid = " + tokenRecord.getId(); + CMS.debug(method + ":" + auditMsg); + } + continue; + } + } + + if (isRecover == true) { // this could be set in previous iteration + if (lostToken == null) { + auditMsg = "No lost token to be recovered; do enrollment"; + CMS.debug(method + ":" + auditMsg); + //shouldn't even get here; But if we do, just enroll + } else { + String reasonStr = lostToken.getReason(); + //RevocationReason reason = RevocationReason.valueOf(reasonStr); + auditMsg = "isRecover true; reasonStr =" + reasonStr; + CMS.debug(method + ":" + auditMsg); + + if (reasonStr.equals("keyCompromise")) { + return processRecovery(lostToken, certsInfo, channel, aInfo); + } else if (reasonStr.equals("onHold")) { + /* + * the inactive one becomes the temp token + * No recovery scheme, basically we are going to + * do the brand new enrollment + * + * + */ + + // ToDo: This section has not been tested to work.. Make sure this works. + + IConfigStore configStore = CMS.getConfigStore(); + String configName = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType() + + ".temporaryToken.tokenType"; + try { + String tmpTokenType = configStore.getString(configName); + setSelectedTokenType(tmpTokenType); + } catch (EPropertyNotFound e) { + auditMsg = " configuration " + configName + " not found"; + CMS.debug(method + ":" + auditMsg); + throw new TPSException(method + ":" + auditMsg); + } catch (EBaseException e) { + auditMsg = " configuration " + configName + " not found"; + CMS.debug(method + ":" + auditMsg); + throw new TPSException(method + ":" + auditMsg); + } + return processRecovery(lostToken, certsInfo, channel, aInfo); + + } else if (reasonStr.equals("destroyed")) { + return processRecovery(lostToken, certsInfo, channel, aInfo); + } else { + auditMsg = "No such lost reason: " + reasonStr + " for this cuid: " + aInfo.getCUIDhexStringPlain(); + CMS.debug(method + ":" + auditMsg); + throw new TPSException(auditMsg, TPSStatus.STATUS_ERROR_NO_SUCH_LOST_REASON); + } + } + } + + CMS.debug(method + ": ends"); + return status; + } + + /* + * Renewal logic + * 1. Create Optional local TPS grace period per token profile, + * per token type, such as signing or encryption. + * This grace period must match how the CA is configured. Ex: + * op.enroll.userKey.renewal.encryption.enable=true + * op.enroll.userKey.renewal.encryption.gracePeriod.enable=true + * op.enroll.userKey.renewal.encryption.gracePeriod.before=30 + * op.enroll.userKey.renewal.encryption.gracePeriod.after=30 + * 2. In case of a grace period failure the code will go on + * and attempt to renew the next certificate in the list. + * 3. In case of any other code failure, the code will abort + * and leave the token untouched, while informing the user + * with an error message. + * + */ + private TPSStatus processRenewal(EnrolledCertsInfo certsInfo, SecureChannel channel, AppletInfo aInfo, + TokenRecord tokenRecord) + throws TPSException, IOException { + TPSStatus status = TPSStatus.STATUS_ERROR_RENEWAL_FAILED; + String method = "TPSEnrollProcess.processRenewal"; + String auditMsg; + CMS.debug(method + ": begins"); + + boolean noFailedCerts = true; + + if (certsInfo == null || aInfo == null || channel == null) { + throw new TPSException(method + ": Bad Input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + TPSSubsystem tps = + (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID); + int keyTypeNum = getNumberCertsToRenew(); + /* + * Get certs from the tokendb for this token to find out about + * renewal possibility + */ + ArrayList<TPSCertRecord> allCerts = tps.tdb.tdbGetCertificatesByCUID(tokenRecord.getId()); + + certsInfo.setNumCertsToEnroll(keyTypeNum); + + CMS.debug(method + ": Number of certs to renew: " + keyTypeNum); + + for (int i = 0; i < keyTypeNum; i++) { + /* + * e.g. op.enroll.userKey.renewal.keyType.value.0=signing + * e.g. op.enroll.userKey.renewal.keyType.value.1=encryption + */ + String keyType = getRenewConfigKeyType(i); + boolean renewEnabled = getRenewEnabled(keyType); + CMS.debug(method + ": key type " + keyType); + if (!renewEnabled) { + CMS.debug(method + ": renew not enabled"); + continue; + } + + CMS.debug(method + ": renew enabled"); + + certsInfo.setCurrentCertIndex(i); + + CertEnrollInfo cEnrollInfo = new CertEnrollInfo(); + IConfigStore configStore = CMS.getConfigStore(); + + // find all config + String configName = null; + boolean graceEnabled = false; + String graceBeforeS = null; + String graceAfterS = null; + try { + String keyTypePrefix = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + ".renewal." + keyType; + + //TODO: profileId is actually gotten in the CARemoteRequestHandler. + configName = keyTypePrefix + ".ca.profileId"; + String profileId; + profileId = configStore.getString(configName); + CMS.debug(method + ": profileId: " + profileId); + + configName = keyTypePrefix + ".gracePeriod.enable"; + graceEnabled = configStore.getBoolean(configName, false); + if (graceEnabled) { + CMS.debug(method + ": grace period check is enabled"); + configName = keyTypePrefix + ".gracePeriod.before"; + graceBeforeS = configStore.getString(configName, ""); + configName = keyTypePrefix + ".gracePeriod.after"; + graceAfterS = configStore.getString(configName, ""); + } else { + CMS.debug(method + ": grace period check is not enabled"); + } + + configName = keyTypePrefix + ".certId"; + String certId = configStore.getString(configName, "C0"); + CMS.debug(method + ": certId: " + certId); + + configName = keyTypePrefix + ".certAttrId"; + String certAttrId = configStore.getString(configName, "c0"); + CMS.debug(method + ": certAttrId: " + certAttrId); + + configName = keyTypePrefix + ".privateKeyAttrId"; + String priKeyAttrId = configStore.getString(configName, "k0"); + CMS.debug(method + ": privateKeyAttrId: " + priKeyAttrId); + + configName = keyTypePrefix + ".publicKeyAttrId"; + String publicKeyAttrId = configStore.getString(configName, "k1"); + CMS.debug(method + ": publicKeyAttrId: " + publicKeyAttrId); + + } catch (EBaseException e) { + throw new TPSException(method + ": Internal error finding config value: " + configName + ":" + + e, + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + } + + // find the certs that match the keyType to renew + for (TPSCertRecord cert : allCerts) { + if (keyType.equals(cert.getKeyType())) { + try { + CMS.debug(method + ": cert " + cert.getId() + " with status:" + cert.getStatus()); + if (cert.getStatus().equals("revoked") || + cert.getStatus().equals("renewed")) { + CMS.debug(method + ": cert status is not to be renewed"); + continue; + } + + // check if within grace period to save us a trip (note: CA makes the final decision) + if (graceEnabled) { + try { + if (!isCertWithinRenewalGracePeriod(cert, graceBeforeS, graceAfterS)) + continue; + } catch (TPSException ge) { + // error in this will just log and keep going + CMS.debug(method + ":" + ge + "; continue to try renewal"); + } + } + + //Renew and fetch the renewed cert blob. + + CARenewCertResponse certResponse = tps.getEngine().renewCertificate(cert, + cert.getSerialNumber(), selectedTokenType, keyType, getCAConnectorID()); + cEnrollInfo.setRenewedCertData(certResponse); + + generateCertificate(certsInfo, channel, aInfo, keyType, TPSEngine.ENROLL_MODES.MODE_RENEWAL, + 0, cEnrollInfo); + + //renewCertificate(cert, certsInfo, channel, aInfo, keyType); + status = TPSStatus.STATUS_ERROR_RENEWAL_IS_PROCESSED; + } catch (TPSException e) { + CMS.debug(method + "renewCertificate: exception:" + e); + noFailedCerts = false; + break; //need to clean up half-done token later + } + } + } + } + + if (!noFailedCerts) { + // TODO: handle cleanup + auditMsg = "There has been failed cert renewal"; + CMS.debug(method + ":" + auditMsg); + throw new TPSException(auditMsg + TPSStatus.STATUS_ERROR_RENEWAL_FAILED); + } + return status; + } + + /* + * isCertWithinRenewalGracePeriod - check if a cert is within the renewal grace period + * @param cert the cert to be renewed + * @param renewGraceBeforeS string representation of the # of days "before" cert expiration date + * @param renewGraceAfterS string representation of the # of days "after" cert expiration date + */ + private boolean isCertWithinRenewalGracePeriod(TPSCertRecord cert, String renewGraceBeforeS, String renewGraceAfterS) + throws TPSException { + String method = "TPSEnrollProcessor.isCertWithinRenewalGracePeriod"; + int renewGraceBefore = 0; + int renewGraceAfter = 0; + + if (cert == null || renewGraceBeforeS == null || renewGraceAfterS == null) { + CMS.debug(method + ": missing some input"); + throw new TPSException(method + ": Bad Input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + BigInteger renewGraceBeforeBI = new BigInteger(renewGraceBeforeS); + BigInteger renewGraceAfterBI = new BigInteger(renewGraceAfterS); + + // -1 means no limit + if (renewGraceBeforeS == "") + renewGraceBefore = -1; + else + renewGraceBefore = Integer.parseInt(renewGraceBeforeS); + + if (renewGraceAfterS == "") + renewGraceAfter = -1; + else + renewGraceAfter = Integer.parseInt(renewGraceAfterS); + + if (renewGraceBefore > 0) + renewGraceBeforeBI = renewGraceBeforeBI.multiply(BigInteger.valueOf(1000 * 86400)); + if (renewGraceAfter > 0) + renewGraceAfterBI = renewGraceAfterBI.multiply(BigInteger.valueOf(1000 * 86400)); + + Date origExpDate = cert.getValidNotAfter(); + Date current = CMS.getCurrentDate(); + long millisDiff = origExpDate.getTime() - current.getTime(); + CMS.debug(method + ": millisDiff=" + + millisDiff + " origExpDate=" + origExpDate.getTime() + " current=" + current.getTime()); + + /* + * "days", if positive, has to be less than renew_grace_before + * "days", if negative, means already past expiration date, + * (abs value) has to be less than renew_grace_after + * if renew_grace_before or renew_grace_after are negative + * the one with negative value is ignored + */ + if (millisDiff >= 0) { + if ((renewGraceBefore > 0) && (millisDiff > renewGraceBeforeBI.longValue())) { + CMS.debug(method + ": renewal attempted outside of grace period;" + + renewGraceBefore + " days before and " + + renewGraceAfter + " days after original cert expiration date"); + return false; + } + } else { + if ((renewGraceAfter > 0) && ((0 - millisDiff) > renewGraceAfterBI.longValue())) { + CMS.debug(method + ": renewal attempted outside of grace period;" + + renewGraceBefore + " days before and " + + renewGraceAfter + " days after original cert expiration date"); + return false; + } + } + return true; + } + + private boolean getRenewEnabled(String keyType) { + String method = "TPSEnrollProcessor.getRenewEnabled"; + IConfigStore configStore = CMS.getConfigStore(); + boolean enabled = false; + + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + ".renewal." + + keyType + "." + "enable"; + enabled = configStore.getBoolean( + configValue, false); + + } catch (EBaseException e) { + //default to false + } + + CMS.debug(method + ": returning " + enabled); + return enabled; + } + + private String getRenewConfigKeyType(int keyTypeIndex) throws TPSException { + String method = "TPSEnrollProcessor.getRenewConfigKeyType"; + IConfigStore configStore = CMS.getConfigStore(); + String keyType = null; + + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + + TPSEngine.CFG_RENEW_KEYTYPE_VALUE + "." + keyTypeIndex; + keyType = configStore.getString( + configValue, null); + + } catch (EBaseException e) { + throw new TPSException( + method + ": Internal error finding config value: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + //We would really like one of these to exist + if (keyType == null) { + throw new TPSException( + method + ": Internal error finding config value: ", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + CMS.debug(method + ": returning: " + keyType); + + return keyType; + + } + + private int getNumberCertsToRenew() throws TPSException { + String method = "TPSEnrollProcessor.getNumberCertsToRenew"; + + IConfigStore configStore = CMS.getConfigStore(); + int keyTypeNum = 0; + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + + TPSEngine.CFG_RENEW_KEYTYPE_NUM; + keyTypeNum = configStore.getInteger( + configValue, 0); + + } catch (EBaseException e) { + throw new TPSException(method + ": Internal error finding config value: " + + e, + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + } + + if (keyTypeNum == 0) { + throw new TPSException( + method + ": invalid number of certificates to renew configured!", + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + } + CMS.debug(method + ": returning: " + keyTypeNum); + + return keyTypeNum; + } + + private TPSStatus processRecovery(TokenRecord toBeRecovered, EnrolledCertsInfo certsInfo, SecureChannel channel, + AppletInfo aInfo) throws TPSException, IOException { + String method = "TPSEnrollProcessor.processRecover"; + String auditMsg; + TPSStatus status = TPSStatus.STATUS_ERROR_RECOVERY_IS_PROCESSED; + + TPSSubsystem tps = (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID); + IConfigStore configStore = CMS.getConfigStore(); + + CMS.debug("TPSEnrollProcessor.processRecovery: entering:"); + + if (toBeRecovered == null || certsInfo == null || channel == null || aInfo == null) { + throw new TPSException("TPSEnrollProcessor.processRecovery: Invalid reason!", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + + String reason = toBeRecovered.getReason(); + + int num = getNumberCertsForRecovery(reason); + + int totalNumCerts = 0; + + //We will have to rifle through the configuration to see if there any recovery operations with + //scheme "GenerateNewKeyandRecoverLast" which allows for recovering the old key AND generating a new + // one for the encryption type only. If this scheme is present, the number of certs for bump by + // 1 for each occurrence. + + String keyTypeValue = null; + String scheme = null; + CMS.debug("TPSEnrollProcessor.processRecovery: About to find if we have any GenerateNewAndRecoverLast schemes."); + for (int i = 0; i < num; i++) { + keyTypeValue = getRecoveryKeyTypeValue(reason, i); + scheme = getRecoveryScheme(reason, keyTypeValue); + + if (scheme.equals(TPSEngine.RECOVERY_SCHEME_GENERATE_NEW_KEY_AND_RECOVER_LAST)) { + + //Make sure we are not signing: + if (keyTypeValue.equals(TPSEngine.CFG_SIGNING)) { + throw new TPSException( + "TPSEnrollProcessor.processRecovery: Can't have GenerateNewAndRecoverLast scheme with a signing key!", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + totalNumCerts++; + } + totalNumCerts++; + } + + CMS.debug("TPSEnrollProcessor.processRecovery: About to perform actual recoveries: totalNumCerts: " + + totalNumCerts); + + if (!(totalNumCerts > num)) { + totalNumCerts = num; + } + + boolean isGenerateAndRecover = false; + int actualCertIndex = 0; + boolean legalScheme = false; + + //Go through again and do the recoveries/enrollments + + certsInfo.setNumCertsToEnroll(totalNumCerts); + for (int i = 0; i < num; i++) { + + keyTypeValue = getRecoveryKeyTypeValue(reason, i); + scheme = getRecoveryScheme(reason, keyTypeValue); + + if (scheme.equals(TPSEngine.RECOVERY_SCHEME_GENERATE_NEW_KEY_AND_RECOVER_LAST)) { + CMS.debug("TPSEnrollProcessor.processRecovery: scheme GenerateNewKeyAndRecoverLast found."); + isGenerateAndRecover = true; + + } else { + isGenerateAndRecover = false; + } + + if (scheme.equals(TPSEngine.RECOVERY_GENERATE_NEW_KEY) || isGenerateAndRecover) { + legalScheme = true; + CertEnrollInfo cEnrollInfo = new CertEnrollInfo(); + generateCertificate(certsInfo, channel, aInfo, keyTypeValue, TPSEngine.ENROLL_MODES.MODE_ENROLL, + actualCertIndex, cEnrollInfo); + + actualCertIndex = cEnrollInfo.getCertIdIndex(); + CMS.debug("TPSEnrollProcessor.processRecovery: scheme GenerateNewKey found, or isGenerateAndRecove is true: actualCertIndex, after enrollment: " + + actualCertIndex); + + } + + if (scheme.equals(TPSEngine.RECOVERY_RECOVER_LAST) || isGenerateAndRecover) { + legalScheme = true; + CMS.debug("TPSEnrollProcessor.processRecovery: scheme RecoverLast found, or isGenerateAndRecove is true"); + if (isGenerateAndRecover) { + CMS.debug("TPSEnrollProcessor.processRecovery: isGenerateAndRecover is true."); + actualCertIndex++; + } + + ArrayList<TPSCertRecord> certs = tps.tdb.tdbGetCertificatesByCUID(toBeRecovered.getId()); + + String serialToRecover = null; + TPSCertRecord certToRecover = null; + for (TPSCertRecord rec : certs) { + + //Just take the end of the list most recent cert of given type. + CMS.debug("TPSEnrollProcessor.processRecovery: Looking for keyType record: " + keyTypeValue + + " curSererial: " + rec.getSerialNumber()); + + if (rec.getKeyType().equals(keyTypeValue)) { + serialToRecover = rec.getSerialNumber(); + certToRecover = rec; + CMS.debug("TPSCertRecord: serial number: " + serialToRecover); + } + + } + String b64cert = null; + if (serialToRecover != null) { + // get recovery conn id + String caConnId; + String config = "op.enroll." + certToRecover.getType() + ".keyGen." + certToRecover.getKeyType() + ".ca.conn"; + try { + caConnId = configStore.getString(config); + } catch (Exception e) { + auditMsg = "cannot find config:" + config; + CMS.debug(method + ":" + auditMsg); + throw new TPSException( + method + ":" + auditMsg, + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + CMS.debug("TPSEnrollProcessor.processRecovery: Selecting cert to recover: " + serialToRecover); + + CARetrieveCertResponse certResponse = tps.getEngine().recoverCertificate(certToRecover, + serialToRecover, keyTypeValue, caConnId); + + b64cert = certResponse.getCertB64(); + CMS.debug("TPSEnrollProcessor.processRecovery: recoverd cert blob: " + b64cert); + + KRARecoverKeyResponse keyResponse = tps.getEngine().recoverKey(toBeRecovered.getId(), + toBeRecovered.getUserID(), + channel.getDRMWrappedDesKey(), b64cert, getDRMConnectorID()); + + CertEnrollInfo cEnrollInfo = new CertEnrollInfo(); + + cEnrollInfo.setTokenToBeRecovered(toBeRecovered); + cEnrollInfo.setRecoveredCertData(certResponse); + cEnrollInfo.setRecoveredKeyData(keyResponse); + + generateCertificate(certsInfo, channel, aInfo, keyTypeValue, TPSEngine.ENROLL_MODES.MODE_RECOVERY, + actualCertIndex, cEnrollInfo); + + // unrevoke cert if needed + if (certToRecover.getStatus().equalsIgnoreCase("revoked_on_hold")) { + auditMsg = "unrevoking cert..."; + CMS.debug(method + ":" + auditMsg); + + CARemoteRequestHandler caRH = null; + try { + caRH = new CARemoteRequestHandler(caConnId); + + CARevokeCertResponse response = + caRH.revokeCertificate(false /*unrevoke*/, serialToRecover, + certToRecover.getCertificate(), + null); + CMS.debug(method + ": response status =" + response.getStatus()); + + } catch (EBaseException e) { + auditMsg = "failed getting CARemoteRequestHandler"; + CMS.debug(method + ":" + auditMsg); + throw new TPSException(method + ":" + auditMsg, TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + } + + // set cert status to active + certToRecover.setStatus("active"); + try { + tps.tdb.tdbUpdateCertEntry(certToRecover); + } catch (Exception e) { + auditMsg = "failed tdbUpdateCertEntry"; + CMS.debug(method + ":" + auditMsg); + throw new TPSException(method + ":" + auditMsg, TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + } else { + + } + + } + + if (!legalScheme) { + throw new TPSException("TPSEnrollProcessor.processRecovery: Invalid recovery configuration!", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + actualCertIndex++; + + } + + return status; + } + + //Stub to generate a certificate, more to come + private boolean generateCertificates(EnrolledCertsInfo certsInfo, SecureChannel channel, AppletInfo aInfo) + throws TPSException, IOException { + + CMS.debug("TPSEnrollProcess.generateCertificates: begins "); + boolean noFailedCerts = true; + + if (certsInfo == null || aInfo == null || channel == null) { + throw new TPSException("TPSEnrollProcessor.generateCertificates: Bad Input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + int keyTypeNum = getNumberCertsToEnroll(); + + certsInfo.setNumCertsToEnroll(keyTypeNum); + + CMS.debug("TPSEnrollProcessor.generateCertificate: Number of certs to enroll: " + keyTypeNum); + + for (int i = 0; i < keyTypeNum; i++) { + String keyType = getConfiguredKeyType(i); + certsInfo.setCurrentCertIndex(i); + try { + generateCertificate(certsInfo, channel, aInfo, keyType, TPSEngine.ENROLL_MODES.MODE_ENROLL, 0, null); + } catch (TPSException e) { + CMS.debug("TPSEnrollProcessor.generateCertificate: exception:" + e); + noFailedCerts = false; + break; //need to clean up half-done token later + } + } + + /* + * In this special case of RE_ENROLL, Revoke current certs for this token + * if so configured + */ + /*TODO: format that follows should do this already based on the returned noFailedCerts value + if (noFailedCerts == true) { + revokeCertificates(aInfo.getCUIDhexStringPlain()); + } + */ + + CMS.debug("TPSEnrollProcessor.generateCertificates: ends "); + return noFailedCerts; + } + + private String buildTokenLabel(EnrolledCertsInfo certsInfo, AppletInfo ainfo) throws TPSException { + String label = null; + + if (certsInfo == null || ainfo == null) { + throw new TPSException("TPSEnrollProcessor.buildTokenLabel: invalide input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + CMS.debug("TPSEnrollProcessor.buildTokenLabel: entering..."); + + IConfigStore configStore = CMS.getConfigStore(); + + String configName = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType() + ".keyGen.tokenName"; + String pattern = null; + + try { + pattern = configStore.getString(configName, "$cuid$"); + } catch (EBaseException e) { + throw new TPSException( + "TPSEnrollProcessor.buildTokenLabel: Internal error finding config value: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + + } + + CMS.debug("TPSEnrollProcessor.buildTokenLabel: pattern: " + pattern); + + Map<String, String> nv = new LinkedHashMap<String, String>(); + + nv.put("cuid", ainfo.getCUIDhexString()); + nv.put("msn", ainfo.getMSNString()); + nv.put("userid", userid); + nv.put("auth.cn", userid); + nv.put("profileId", getSelectedTokenType()); + + label = mapPattern((LinkedHashMap<String, String>) nv, pattern); + + CMS.debug("TPSEnrollProcessor.buildTokenLabel: returning: " + label); + + return label; + + } + + /* This routine will be able to handle: + * regular enrollment + * recovery enrollment + * renewal enrollment + */ + private void generateCertificate(EnrolledCertsInfo certsInfo, SecureChannel channel, AppletInfo aInfo, + String keyType, TPSEngine.ENROLL_MODES mode, int certIdNumOverride, CertEnrollInfo cEnrollInfo) + throws TPSException, IOException { + + CMS.debug("TPSEnrollProcessor.generateCertificate: entering ... certIdNumOverride: " + certIdNumOverride + + " mode: " + mode); + + if (certsInfo == null || aInfo == null || channel == null || aInfo == null) { + throw new TPSException("TPSEnrollProcessor.generateCertificate: Bad Input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + //get the params needed all at once + + IConfigStore configStore = CMS.getConfigStore(); + + boolean isRenewal = false; + + // This operation modifier allows us to get config entries for either + // regular enrollment and renewal. Allows the re-use of repetitive config processing code below. + String operationModifier = "keyGen"; + if (mode == ENROLL_MODES.MODE_RENEWAL) { + isRenewal = true; + operationModifier = "renewal"; + } + + if (cEnrollInfo == null) + cEnrollInfo = new CertEnrollInfo(); + + try { + + String keyTypePrefix = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType() + "." + operationModifier + + "." + keyType; + CMS.debug("TPSEnrollProcessor.generateCertificate: keyTypePrefix: " + keyTypePrefix); + + String configName = keyTypePrefix + ".ca.profileId"; + String profileId = configStore.getString(configName); + CMS.debug("TPSEnrollProcessor.generateCertificate: profileId: " + profileId); + + configName = keyTypePrefix + ".certId"; + String certId = configStore.getString(configName, "C0"); + CMS.debug("TPSEnrollProcessor.generateCertificate: certId: " + certId); + + configName = keyTypePrefix + ".certAttrId"; + String certAttrId = configStore.getString(configName, "c0"); + CMS.debug("TPSEnrollProcessor.generateCertificate: certAttrId: " + certAttrId); + + configName = keyTypePrefix + ".privateKeyAttrId"; + String priKeyAttrId = configStore.getString(configName, "k0"); + CMS.debug("TPSEnrollProcessor.generateCertificate: priKeyAttrId: " + priKeyAttrId); + + configName = keyTypePrefix + ".publicKeyAttrId"; + String publicKeyAttrId = configStore.getString(configName, "k1"); + CMS.debug("TPSEnrollProcessor.generateCertificate: publicKeyAttrId: " + publicKeyAttrId); + + configName = keyTypePrefix + ".keySize"; + int keySize = configStore.getInteger(configName, 1024); + CMS.debug("TPSEnrollProcessor.generateCertificate: keySize: " + keySize); + + //Default RSA_CRT=2 + configName = keyTypePrefix + ".alg"; + int algorithm = configStore.getInteger(configName, 2); + CMS.debug("TPSEnrollProcessor.generateCertificate: algorithm: " + algorithm); + + configName = keyTypePrefix + ".publisherId"; + String publisherId = configStore.getString(configName, ""); + CMS.debug("TPSEnrollProcessor.generateCertificate: publisherId: " + publisherId); + + configName = keyTypePrefix + ".keyUsage"; + int keyUsage = configStore.getInteger(configName, 0); + CMS.debug("TPSEnrollProcessor.generateCertificate: keyUsage: " + keyUsage); + + configName = keyTypePrefix + ".keyUser"; + int keyUser = configStore.getInteger(configName, 0); + CMS.debug("TPSEnrollProcessor.generateCertificate: keyUser: " + keyUser); + + configName = keyTypePrefix + ".privateKeyNumber"; + int priKeyNumber = configStore.getInteger(configName, 0); + CMS.debug("TPSEnrollProcessor.generateCertificate: privateKeyNumber: " + priKeyNumber); + + configName = keyTypePrefix + ".publicKeyNumber"; + int pubKeyNumber = configStore.getInteger(configName, 0); + CMS.debug("TPSEnrollProcessor.generateCertificate: pubKeyNumber: " + pubKeyNumber); + + // get key capabilites to determine if the key type is SIGNING, + // ENCRYPTION, or SIGNING_AND_ENCRYPTION + + configName = keyTypePrefix + ".private.keyCapabilities.sign"; + boolean isSigning = configStore.getBoolean(configName, false); + CMS.debug("TPSEnrollProcessor.generateCertificate: isSigning: " + isSigning); + + configName = keyTypePrefix + ".public.keyCapabilities.encrypt"; + CMS.debug("TPSEnrollProcessor.generateCertificate: encrypt config name: " + configName); + boolean isEncrypt = configStore.getBoolean(configName, true); + CMS.debug("TPSEnrollProcessor.generateCertificate: isEncrypt: " + isEncrypt); + + TokenKeyType keyTypeEnum; + + if (isSigning && isEncrypt) { + keyTypeEnum = TokenKeyType.KEY_TYPE_SIGNING_AND_ENCRYPTION; + } else if (isSigning) { + keyTypeEnum = TokenKeyType.KEY_TYPE_SIGNING; + } else if (isEncrypt) { + keyTypeEnum = TokenKeyType.KEY_TYPE_ENCRYPTION; + } else { + CMS.debug("TPSEnrollProcessor.generateCertificate: Illegal toke key type!"); + throw new TPSException("TPSEnrollProcessor.generateCertificate: Illegal toke key type!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + CMS.debug("TPSEnrollProcessor.generateCertificate: keyTypeEnum value: " + keyTypeEnum); + + // The certIdNumOverride allows us to place the certs and keys into a different slot. + // Thus overriding what is found in the config. + // Used in recovery mostly up to this point. + + if (certIdNumOverride > 0) { + CMS.debug("TPSEnrollProcessor.generateCertificate: called with overridden cert id number: " + + certIdNumOverride); + + pubKeyNumber = 2 * certIdNumOverride + 1; + priKeyNumber = 2 * certIdNumOverride; + + certId = "C" + certIdNumOverride; + certAttrId = "c" + certIdNumOverride; + priKeyAttrId = "k" + priKeyNumber; + publicKeyAttrId = "k" + pubKeyNumber; + + CMS.debug("TPSEnrollProcessor.generateCertificate: called with overridden cert no: certId: " + certId + + " certAttrId: " + certAttrId + " priKeyAttrId: " + priKeyAttrId + " publicKeyAttrId: " + + publicKeyAttrId); + + } + + cEnrollInfo.setKeyTypeEnum(keyTypeEnum); + cEnrollInfo.setProfileId(profileId); + cEnrollInfo.setCertId(certId); + cEnrollInfo.setCertAttrId(certAttrId); + + // These setting are key related and have no meaning in renewal. + if (isRenewal == false) { + cEnrollInfo.setPrivateKeyAttrId(priKeyAttrId); + cEnrollInfo.setPublicKeyAttrId(publicKeyAttrId); + cEnrollInfo.setKeySize(keySize); + cEnrollInfo.setAlgorithm(algorithm); + cEnrollInfo.setPublisherId(publisherId); + cEnrollInfo.setKeyUsage(keyUsage); + cEnrollInfo.setKeyUser(keyUser); + cEnrollInfo.setPrivateKeyNumber(priKeyNumber); + cEnrollInfo.setPublicKeyNumber(pubKeyNumber); + cEnrollInfo.setKeyType(keyType); + cEnrollInfo.setKeyTypePrefix(keyTypePrefix); + } + + int certsStartProgress = certsInfo.getStartProgressValue(); + int certsEndProgress = certsInfo.getEndProgressValue(); + int currentCertIndex = certsInfo.getCurrentCertIndex(); + int totalNumCerts = certsInfo.getNumCertsToEnroll(); + + int progressBlock = (certsEndProgress - certsStartProgress) / totalNumCerts; + + int startCertProgValue = certsStartProgress + currentCertIndex * progressBlock; + + int endCertProgValue = startCertProgValue + progressBlock; + + cEnrollInfo.setStartProgressValue(startCertProgValue); + cEnrollInfo.setEndProgressValue(endCertProgValue); + + } catch (EBaseException e) { + + throw new TPSException( + "TPSEnrollProcessor.generateCertificate: Internal error finding config value: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + enrollOneCertificate(certsInfo, cEnrollInfo, aInfo, channel, mode); + + } + + /* Core method handles the following modes: + * Regular enrollment + * Recovery enrollment + * Renewal enrollment + */ + private void enrollOneCertificate(EnrolledCertsInfo certsInfo, CertEnrollInfo cEnrollInfo, AppletInfo aInfo, + SecureChannel channel, TPSEngine.ENROLL_MODES mode) + throws TPSException, IOException { + + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: entering ... mode: " + mode); + + if (certsInfo == null || aInfo == null || cEnrollInfo == null || channel == null) { + throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: Bad Input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + statusUpdate(cEnrollInfo.getStartProgressValue(), "PROGRESS_KEY_GENERATION"); + boolean serverSideKeyGen = checkForServerSideKeyGen(cEnrollInfo); + boolean objectOverwrite = checkForObjectOverwrite(cEnrollInfo); + + PKCS11Obj pkcs11obj = certsInfo.getPKCS11Obj(); + + int keyAlg = cEnrollInfo.getAlgorithm(); + + boolean isECC = getTPSEngine().isAlgorithmECC(keyAlg); + + if (objectOverwrite) { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: We are configured to overwrite existing cert objects."); + + } else { + + boolean certIdExists = pkcs11obj.doesCertIdExist(cEnrollInfo.getCertId()); + + //Bomb out if cert exists, we ca't overwrite + + if (certIdExists) { + throw new TPSException( + "TPSEnrollProcessor.enrollOneCertificate: Overwrite of certificates not allowed!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + } + + TPSBuffer public_key_blob = null; + KRAServerSideKeyGenResponse ssKeyGenResponse = null; + KRARecoverKeyResponse keyResp = null; + RSAPublicKey parsedPubKey = null; + PK11PubKey parsedPK11PubKey = null; + byte[] parsedPubKey_ba = null; + + boolean isRecovery = false; + boolean isRenewal = false; + + if (mode == ENROLL_MODES.MODE_RECOVERY) { + isRecovery = true; + + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: detecting recovery mode!"); + if (isRecovery && !serverSideKeyGen) { + throw new TPSException( + "TPSEnrollProcessor.enrollOneCertificate: Attempting illegal recovery when archival is not enabled!", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + } + + if (mode == ENROLL_MODES.MODE_RENEWAL) { + isRenewal = true; + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: detecting renewal mode!"); + } + + if (serverSideKeyGen || isRecovery) { + //Handle server side keyGen/recovery + // The main difference is where the key and cert data is obtained. + // In recovery the cert and key are recovered. + // In server side key gen, cert is enrolled and key is generated and recovered. + + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: either generate private key on the server, or preform recovery or perform renewal."); + boolean archive = checkForServerKeyArchival(cEnrollInfo); + String drmConnId = getDRMConnectorID(); + + String publicKeyStr = null; + //Do this for JUST server side keygen + if (isRecovery == false) { + ssKeyGenResponse = getTPSEngine() + .serverSideKeyGen(cEnrollInfo.getKeySize(), + aInfo.getCUIDhexStringPlain(), userid, drmConnId, channel.getDRMWrappedDesKey(), + archive, isECC); + + publicKeyStr = ssKeyGenResponse.getPublicKey(); + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: public key string from server: " + publicKeyStr); + public_key_blob = new TPSBuffer(Utils.base64decode(publicKeyStr)); + + } else { + //Here we have a recovery, get the key data from the CertInfo object + + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: Attempt to get key data in recovery mode!"); + keyResp = cEnrollInfo.getRecoveredKeyData(); + + publicKeyStr = keyResp.getPublicKey(); + public_key_blob = new TPSBuffer(Utils.base64decode(publicKeyStr)); + + } + + try { + parsedPK11PubKey = PK11RSAPublicKey.fromSPKI(public_key_blob.toBytesArray()); + + } catch (InvalidKeyFormatException e) { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate, can't create public key object from server side key generated public key blob!"); + throw new TPSException( + "TPSEnrollProcessor.enrollOneCertificate, can't create public key object from server side key generated public key blob!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + parsedPubKey_ba = parsedPK11PubKey.getEncoded(); + + } else if (isRenewal) { + + CMS.debug("TPSEnrollProcessor: We are in renewal mode, no work to do with the keys, in renewal the keys remain on the token."); + + } else { + //Handle token side keyGen + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: about to generate the private key on the token."); + + int algorithm = 0x80; + + if (certsInfo.getKeyCheck() != null) { + algorithm = 0x81; + } + + if (isECC) { + algorithm = keyAlg; + } + + int pe1 = (cEnrollInfo.getKeyUser() << 4) + cEnrollInfo.getPrivateKeyNumber(); + int pe2 = (cEnrollInfo.getKeyUsage() << 4) + cEnrollInfo.getPublicKeyNumber(); + + int size = channel.startEnrollment(pe1, pe2, certsInfo.getWrappedChallenge(), certsInfo.getKeyCheck(), + algorithm, cEnrollInfo.getKeySize(), 0x0); + + byte[] iobytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; + TPSBuffer iobuf = new TPSBuffer(iobytes); + + public_key_blob = channel.readObject(iobuf, 0, size); + + parsedPubKey = parsePublicKeyBlob(public_key_blob, isECC); + + parsedPubKey_ba = parsedPubKey.getEncoded(); + } + + // enrollment/recovery begins + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: enrollment begins"); + X509CertImpl x509Cert = null; + byte[] cert_bytes = null; + try { + + if (isRecovery == false && isRenewal == false) { + String caConnID = getCAConnectorID(); + CARemoteRequestHandler caRH = new CARemoteRequestHandler(caConnID); + TPSBuffer encodedParsedPubKey = new TPSBuffer(parsedPubKey_ba); + + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: userid =" + userid + ", cuid=" + + aInfo.getCUIDhexString()); + CAEnrollCertResponse caEnrollResp = caRH.enrollCertificate(encodedParsedPubKey, userid, + aInfo.getCUIDhexString(), getSelectedTokenType(), + cEnrollInfo.getKeyType()); + String retCertB64 = caEnrollResp.getCertB64(); + + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: retCertB64: " + retCertB64); + + cert_bytes = Utils.base64decode(retCertB64); + + TPSBuffer cert_bytes_buf = new TPSBuffer(cert_bytes); + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: retCertB64: " + cert_bytes_buf.toHexString()); + + if (retCertB64 != null) + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: new cert b64 =" + retCertB64); + else { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: new cert b64 not found"); + throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: new cert b64 not found", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + x509Cert = caEnrollResp.getCert(); + if (x509Cert != null) + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: new cert retrieved"); + else { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: new cert not found"); + throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: new cert not found", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + } else { + //Import the cert data from the CertEnrollObject or from Renewal object + + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: Attempt to import cert data in recovery mode or renew mode!"); + + if (isRecovery) { + CARetrieveCertResponse certResp = cEnrollInfo.getRecoveredCertData(); + + if (certResp == null) { + throw new TPSException( + "TPSEnrollProcessor.enrollOneCertificate: In recovery mode, CARetieveCertResponse object not found!", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + + String retCertB64 = certResp.getCertB64(); + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: recovering: retCertB64: " + retCertB64); + cert_bytes = Utils.base64decode(retCertB64); + + TPSBuffer cert_bytes_buf = new TPSBuffer(cert_bytes); + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: recovering: retCertB64: " + + cert_bytes_buf.toHexString()); + + if (retCertB64 != null) + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: recovering: new cert b64 =" + retCertB64); + else { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: recovering new cert b64 not found"); + throw new TPSException( + "TPSEnrollProcessor.enrollOneCertificate: recovering: new cert b64 not found", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + x509Cert = certResp.getCert(); + if (x509Cert != null) + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: recovering new cert retrieved"); + else { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: recovering new cert not found"); + throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: new cert not found", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + + } + + // If we are here, it has to be one or the other. + + if (isRenewal) { + + CARenewCertResponse certResp = cEnrollInfo.getRenewedCertData(); + if (certResp == null) { + throw new TPSException( + "TPSEnrollProcessor.enrollOneCertificate: In renewal mode, CARemewCertResponse object not found!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + String retCertB64 = certResp.getRenewedCertB64(); + cert_bytes = Utils.base64decode(retCertB64); + + if (retCertB64 != null) + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: renewing: new cert b64 =" + retCertB64); + else { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: renewing new cert b64 not found"); + throw new TPSException( + "TPSEnrollProcessor.enrollOneCertificate: remewomg: new cert b64 not found", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + x509Cert = certResp.getRenewedCert(); + + if (x509Cert != null) + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: renewing new cert retrieved"); + else { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: renewing new cert not found"); + throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: new cert not found", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + + TPSBuffer cert_bytes_buf = new TPSBuffer(cert_bytes); + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: renewing: retCertB64: " + + cert_bytes_buf.toHexString()); + + } + + } + + certsInfo.addCertificate(x509Cert); + // In renewal case, we don't need to save this info. + if (!isRenewal) { + certsInfo.addKType(cEnrollInfo.getKeyType()); + } + + //Add origin, special handling for recovery case. + if (isRecovery == true) { + TokenRecord recordToRecover = cEnrollInfo.getTokenToBeRecovered(); + //We need to have this token record otherwise bomb out. + + if (recordToRecover == null) { + throw new TPSException( + "TPSEnrollProcessor.enrollOneCertificate: TokenRecord of token to be recovered not found.", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + + certsInfo.addOrigin(recordToRecover.getId()); + + } else { + certsInfo.addOrigin(aInfo.getCUIDhexStringPlain()); + } + + certsInfo.addTokenType(selectedTokenType); + + SubjectPublicKeyInfo publicKeyInfo = null; + + String label = null; + TPSBuffer keyid = null; + TPSBuffer modulus = null; + TPSBuffer exponent = null; + + if (!isRenewal) { + + try { + if (serverSideKeyGen) { + publicKeyInfo = new SubjectPublicKeyInfo(parsedPK11PubKey); + } else { + publicKeyInfo = new SubjectPublicKeyInfo(parsedPubKey); + } + } catch (InvalidBERException e) { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: cant get publicKeyInfo object."); + throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: can't get publcKeyInfo object.", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + //Create label ToDo: Do this the correct way later + + label = buildCertificateLabel(cEnrollInfo, aInfo); + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: cert label: " + label); + + keyid = new TPSBuffer(makeKeyIDFromPublicKeyInfo(publicKeyInfo.getEncoded())); + + modulus = null; + exponent = null; + + if (serverSideKeyGen) { + modulus = new TPSBuffer(((PK11RSAPublicKey) parsedPK11PubKey).getModulus().toByteArray()); + exponent = new TPSBuffer(((PK11RSAPublicKey) parsedPK11PubKey).getPublicExponent().toByteArray()); + + } else { + modulus = new TPSBuffer(parsedPubKey.getModulus().toByteArray()); + exponent = new TPSBuffer(parsedPubKey.getPublicExponent().toByteArray()); + } + + } + + //Write cert to the token,do this in all modes + + long l1, l2; + long objid; + PKCS11Obj pkcs11Obj = certsInfo.getPKCS11Obj(); + + String certId = cEnrollInfo.getCertId(); + + l1 = (certId.charAt(0) & 0xff) << 24; + l2 = (certId.charAt(1) & 0xff) << 16; + objid = l1 + l2; + + CMS.debug("TPSEnrollProcess.enrollOneCertificate: cert objid long: " + objid); + + ObjectSpec certObjSpec = ObjectSpec.parseFromTokenData(objid, new TPSBuffer(cert_bytes)); + pkcs11Obj.addObjectSpec(certObjSpec); + + //Do the rest of this stuff only in enrollment or recovery case, in renewal, we need not deal with the keys + + if (isRenewal == false) { + + String certAttrId = cEnrollInfo.getCertAttrId(); + + TPSBuffer certAttrsBuffer = channel.createPKCS11CertAttrsBuffer(cEnrollInfo.getKeyTypeEnum(), + certAttrId, label, keyid); + + l1 = (certAttrId.charAt(0) & 0xff) << 24; + l2 = (certAttrId.charAt(1) & 0xff) << 16; + objid = l1 + l2; + + CMS.debug("TPSEnrollProcess.enrollOneCertificate: cert attr objid long: " + objid); + ObjectSpec certAttrObjSpec = ObjectSpec.parseFromTokenData(objid, certAttrsBuffer); + pkcs11Obj.addObjectSpec(certAttrObjSpec); + + //Add the pri key attrs object + + String priKeyAttrId = cEnrollInfo.getPrivateKeyAttrId(); + + l1 = (priKeyAttrId.charAt(0) & 0xff) << 24; + l2 = (priKeyAttrId.charAt(1) & 0xff) << 16; + + objid = l1 + l2; + + CMS.debug("TPSEnrollProcess.enrollOneCertificate: pri key objid long: " + objid); + + TPSBuffer privKeyAttrsBuffer = channel.createPKCS11PriKeyAttrsBuffer(priKeyAttrId, label, keyid, + modulus, cEnrollInfo.getKeyTypePrefix()); + + ObjectSpec priKeyObjSpec = ObjectSpec.parseFromTokenData(objid, privKeyAttrsBuffer); + pkcs11obj.addObjectSpec(priKeyObjSpec); + + // Now add the public key object + + String pubKeyAttrId = cEnrollInfo.getPublicKeyAttrId(); + + l1 = (pubKeyAttrId.charAt(0) & 0xff) << 24; + l2 = (pubKeyAttrId.charAt(1) & 0xff) << 16; + + objid = l1 + l2; + CMS.debug("TPSEnrollProcess.enrollOneCertificate: pub key objid long: " + objid); + + TPSBuffer pubKeyAttrsBuffer = channel.createPKCS11PublicKeyAttrsBuffer(pubKeyAttrId, label, keyid, + modulus, exponent, cEnrollInfo.getKeyTypePrefix()); + ObjectSpec pubKeyObjSpec = ObjectSpec.parseFromTokenData(objid, pubKeyAttrsBuffer); + pkcs11obj.addObjectSpec(pubKeyObjSpec); + + } + } catch (EBaseException e) { + CMS.debug("TPSEnrollProcessor.enrollOneCertificate::" + e); + throw new TPSException("TPSEnrollProcessor.enrollOneCertificate: Exception thrown: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + if (serverSideKeyGen || isRecovery) { + //Handle injection of private key onto token + CMS.debug("TPSEnrollProcessor.enrollOneCertificate: About to inject private key"); + + if (!isRecovery) { + + // SecureChannel newChannel = setupSecureChannel(); + importPrivateKeyPKCS8(ssKeyGenResponse, cEnrollInfo, channel, isECC); + + } else { + importPrivateKeyPKCS8(keyResp, cEnrollInfo, channel, isECC); + } + + } + + CMS.debug("TPSEnrollProcessor.enrollOneCertificate:: enrollment ends"); + + statusUpdate(cEnrollInfo.getEndProgressValue(), "PROGRESS_ENROLL_CERT"); + CMS.debug("TPSEnrollProcessor.enrollOneCertificate ends"); + + } + + private void importPrivateKeyPKCS8(KRARecoverKeyResponse keyResp, CertEnrollInfo cEnrollInfo, + SecureChannel channel, + boolean isECC) throws TPSException, IOException { + + if (keyResp == null || cEnrollInfo == null || channel == null) { + throw new TPSException("TPSEnrollProcessor.importPrivateKeyPKCS8: invalid input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + importPrivateKeyPKCS8(keyResp.getWrappedPrivKey(), keyResp.getIVParam(), cEnrollInfo, channel, isECC); + + } + + private void importPrivateKeyPKCS8(KRAServerSideKeyGenResponse ssKeyGenResponse, CertEnrollInfo cEnrollInfo, + SecureChannel channel, + boolean isECC) throws TPSException, IOException { + + if (ssKeyGenResponse == null || cEnrollInfo == null || channel == null) { + throw new TPSException("TPSEnrollProcessor.importPrivateKeyPKCS8: invalid input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + importPrivateKeyPKCS8(ssKeyGenResponse.getWrappedPrivKey(), ssKeyGenResponse.getIVParam(), cEnrollInfo, + channel, isECC); + + } + + private void importPrivateKeyPKCS8(String wrappedPrivKeyStr, String ivParams, CertEnrollInfo cEnrollInfo, + SecureChannel channel, + boolean isECC) throws TPSException, IOException { + + CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8 entering.."); + if (wrappedPrivKeyStr == null || ivParams == null || cEnrollInfo == null || channel == null) { + throw new TPSException("TPSEnrollProcessor.importPrivateKeyPKCS8: invalid input data!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + byte[] objid = { + (byte) 0xFF, + 0x00, + (byte) 0xFF, + (byte) 0xF3 }; + + byte keytype = 0x09; //RSAPKCS8Pair + + // String wrappedPrivKeyStr = ssKeyGenResponse.getWrappedPrivKey(); + int keysize = cEnrollInfo.getKeySize(); + + TPSBuffer privKeyBlob = new TPSBuffer(); + + privKeyBlob.add((byte) 0x1); // encryption + privKeyBlob.add(keytype); + privKeyBlob.add((byte) (keysize / 256)); + privKeyBlob.add((byte) (keysize % 256)); + + TPSBuffer privKeyBuff = new TPSBuffer(Util.uriDecodeFromHex(wrappedPrivKeyStr)); + privKeyBlob.add(privKeyBuff); + + CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8 privKeyBlob: " + privKeyBlob.toHexString()); + + byte[] perms = { 0x40, + 0x00, + 0x40, + 0x00, + 0x40, + 0x00 }; + + TPSBuffer objIdBuff = new TPSBuffer(objid); + + channel.createObject(objIdBuff, new TPSBuffer(perms), privKeyBlob.size()); + + channel.writeObject(objIdBuff, privKeyBlob); + + TPSBuffer keyCheck = channel.getKeyCheck(); + + CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8 : keyCheck: " + keyCheck.toHexString()); + + // String ivParams = ssKeyGenResponse.getIVParam(); + CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8: ivParams: " + ivParams); + TPSBuffer ivParamsBuff = new TPSBuffer(Util.uriDecodeFromHex(ivParams)); + + if (ivParamsBuff.size() == 0) { + throw new TPSException("TPSEnrollProcessor.importPrivateKeyPKCS8: invalid iv vector!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + + } + + TPSBuffer kekWrappedDesKey = channel.getKekDesKey(); + + if (kekWrappedDesKey != null) + CMS.debug("TPSEnrollProcessor.importPrivateKeyPKCS8: keyWrappedDesKey: " + kekWrappedDesKey.toHexString()); + else + CMS.debug("TPSEnrollProcessor.iportPrivateKeyPKC8: null kekWrappedDesKey!"); + + byte alg = (byte) 0x80; + if (kekWrappedDesKey == null || kekWrappedDesKey.size() > 0) { + alg = (byte) 0x81; + } + + TPSBuffer data = new TPSBuffer(); + + data.add(objIdBuff); + data.add(alg); + data.add((byte) kekWrappedDesKey.size()); + data.add(kekWrappedDesKey); + data.add((byte) keyCheck.size()); + data.add(keyCheck); + data.add((byte) ivParamsBuff.size()); + data.add(ivParamsBuff); + + int pe1 = (cEnrollInfo.getKeyUser() << 4) + cEnrollInfo.getPrivateKeyNumber(); + int pe2 = (cEnrollInfo.getKeyUsage() << 4) + cEnrollInfo.getPublicKeyNumber(); + + channel.importKeyEnc(pe1, pe2, data); + + CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8 successful, leaving..."); + + } + + private String buildCertificateLabel(CertEnrollInfo cEnrollInfo, AppletInfo ainfo) throws TPSException { + + CMS.debug("TPSEnrollProcessor.buildCertificateLabel"); + + if (cEnrollInfo == null) { + throw new TPSException("TPSErollProcessor.buildCertificateLabel: Invalid input params!", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + String label = null; + String pattern = null; + + String defaultLabel = cEnrollInfo.getKeyType() + " key for $userid$"; + + IConfigStore configStore = CMS.getConfigStore(); + + String configValue = "op." + currentTokenOperation + "." + selectedTokenType + ".keyGen." + + cEnrollInfo.getKeyType() + ".label"; + + CMS.debug("TPSEnrollProcessor.buildCertificateLabel: label config: " + configValue); + + try { + pattern = configStore.getString( + configValue, defaultLabel); + + } catch (EBaseException e) { + throw new TPSException( + "TPSEnrollProcessor.buildCertificateLabel: Internal error finding config value: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + Map<String, String> nv = new LinkedHashMap<String, String>(); + + nv.put("cuid", ainfo.getCUIDhexString()); + nv.put("msn", ainfo.getMSNString()); + nv.put("userid", userid); + nv.put("auth.cn", userid); + nv.put("profileId", getSelectedTokenType()); + + label = mapPattern((LinkedHashMap<String, String>) nv, pattern); + + CMS.debug("TPSEnrollProcessor.buildCertificateLabel: returning: " + label); + + return label; + } + + /** + * Extracts information from the public key blob and verify proof. + * + * Muscle Key Blob Format (RSA Public Key) + * --------------------------------------- + * + * The key generation operation places the newly generated key into + * the output buffer encoding in the standard Muscle key blob format. + * For an RSA key the data is as follows: + * + * Byte Encoding (0 for plaintext) + * + * Byte Key Type (1 for RSA public) + * + * Short Key Length (1024 รป high byte first) + * + * Short Modulus Length + * + * Byte[] Modulus + * + * Short Exponent Length + * + * Byte[] Exponent + * + * + * ECC KeyBlob Format (ECC Public Key) + * ---------------------------------- + * + * Byte Encoding (0 for plaintext) + * + * Byte Key Type (10 for ECC public) + * + * Short Key Length (256, 384, 521 high byte first) + * + * Byte[] Key (W) + * + * + * Signature Format (Proof) + * --------------------------------------- + * + * The key generation operation creates a proof-of-location for the + * newly generated key. This proof is a signature computed with the + * new private key using the RSA-with-MD5 signature algorithm. The + * signature is computed over the Muscle Key Blob representation of + * the new public key and the challenge sent in the key generation + * request. These two data fields are concatenated together to form + * the input to the signature, without any other data or length fields. + * + * Byte[] Key Blob Data + * + * Byte[] Challenge + * + * + * Key Generation Result + * --------------------------------------- + * + * The key generation command puts the key blob and the signature (proof) + * into the output buffer using the following format: + * + * Short Length of the Key Blob + * + * Byte[] Key Blob Data + * + * Short Length of the Proof + * + * Byte[] Proof (Signature) Data + * + * @param blob the publickey blob to be parsed + * @param challenge the challenge generated by TPS + * + ******/ + private RSAPublicKey parsePublicKeyBlob( + TPSBuffer public_key_blob, + /* TPSBuffer challenge,*/ + boolean isECC) + throws TPSException { + RSAPublicKey parsedPubKey = null; + + if (public_key_blob == null /*|| challenge == null*/) { + throw new TPSException( + "TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! Missing public_key_blob or challenge", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: public key blob from token to parse: " + + public_key_blob.toHexString()); + /* + * decode blob into structures + */ + + // offset to the beginning of the public key length. should be 0 + int pkeyb_len_offset = 0; + + /* + * now, convert lengths + */ + // 1st, keyblob length + /* + byte len0 = public_key_blob.at(pkeyb_len_offset); + byte len1 = public_key_blob.at(pkeyb_len_offset + 1); + int pkeyb_len = (len0 << 8) | (len1 & 0xFF); + */ + int pkeyb_len = public_key_blob.getIntFrom2Bytes(pkeyb_len_offset); + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: pkeyb_len = " + + pkeyb_len + ", isECC: " + isECC); + // public key blob + TPSBuffer pkeyb = public_key_blob.substr(pkeyb_len_offset + 2, pkeyb_len); + if (pkeyb == null) { + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: pkeyb null "); + throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! pkeyb null", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: pkeyb = " + + pkeyb.toHexString()); + + // 2nd, proof blob length + int proofb_len_offset = pkeyb_len_offset + 2 + pkeyb_len; + /* + len0 = public_key_blob.at(proofb_len_offset); + len1 = public_key_blob.at(proofb_len_offset + 1); + int proofb_len = (len0 << 8 | len1 & 0xFF); + */ + int proofb_len = public_key_blob.getIntFrom2Bytes(proofb_len_offset); + // proof blob + TPSBuffer proofb = public_key_blob.substr(proofb_len_offset + 2, proofb_len); + if (proofb == null) { + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: proofb null "); + throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! proofb null", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: proofb = " + + proofb.toHexString()); + + // convert pkeyb to pkey + // 1 byte encoding, 1 byte key type, 2 bytes key length, then the key + int pkey_offset = 4; + /* + len0 = pkeyb.at(pkey_offset); + len1 = pkeyb.at(pkey_offset + 1); + */ + if (!isECC) { + // int mod_len = len0 << 8 | len1 & 0xFF; + int mod_len = pkeyb.getIntFrom2Bytes(pkey_offset); + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: mod_len= " + mod_len); + /* + len0 = pkeyb.at(pkey_offset + 2 + mod_len); + len1 = pkeyb.at(pkey_offset + 2 + mod_len + 1); + int exp_len = len0 << 8 | len1 & 0xFF; + */ + int exp_len = pkeyb.getIntFrom2Bytes(pkey_offset + 2 + mod_len); + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: exp_len= " + exp_len); + + TPSBuffer modb = pkeyb.substr(pkey_offset + 2, mod_len); + if (modb == null) { + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: modb null "); + throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! modb null", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: modb= " + + modb.toHexString()); + TPSBuffer expb = pkeyb.substr(pkey_offset + 2 + mod_len + 2, exp_len); + + if (expb == null) { + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: expb null "); + throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Bad input data! expb null", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: expb= " + + expb.toHexString()); + BigInt modb_bi = new BigInt(modb.toBytesArray()); + BigInt expb_bi = new BigInt(expb.toBytesArray()); + try { + RSAPublicKey rsa_pub_key = new RSAPublicKey(modb_bi, expb_bi); + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: public key blob converted to RSAPublicKey"); + if (rsa_pub_key != null) { + parsedPubKey = rsa_pub_key; + } + } catch (InvalidKeyException e) { + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob:InvalidKeyException thrown"); + throw new TPSException("TPSEnrollProcessor.parsePublicKeyBlob: Exception thrown: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + } else { + // TODO: handle ECC + } + + // TODO: challenge verification + + // sanity-check parsedPubKey before return + if (parsedPubKey == null) { + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey null"); + throw new TPSException( + "TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey null.", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } else { + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey not null"); + } + byte[] parsedPubKey_ba = parsedPubKey.getEncoded(); + if (parsedPubKey_ba == null) { + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey_ba null"); + throw new TPSException( + "TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey encoding failure.", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } else { + CMS.debug("TPSEnrollProcessor.parsePublicKeyBlob: parsedPubKey getEncoded not null"); + } + + return parsedPubKey; + } + + private boolean checkForServerSideKeyGen(CertEnrollInfo cInfo) throws TPSException { + + if (cInfo == null) { + throw new TPSException("TPSEnrollProcessor.checkForServerSideKeyGen: invalid cert info.", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + IConfigStore configStore = CMS.getConfigStore(); + boolean serverSideKeygen = false; + + try { + String configValue = cInfo.getKeyTypePrefix() + "." + TPSEngine.CFG_SERVER_KEYGEN_ENABLE; + CMS.debug("TPSEnrollProcessor.checkForServerSideKeyGen: config: " + configValue); + serverSideKeygen = configStore.getBoolean( + configValue, false); + + } catch (EBaseException e) { + throw new TPSException( + "TPSEnrollProcessor.checkForServerSideKeyGen: Internal error finding config value: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + CMS.debug("TPSProcess.checkForServerSideKeyGen: returning: " + serverSideKeygen); + + return serverSideKeygen; + + } + + private boolean checkForServerKeyArchival(CertEnrollInfo cInfo) throws TPSException { + + if (cInfo == null) { + throw new TPSException("TPSEnrollProcessor.checkForServerKeyArchival: invalid cert info.", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + IConfigStore configStore = CMS.getConfigStore(); + boolean serverKeyArchival = false; + + try { + String configValue = cInfo.getKeyTypePrefix() + "." + TPSEngine.CFG_SERVER_KEY_ARCHIVAL; + CMS.debug("TPSEnrollProcessor.checkForServerKeyArchival: config: " + configValue); + serverKeyArchival = configStore.getBoolean( + configValue, false); + + } catch (EBaseException e) { + throw new TPSException( + "TPSEnrollProcessor.checkForServerKeyArchival: Internal error finding config value: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + CMS.debug("TPSProcess.checkForServerKeyArchival: returning: " + serverKeyArchival); + + return serverKeyArchival; + + } + + private boolean checkForObjectOverwrite(CertEnrollInfo cInfo) throws TPSException { + + if (cInfo == null) { + throw new TPSException("TPSEnrollProcessor.checkForObjectOverwrite: invalid cert info.", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + IConfigStore configStore = CMS.getConfigStore(); + boolean objectOverwrite = false; + + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + getSelectedTokenType() + ".keyGen." + + cInfo.getKeyType() + "." + TPSEngine.CFG_OVERWRITE; + + CMS.debug("TPSProcess.checkForObjectOverwrite: config: " + configValue); + objectOverwrite = configStore.getBoolean( + configValue, true); + + } catch (EBaseException e) { + throw new TPSException( + "TPSEnrollProcessor.checkForServerSideKeyGen: Internal error finding config value: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + CMS.debug("TPSProcess.checkForObjectOverwrite: returning: " + objectOverwrite); + + return objectOverwrite; + + } + + private String getConfiguredKeyType(int keyTypeIndex) throws TPSException { + + IConfigStore configStore = CMS.getConfigStore(); + String keyType = null; + + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + + TPSEngine.CFG_KEYGEN_KEYTYPE_VALUE + "." + keyTypeIndex; + keyType = configStore.getString( + configValue, null); + + } catch (EBaseException e) { + throw new TPSException( + "TPSEnrollProcessor.getConfiguredKeyType: Internal error finding config value: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + //We would really like one of these to exist + + if (keyType == null) { + throw new TPSException( + "TPSEnrollProcessor.getConfiguredKeyType: Internal error finding config value: ", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + CMS.debug("TPSProcess.getConfiguredKeyType: returning: " + keyType); + + return keyType; + + } + + private String getDRMConnectorID() throws TPSException { + IConfigStore configStore = CMS.getConfigStore(); + String id = null; + + String config = "op." + currentTokenOperation + "." + selectedTokenType + "." + TPSEngine.CFG_KEYGEN_ENCRYPTION + + "." + TPSEngine.CFG_DRM_CONNECTOR; + + CMS.debug("TPSEnrollProcessor.getDRMConnectorID: config value: " + config); + try { + id = configStore.getString(config, "kra1"); + } catch (EBaseException e) { + throw new TPSException("TPSEnrollProcessor.getDRMConnectorID: Internal error finding config value."); + + } + + CMS.debug("TPSEnrollProcessor.getDRMConectorID: returning: " + id); + + return id; + } + + protected int getNumberCertsToEnroll() throws TPSException { + IConfigStore configStore = CMS.getConfigStore(); + int keyTypeNum = 0; + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + + TPSEngine.CFG_KEYGEN_KEYTYPE_NUM; + keyTypeNum = configStore.getInteger( + configValue, 0); + + } catch (EBaseException e) { + throw new TPSException("TPSEnrollProcessor.getNumberCertsToEnroll: Internal error finding config value: " + + e, + TPSStatus.STATUS_ERROR_UPGRADE_APPLET); + + } + + if (keyTypeNum == 0) { + throw new TPSException( + "TPSEnrollProcessor.getNumberCertsToEnroll: invalid number of certificates configured!", + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + } + CMS.debug("TPSProcess.getNumberCertsToEnroll: returning: " + keyTypeNum); + + return keyTypeNum; + } + + protected int getEnrollmentAlg() throws TPSException { + IConfigStore configStore = CMS.getConfigStore(); + int enrollmentAlg; + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + + TPSEngine.CFG_KEYGEN_ENCRYPTION + "." + TPSEngine.CFG_ALG; + + CMS.debug("TPSProcess.getEnrollmentAlg: configValue: " + configValue); + + enrollmentAlg = configStore.getInteger( + configValue, 2); + + } catch (EBaseException e) { + throw new TPSException("TPSEnrollProcessor.getEnrollmentAlg: Internal error finding config value: " + + e, + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + + } + + CMS.debug("TPSProcess.getEnrollmentAlg: returning: " + enrollmentAlg); + + return enrollmentAlg; + } + + protected String getRecoveryKeyTypeValue(String reason, int index) throws TPSException { + + if (reason == null || index < 0) { + throw new TPSException("TPSEnrollProcessor.getRecoveryKeyTypeValue: invalide input data!", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + + IConfigStore configStore = CMS.getConfigStore(); + String keyTypeValue; + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + TPSEngine.CFG_KEYGEN + + "." + + TPSEngine.RECOVERY_OP + "." + reason + "." + TPSEngine.CFG_KEYTYPE_VALUE + "." + index; + ; + + CMS.debug("TPSProcess.getRecoveryKeyTypeValue: configValue: " + configValue); + + keyTypeValue = configStore.getString( + configValue, null); + + } catch (EBaseException e) { + throw new TPSException("TPSEnrollProcessor.getRecoveryKeyTypeValue: Internal error finding config value: " + + e, + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + + } + + if (keyTypeValue == null) { + throw new TPSException("TPSEnrollProcessor.getRecoveryKeyTypeValue: Invalid keyTypeValue found! ", + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + } + + CMS.debug("TPSProcess.getRecoveryKeyTypeValue: returning: " + keyTypeValue); + + return keyTypeValue; + } + + protected String getRecoveryScheme(String reason, String keyTypeValue) throws TPSException { + + if (reason == null || keyTypeValue == null) { + throw new TPSException("TPSEnrollProcessor.getRecoveryScheme: invalid input data!", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + + IConfigStore configStore = CMS.getConfigStore(); + String scheme = null; + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + TPSEngine.CFG_KEYGEN + + "." + keyTypeValue + "." + + TPSEngine.RECOVERY_OP + "." + reason + "." + TPSEngine.CFG_SCHEME; + ; + + CMS.debug("TPSProcess.getRecoveryScheme: configValue: " + configValue); + + scheme = configStore.getString( + configValue, null); + + } catch (EBaseException e) { + throw new TPSException("TPSEnrollProcessor.getRecoveryScheme: Internal error finding config value: " + + e, + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + + } + + if (scheme == null) { + throw new TPSException("TPSEnrollProcessor.getRecoverScheme: Invalid scheme found! ", + TPSStatus.STATUS_ERROR_MISCONFIGURATION); + } + + CMS.debug("TPSProcess.getRecoveryScheme: returning: " + scheme); + + return scheme; + } + + protected int getNumberCertsForRecovery(String reason) throws TPSException { + if (reason == null) { + throw new TPSException("TPSEnrollProcessor.getNumberCertsForRecovery: invlalid input data!", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + + IConfigStore configStore = CMS.getConfigStore(); + int keyTypeNum = 0; + try { + String configValue = TPSEngine.OP_ENROLL_PREFIX + "." + selectedTokenType + "." + TPSEngine.CFG_KEYGEN + + "." + TPSEngine.RECOVERY_OP + + "." + reason + "." + TPSEngine.CFG_KEYTYPE_NUM; + + CMS.debug("TPSEnrollProcessor.getNumberCertsForRecovery: configValue: " + configValue); + keyTypeNum = configStore.getInteger( + configValue, 0); + + } catch (EBaseException e) { + throw new TPSException( + "TPSEnrollProcessor.getNumberCertsForRecovery: Internal error finding config value: " + + e, + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + + } + + if (keyTypeNum == 0) { + throw new TPSException( + "TPSEnrollProcessor.getNumberCertsForRecovery: invalid number of certificates configured!", + TPSStatus.STATUS_ERROR_RECOVERY_FAILED); + } + CMS.debug("TPSProcess.getNumberCertsForRecovery: returning: " + keyTypeNum); + + return keyTypeNum; + } + + protected String getCAConnectorID() throws TPSException { + IConfigStore configStore = CMS.getConfigStore(); + String id = null; + + String config = "op." + currentTokenOperation + "." + selectedTokenType + ".ca.conn"; + + try { + id = configStore.getString(config, "ca1"); + } catch (EBaseException e) { + throw new TPSException("TPSEnrollProcessor.getCAConnectorID: Internal error finding config value."); + + } + + CMS.debug("TPSEnrollProcessor.getCAConectorID: returning: " + id); + + return id; + } + + private TPSBuffer makeKeyIDFromPublicKeyInfo(byte[] publicKeyInfo) throws TPSException { + + final String alg = "SHA1"; + + if (publicKeyInfo == null) { + throw new TPSException("TPSEnrollProcessor.makeKeyIDFromPublicKeyInfo: invalid input data", + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + TPSBuffer keyID = null; + + byte[] mozillaDigestOut; + + java.security.MessageDigest mozillaDigest; + try { + mozillaDigest = java.security.MessageDigest.getInstance(alg); + } catch (NoSuchAlgorithmException e) { + throw new TPSException("TPSEnrollProcessor.makeKeyIDFromPublicKeyInfo: " + e, + TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + mozillaDigestOut = mozillaDigest.digest(publicKeyInfo); + + if (mozillaDigestOut.length == mozillaDigest.getDigestLength()) { + System.out.println(mozillaDigest.getAlgorithm() + " " + + " digest output size is " + mozillaDigestOut.length); + } else { + throw new TPSException("ERROR: digest output size is " + + mozillaDigestOut.length + ", should be " + + mozillaDigest.getDigestLength(), TPSStatus.STATUS_ERROR_MAC_ENROLL_PDU); + } + + keyID = new TPSBuffer(mozillaDigestOut); + + CMS.debug("TPSEnrollProcessor.makeKeyIDFromPublicKeyInfo: " + keyID.toHexString()); + + return keyID; + } + + public BigInteger serialNoToBigInt(String serialS) { + if (serialS == null) + return new BigInteger("0", 16); + + CMS.debug("TPSEnrollProcessor.seralNoToBigInt: serial # =" + serialS); + String serialhex = serialS.substring(2); // strip off the "0x" + BigInteger serialBI = new BigInteger(serialhex, 16); + + return serialBI; + } + + public static void main(String[] args) { + } + +} |