private byte[] DoGPO(byte[] adpu) { TLVList db = new TLVList(); EMVGetProcessingOptionsRequest request = new EMVGetProcessingOptionsRequest(); request.Deserialize(adpu); TLV _83 = TLV.Create(EMVTagsEnum.COMMAND_TEMPLATE_83_KRN.Tag); _83.Deserialize(request.CommandData, 0); int pos = 0; byte[] amount = Formatting.copyOfRange(_83.Value, pos, pos + MAX_AMOUNT_AUTH__LENGTH); pos = pos + MAX_AMOUNT_AUTH__LENGTH; byte[] upn = Formatting.copyOfRange(_83.Value, pos, pos + MAX_UNPRED_NUM__LENGTH); pos = pos + MAX_UNPRED_NUM__LENGTH; byte[] ttq = Formatting.copyOfRange(_83.Value, pos, pos + MAX_TTQ_LENGTH); //pos = pos + MAX_TTQ_LENGTH; db.AddToList(TLV.Create(EMVTagsEnum.TERMINAL_TRANSACTION_QUALIFIERS_TTQ_9F66_KRN.Tag, ttq)); /* * supported by card and reader (TTQ byte 1 bit 6 set to 1b) * return 6985 if not */ TERMINAL_TRANSACTION_QUALIFIERS_9F66_KRN ttqST = new TERMINAL_TRANSACTION_QUALIFIERS_9F66_KRN(db.Get(EMVTagsEnum.TERMINAL_TRANSACTION_QUALIFIERS_TTQ_9F66_KRN.Tag)); if (!ttqST.Value.EMVModeSupported) { return(BitConverter.GetBytes((int)ISO7816ReturnCodes.SW_CONDITIONS_OF_USE_NOT_SATISFIED)); } /* * Card action analysis */ /* * Card Risk Management Processing */ /* * Initialize data */ //Req H.2 (Initialization of Card Transaction Qualifiers) //The card shall reset CTQ byte 1 bits 8-7 to 00b (indicating Online PIN Not Required and Signature Not Required). CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3 ctq = new CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3(); ctq.Value.OnlinePINRequired = false; ctq.Value.SignatureRequired = false; ctq.Value.GoOnlineIfApplicationExpired = true; //hardcoded perso ctq.Value.GoOnlineIfOfflineDataAuthenticationFailsAndReaderIsOnlineCapable = true; //hardcoded perso //Req H.3 (Initialization of Issuer Application Data) //The card shall set the CVR to '03 80 00 00' (indicating Second GENERATE AC not requested) byte[] cvr = new byte[4]; cvr[Byte1] = 0x03; cvr[Byte2] = (byte)0x80; cvr[Byte3] = 0x00; cvr[Byte4] = 0x00; //Req H.4 (Initialization of Cryptogram Information Data) //The card shall reset the Cryptogram Information Data (CID) to '00'. byte[] cid_9F27 = new byte[1]; cid_9F27[Byte1] = 0x00; /* * Application Block Check */ //Req H.5 (Application Blocked Check) //If the application is blocked, then the card shall discontinue processing the command and shall respond with SW1 SW2 = '6985' /* * PIN tries exceeded check */ /* * Refunds and Credits Check */ /* * Reader Indicators Check */ /* * Cardholder Verification Method Check */ //Req H.6 (CVM Required Check) //If CVM Required by reader (TTQ byte 2 bit 7 is 1b), then a CVM is required for the //transaction, and the card shall determine the common CVM to be performed byte[] capDefault = PersoAndCardStateStorage.CARD_ADDITIONAL_PROCESSES_9F68_KRN.Value; if (ttqST.Value.CVMRequired) { //Req H.7 (Determine Common CVM) //If a CVM is required for the transaction, then the card shall attempt to select a //common CVM supported by both itself and the reader, as defined in this requirement. //If there is more than one CVM supported by both the card and the reader, the //selected CVM is chosen based on the following defined CVM hierarchy: 1) Online //PIN, 2) Signature. if (isCapPersonalized) { //If CVM Required by reader (TTQ byte 2 bit 7 is 1b), then a CVM is required for the //transaction, and the card shall determine the common CVM to be performed. if (ttqST.Value.CVMRequired) { //Online PIN supported by reader (TTQ byte 1 bit 3 is 1b) and either //Online PIN supported by card for domestic transactions (CAP byte 3 bit 8 is 1b) //or Online PIN supported by card for international transactions (CAP byte 3 bit 7 is 1b) if (ttqST.Value.OnlinePINSupported && Formatting.GetBitPosition(capDefault[Byte3], Bit8 + 1) || Formatting.GetBitPosition(capDefault[Byte3], Bit7 + 1)) { //Then the card shall indicate Online PIN Required (set CTQ byte 1 bit 8 to 1b) ctq.Value.OnlinePINRequired = true; //Else, if both of the following are true } else if (ttqST.Value.OfflineDataAuthenticationForOnlineAuthorizationsSupported && Formatting.GetBitPosition(capDefault[Byte3], Bit5 + 1)) { ctq.Value.GoOnlineIfOfflineDataAuthenticationFailsAndReaderIsOnlineCapable = true; } else { return(BitConverter.GetBytes((int)ISO7816ReturnCodes.SW_DATA_INVALID)); } } } else { //if Signature is not supported by the reader (TTQ byte 1 bit 2 is 0b), then the card //shall discontinue processing and respond to the GPO command with SW1 SW2 = '6984' if (!ttqST.Value.SignatureSupported) { return(BitConverter.GetBytes((int)ISO7816ReturnCodes.SW_DATA_INVALID)); } } } /* * Domestic Velocity Checking */ /* * International Velocity Checking */ /* * Contactless Transaction Counter Velocity Checking */ /* * Transaction Disposition */ //Req H.8 (Online) //Indicate Authorization Request Cryptogram returned (set CVR byte 2 bits 6-5 //to 10b and set CID bits 8-7 to 10b). Formatting.SetBitPosition(ref cvr[Byte2], true, Bit6 + 1); Formatting.SetBitPosition(ref cvr[Byte2], false, Bit5 + 1); Formatting.SetBitPosition(ref cid_9F27[Byte1], true, Bit8 + 1); Formatting.SetBitPosition(ref cid_9F27[Byte1], false, Bit7 + 1); //Increment the Application Transaction Counter (ATC) by one. The ATC shall be //incremented prior to the performance of any cryptographic operations. //If incrementing the ATC results in the ATC reaching its maximum value, then the //application shall be permanently blocked, Req 6.7 (Application Permanently //Blocked), and shall respond to the GPO command with error SW1 SW2 = '6985' //Increment the Application Transaction Counter (ATC) by one. The ATC shall be //incremented prior to the performance of any cryptographic operations TLV atc_9F36 = PersoAndCardStateStorage.APPLICATION_TRANSACTION_COUNTER_ATC_9F36_KRN; if (atc_9F36.Value[0] == 0xFF) { return(BitConverter.GetBytes((int)ISO7816ReturnCodes.SW_CONDITIONS_OF_USE_NOT_SATISFIED)); } else { if (atc_9F36.Value[1] == 0xFF) { atc_9F36.Value[0] = (byte)(atc_9F36.Value[0] + 1); atc_9F36.Value[1] = 0x00; } else { atc_9F36.Value[1] = (byte)(atc_9F36.Value[1] + 1); } } //Construct the Issuer Application Data. If an Issuer Discretionary Data Option (IDD //Option) is supported (see Appendix E), it shall be constructed and the MAC //generated (if applicable). //Only Option 0 supported, IDD already included during perso //If the card is capable of performing fDDA and all of the following are true: //the card supports fDDA for Online Authorizations (AIP byte 1 bit 6 is 1b for the //"Online (with ODA)" GPO response) //and ODA for Online Authorizations supported by card (CAP byte 2 bit 6 is 0b) //and ODA for Online Authorizations supported by reader (TTQ byte 1 bit 1 is 1b) //Then the card shall construct the Card Authentication Related Data and generate //the Signed Dynamic Application Data (tag '9F4B'). The Signed Dynamic //Application Data shall be generated as defined in Appendix A. byte[] iapDefault = PersoAndCardStateStorage.APPLICATION_INTERCHANGE_PROFILE_82_KRN.Value; if (Formatting.GetBitPosition(iapDefault[Byte1], Bit6 + 1) && !Formatting.GetBitPosition(capDefault[Byte2], Bit6 + 1) && ttqST.Value.OfflineDataAuthenticationForOnlineAuthorizationsSupported) { //fdda not supported return(BitConverter.GetBytes((int)ISO7816ReturnCodes.SW_CONDITIONS_OF_USE_NOT_SATISFIED)); } //Generate the Application Cryptogram //The path shall implement support for Cryptogram Version Number 10 and //Cryptogram Version Number 17, and may implement support for Cryptogram Version //Number 18 at implementer discretion. The Cryptogram Version to be used for //cryptogram generation shall be issuer configurable, and indicated by the issuer in the //Cryptogram Version Number of the Issuer Application Data returned for //transactions. //We use only 17 at this stage //if(tm_CVN[Byte1] != 0x11) // ISOException.throwIt((short) 0x6984); //9F10 IAD Byte 5 (IAD byte 5 is CVR byte 2) from card TLV iad_9F10 = PersoAndCardStateStorage.ISSUER_APPLICATION_DATA_9F10_KRN; iad_9F10.Value[Byte5] = cvr[Byte2]; //9F02 Amount, Authorized from terminal via pdol //9F37 Unpredictable Number from terminal via pdol //9F36 ATC from card //9F10 IAD Byte 5 (IAD byte 5 is CVR byte 2) from card byte[] crytogram_9F26 = generateCryptogram17(PersoAndCardStateStorage.ICC_MK, Formatting.ConcatArrays(amount, upn, atc_9F36.Value, new byte[] { iad_9F10.Value[Byte5] })); //If ODA for Online Authorizations supported by reader (TTQ byte 1 bit 1 is 1b), then //construct and send the GPO response in [EMV] Format 2 with the data shown in //Table 6-2 using Condition column "Online (with ODA)". EMVGetProcessingOptionsResponse response; //pdol sent back during select is 9F38 09 -> 9F02 06 9F37 04 9F66 04 ctq.Serialize(); db.AddToList(TLV.Create(EMVTagsEnum.AMOUNT_AUTHORISED_NUMERIC_9F02_KRN.Tag, amount)); db.AddToList(TLV.Create(EMVTagsEnum.UNPREDICTABLE_NUMBER_9F37_KRN.Tag, upn)); db.AddToList(TLV.Create(EMVTagsEnum.TERMINAL_TRANSACTION_QUALIFIERS_TTQ_9F66_KRN.Tag, ttq)); db.AddToList(TLV.Create(EMVTagsEnum.CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3.Tag, ctq.Value.Value)); db.AddToList(TLV.Create(EMVTagsEnum.CRYPTOGRAM_INFORMATION_DATA_9F27_KRN.Tag, cid_9F27)); db.AddToList(TLV.Create(EMVTagsEnum.APPLICATION_CRYPTOGRAM_9F26_KRN.Tag, crytogram_9F26)); TLV sdad = TLV.Create(EMVTagsEnum.SIGNED_DYNAMIC_APPLICATION_DATA_9F4B_KRN.Tag); sdad.Val.PackValue(15); db.AddToList(sdad); db.AddToList(atc_9F36); db.AddToList(iad_9F10); if (ttqST.Value.OfflineDataAuthenticationForOnlineAuthorizationsSupported) { //only diff is to add empty 9F4B SDAD response = genGPOResponse(true, db); } //Else (TTQ byte 1 bit 1 is 0b), construct and send the GPO response in [EMV] //Format 2 with the data shown in Table 6-2 using Condition column "Online and //Decline (without ODA)". else { response = genGPOResponse(false, db); } //Note: The Available Offline Spending Amount (tag '9F5D') is not supported return(response.Serialize()); }
public static SignalsEnum DoCommonProcessing(string source, KernelDatabaseBase databaseIn, KernelQ qManager, CardQ cardQManager, Stopwatch sw, PublicKeyCertificateManager pkcm, CardExceptionManager cardExceptionManager) { Kernel3Database database = (Kernel3Database)databaseIn; if (database.NextCommandEnum == NextCommandEnum.READ_RECORD) { DoDEKIfNeeded(database, qManager); return(SignalsEnum.WAITING_FOR_EMV_READ_RECORD_RESPONSE); } DoDEKIfNeeded(database, qManager); //ReaderContactlessTransactionLimit exceeded if (database.ProcessingIndicatorsForSelected.ContactlessApplicationNotAllowed) { CommonRoutines.CreateEMVDiscretionaryData(database); return(CommonRoutines.PostOutcomeWithError(database, qManager, Kernel2OutcomeStatusEnum.SELECT_NEXT, Kernel2StartEnum.C, L1Enum.NOT_SET, L2Enum.MAX_LIMIT_EXCEEDED, L3Enum.NOT_SET)); } #region 5.4.3.1 TLV cidTLV = database.Get(EMVTagsEnum.CRYPTOGRAM_INFORMATION_DATA_9F27_KRN); if (cidTLV == null) { cidTLV = TLV.Create(EMVTagsEnum.CRYPTOGRAM_INFORMATION_DATA_9F27_KRN.Tag); cidTLV.Val.PackValue(cidTLV.Val.DataFormatter.GetMaxLength()); byte iad = database.Get(EMVTagsEnum.ISSUER_APPLICATION_DATA_9F10_KRN).Value[4]; Formatting.SetBitPosition(ref cidTLV.Value[0], Formatting.GetBitPosition(iad, 6), 8); Formatting.SetBitPosition(ref cidTLV.Value[0], Formatting.GetBitPosition(iad, 5), 7); database.AddToList(cidTLV); } #endregion #region 5.4.3.2 byte cid = cidTLV.Value[0]; cid = (byte)(cid >> 6); TERMINAL_TRANSACTION_QUALIFIERS_9F66_KRN ttq = new TERMINAL_TRANSACTION_QUALIFIERS_9F66_KRN(database); if (cid == (byte)ACTypeEnum.AAC) { database.DeclineRequiredByReaderIndicator = true; } if (cid == (byte)ACTypeEnum.ARQC || ttq.Value.OnlineCryptogramRequired) { database.OnlineRequiredByReaderIndicator = true; } if (cid != (byte)ACTypeEnum.AAC && cid != (byte)ACTypeEnum.ARQC && cid != (byte)ACTypeEnum.TC) { database.DeclineRequiredByReaderIndicator = true; } #endregion #region 5.4.2.1 if (!database.DeclineRequiredByReaderIndicator) { if (!CheckMandatoryFields(database, pkcm)) { return(CommonRoutines.PostOutcome(database, qManager, KernelMessageidentifierEnum.ERROR_OTHER_CARD, KernelStatusEnum.PROCESSING_ERROR, null, Kernel2OutcomeStatusEnum.END_APPLICATION, Kernel2StartEnum.N_A, true, KernelMessageidentifierEnum.ERROR_OTHER_CARD, L1Enum.NOT_SET, null, L2Enum.CARD_DATA_ERROR, L3Enum.NOT_SET)); } } #endregion if (!database.DeclineRequiredByReaderIndicator && !database.OnlineRequiredByReaderIndicator) { #region 5.5.1.1 to 5.5.1.5 SignalsEnum result = DoProcessingRestrictions(database, qManager, cardExceptionManager); if (result != SignalsEnum.NONE) { return(result); } #endregion #region 5.6.1.1, 5.6.1.2 and 5.6.2.1, 5.6.2.1 if (!DoOfflineAuth(database, qManager, pkcm)) #endregion { CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3 ctq = new CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3(database); if (ctq.Value.GoOnlineIfOfflineDataAuthenticationFailsAndReaderIsOnlineCapable && !database.ProcessingIndicatorsForSelected.TTQ.Value.OfflineOnlyReader) { database.OnlineRequiredByReaderIndicator = true; } else if (ctq.Value.SwitchInterfaceIfOfflineDataAuthenticationFailsAndReaderSupportsVIS && database.ProcessingIndicatorsForSelected.TTQ.Value.EMVContactChipSupported) { return(CommonRoutines.PostOutcome(database, qManager, KernelMessageidentifierEnum.INSERT_CARD, KernelStatusEnum.PROCESSING_ERROR, null, Kernel2OutcomeStatusEnum.TRY_ANOTHER_INTERFACE, Kernel2StartEnum.N_A, true, KernelMessageidentifierEnum.INSERT_CARD, L1Enum.NOT_SET, null, L2Enum.TERMINAL_DATA_ERROR, L3Enum.NOT_SET)); } else { database.DeclineRequiredByReaderIndicator = true; } } } #region 5.7.1.1, 5.7.1.2, 5.7.1.3 KernelCVMEnum cvm = KernelCVMEnum.N_A; if (!database.DeclineRequiredByReaderIndicator) { cvm = DoCVMProcessing(database, (ACTypeEnum)Formatting.GetEnum(typeof(ACTypeEnum), cid)); if (cvm == KernelCVMEnum.NO_CVM && ttq.Value.CVMRequired) { database.DeclineRequiredByReaderIndicator = true; } } #endregion #region 4.3.1.1 byte[] currencyCode = null; byte[] balance = null; ValueQualifierEnum vq = ValueQualifierEnum.NONE; if (database.Kernel3Configuration.DisplayAvailableSpendingAmount) { TLV balanceTLV = database.Get(EMVTagsEnum.AVAILABLE_OFFLINE_SPENDING_AMOUNT_AOSA_9F5D_KRN3); if (balanceTLV != null) { vq = ValueQualifierEnum.BALANCE; balance = balanceTLV.Value; currencyCode = database.Get(EMVTagsEnum.TRANSACTION_CURRENCY_CODE_5F2A_KRN).Value; } } #endregion //#region support for Refunds //byte transactionType = database.Get(EMVTagsEnum.TRANSACTION_TYPE_9C_KRN).Value[0]; //if (transactionType == (byte)TransactionTypeEnum.Refund) // database.DeclineRequiredByReaderIndicator = true; //#endregion #region 5.8.1.1 if (database.OnlineRequiredByReaderIndicator && !database.DeclineRequiredByReaderIndicator) { CommonRoutines.CreateEMVDataRecord(database); CommonRoutines.CreateEMVDiscretionaryData(database); return(CommonRoutines.PostOutcome(database, qManager, KernelMessageidentifierEnum.AUTHORISING_PLEASE_WAIT, KernelStatusEnum.NOT_READY, null, Kernel2OutcomeStatusEnum.ONLINE_REQUEST, Kernel2StartEnum.N_A, true, KernelMessageidentifierEnum.N_A, L1Enum.NOT_SET, null, L2Enum.NOT_SET, L3Enum.NOT_SET, vq, balance, currencyCode, false, cvm)); } #endregion #region 5.9.1.1 if (!database.OnlineRequiredByReaderIndicator && !database.DeclineRequiredByReaderIndicator) { CommonRoutines.CreateEMVDataRecord(database); CommonRoutines.CreateEMVDiscretionaryData(database); return(CommonRoutines.PostOutcome(database, qManager, cvm == KernelCVMEnum.OBTAIN_SIGNATURE ? KernelMessageidentifierEnum.APPROVED_SIGN : KernelMessageidentifierEnum.APPROVED, KernelStatusEnum.READY_TO_READ, null, Kernel2OutcomeStatusEnum.APPROVED, Kernel2StartEnum.N_A, true, KernelMessageidentifierEnum.N_A, L1Enum.NOT_SET, null, L2Enum.NOT_SET, L3Enum.NOT_SET, vq, balance, currencyCode, false, cvm)); } #endregion CommonRoutines.CreateEMVDiscretionaryData(database); //#region support for Refunds //if (transactionType == (byte)TransactionTypeEnum.Refund) //#endregion //{ // //CommonRoutines.PostUIOnly(database, qManager, Kernel1MessageidentifierEnum.CLEAR_DISPLAY, Kernel1StatusEnum.N_A, true, new byte[] { 0x00, 0x00, 0x00 }); // CommonRoutines.CreateEMVDataRecord(database); // return CommonRoutines.PostOutcome(database, qManager, // KernelMessageidentifierEnum.N_A, // KernelStatusEnum.N_A, // null, // Kernel2OutcomeStatusEnum.END_APPLICATION, // Kernel2StartEnum.N_A, // true, // KernelMessageidentifierEnum.N_A, // L1Enum.NOT_SET, // null, // L2Enum.NOT_SET, // L3Enum.NOT_SET, // ValueQualifierEnum.NONE, // null, // null, // false, // cvm); //} //else //{ #region 5.9.1.2 return(CommonRoutines.PostOutcome(database, qManager, KernelMessageidentifierEnum.DECLINED, KernelStatusEnum.READY_TO_READ, null, Kernel2OutcomeStatusEnum.DECLINED, Kernel2StartEnum.N_A, true, KernelMessageidentifierEnum.N_A, L1Enum.NOT_SET, null, L2Enum.NOT_SET, L3Enum.NOT_SET, vq, balance, currencyCode, false, cvm)); #endregion //} }
private static SignalsEnum DoProcessingRestrictions(Kernel3Database database, KernelQ qManager, CardExceptionManager cardExceptionManager) { #region 5.5.1.1 DateTime transactionDate = EMVTagsEnum.TRANSACTION_DATE_9A_KRN.FormatAsDateTime(database.Get(EMVTagsEnum.TRANSACTION_DATE_9A_KRN).Value); DateTime appExpiryDate = DateTime.Now; TLV appExiryDateTLV = database.Get(EMVTagsEnum.APPLICATION_EXPIRATION_DATE_5F24_KRN); if (appExiryDateTLV != null) { appExpiryDate = EMVTagsEnum.APPLICATION_EXPIRATION_DATE_5F24_KRN.FormatAsDateTime(appExiryDateTLV.Value); } if (appExiryDateTLV == null || (transactionDate > appExpiryDate)) { CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3 ctq = new CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3(database); if (ctq.Value.GoOnlineIfApplicationExpired) { database.OnlineRequiredByReaderIndicator = true; } else { database.DeclineRequiredByReaderIndicator = true; return(SignalsEnum.NONE); } } #endregion #region 5.5.1.2 string pan = Formatting.ByteArrayToHexString(database.Get(EMVTagsEnum.APPLICATION_PRIMARY_ACCOUNT_NUMBER_PAN_5A_KRN).Value); if (database.Kernel3Configuration.ExceptionFileEnabled && cardExceptionManager.CheckForCardException(pan)) { database.DeclineRequiredByReaderIndicator = true; return(SignalsEnum.NONE); } #endregion TransactionTypeEnum tt = (TransactionTypeEnum)Formatting.GetEnum(typeof(TransactionTypeEnum), database.Get(EMVTagsEnum.TRANSACTION_TYPE_9C_KRN).Value[0]); #region 5.5.1.3 if (tt == TransactionTypeEnum.CashWithdrawal || tt == TransactionTypeEnum.CashDisbursement && database.Kernel3Configuration.AUCManualCheckSupported) { TLV icc = database.Get(EMVTagsEnum.ISSUER_COUNTRY_CODE_5F28_KRN); if (icc == null) { database.DeclineRequiredByReaderIndicator = true; return(SignalsEnum.NONE); } TLV tcc = database.Get(EMVTagsEnum.TERMINAL_COUNTRY_CODE_9F1A_KRN); APPLICATION_USAGE_CONTROL_9F07_KRN auc = new APPLICATION_USAGE_CONTROL_9F07_KRN(database); if (!((Formatting.ByteArrayToHexString(icc.Value) == Formatting.ByteArrayToHexString(tcc.Value) && auc.Value.IsValidForDomesticCashTransactions) || (Formatting.ByteArrayToHexString(icc.Value) != Formatting.ByteArrayToHexString(tcc.Value) && auc.Value.IsValidForInternationalCashTransactions))) { CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3 ctq = new CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3(database); if (database.IsEmpty(EMVTagsEnum.CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3.Tag) || ctq.Value.SwitchInterfaceForCashTransactions) { return(CommonRoutines.PostOutcome(database, qManager, KernelMessageidentifierEnum.N_A, KernelStatusEnum.PROCESSING_ERROR, null, Kernel2OutcomeStatusEnum.TRY_ANOTHER_INTERFACE, Kernel2StartEnum.N_A, true, KernelMessageidentifierEnum.N_A, L1Enum.NOT_SET, null, L2Enum.STATUS_BYTES, L3Enum.NOT_SET)); } else { database.DeclineRequiredByReaderIndicator = true; return(SignalsEnum.NONE); } } } #endregion #region 5.5.1.4 if (tt == TransactionTypeEnum.PurchaseWithCashback && database.Kernel3Configuration.AUCCashbackCheckSupported) { TLV icc = database.Get(EMVTagsEnum.ISSUER_COUNTRY_CODE_5F28_KRN); if (icc == null) { database.DeclineRequiredByReaderIndicator = true; return(SignalsEnum.NONE); } TLV tcc = database.Get(EMVTagsEnum.TERMINAL_COUNTRY_CODE_9F1A_KRN); APPLICATION_USAGE_CONTROL_9F07_KRN auc = new APPLICATION_USAGE_CONTROL_9F07_KRN(database); if (!((Formatting.ByteArrayToHexString(icc.Value) == Formatting.ByteArrayToHexString(tcc.Value) && auc.Value.IsValidForDomesticCashTransactions) || (Formatting.ByteArrayToHexString(icc.Value) != Formatting.ByteArrayToHexString(tcc.Value) && auc.Value.IsValidForInternationalCashTransactions))) { CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3 ctq = new CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3(database); if (database.IsEmpty(EMVTagsEnum.CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3.Tag) || ctq.Value.SwitchInterfaceForCashBackTransactions) { return(CommonRoutines.PostOutcome(database, qManager, KernelMessageidentifierEnum.N_A, KernelStatusEnum.PROCESSING_ERROR, null, Kernel2OutcomeStatusEnum.TRY_ANOTHER_INTERFACE, Kernel2StartEnum.N_A, true, KernelMessageidentifierEnum.N_A, L1Enum.NOT_SET, null, L2Enum.STATUS_BYTES, L3Enum.NOT_SET)); } else { database.DeclineRequiredByReaderIndicator = true; return(SignalsEnum.NONE); } } } #endregion #region 5.5.1.5 if (database.Kernel3Configuration.ATMOfflineCheck) { TERMINAL_TYPE_9F35_KRN termType = new TERMINAL_TYPE_9F35_KRN(database); if (termType.Value.TerminalType.Code == 0x14 || termType.Value.TerminalType.Code == 0x15 || termType.Value.TerminalType.Code == 0x16) { if (database.IsEmpty(EMVTagsEnum.CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3.Tag)) { database.DeclineRequiredByReaderIndicator = true; return(SignalsEnum.NONE); } else { CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3 ctq = new CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3(database); if (!ctq.Value.ValidForContactlessATMTransactions) { database.OnlineRequiredByReaderIndicator = true; } else { APPLICATION_USAGE_CONTROL_9F07_KRN auc = new APPLICATION_USAGE_CONTROL_9F07_KRN(database); if (auc == null) { database.OnlineRequiredByReaderIndicator = true; } else if (!auc.Value.IsValidAtATMs) { database.DeclineRequiredByReaderIndicator = true; return(SignalsEnum.NONE); } else { return(CommonRoutines.PostOutcome(database, qManager, KernelMessageidentifierEnum.N_A, KernelStatusEnum.PROCESSING_ERROR, null, Kernel2OutcomeStatusEnum.TRY_ANOTHER_INTERFACE, Kernel2StartEnum.N_A, true, KernelMessageidentifierEnum.N_A, L1Enum.NOT_SET, null, L2Enum.STATUS_BYTES, L3Enum.NOT_SET)); } } } } } #endregion return(SignalsEnum.NONE); }
public static KernelCVMEnum DoCVMProcessing(Kernel3Database database, ACTypeEnum acType) { KernelCVMEnum cvm = KernelCVMEnum.N_A; TERMINAL_TRANSACTION_QUALIFIERS_9F66_KRN ttq = new TERMINAL_TRANSACTION_QUALIFIERS_9F66_KRN(database); if (!database.DeclineRequiredByReaderIndicator) { #region 5.7.1.1 if (database.IsEmpty(EMVTagsEnum.CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3.Tag) && ttq.Value.CVMRequired) #endregion { if (ttq.Value.SignatureSupported) { cvm = KernelCVMEnum.OBTAIN_SIGNATURE; } else if (ttq.Value.ConsumerDeviceCVMSupported && ttq.Value.OnlinePINSupported) { cvm = KernelCVMEnum.ONLINE_PIN; } else// only ttq.Value.ConsumerDeviceCVMSupported { database.DeclineRequiredByReaderIndicator = true; } } if (database.IsNotEmpty(EMVTagsEnum.CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3.Tag)) { #region 5.7.1.2 CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3 ctq = new CARD_TRANSACTION_QUALIFIERS_CTQ_9F6C_KRN3(database); if (ctq.Value.OnlinePINRequired && ttq.Value.OnlinePINSupported) { cvm = KernelCVMEnum.ONLINE_PIN; database.OnlineRequiredByReaderIndicator = true; } else { if (ctq.Value.ConsumerDeviceCVMPerformed) { TLV card = database.Get(EMVTagsEnum.CARD_AUTHENTICATION_RELATED_DATA_9F69_KRN3); if (card != null) { byte[] card67 = new byte[2]; byte[] ctq12 = new byte[2]; Array.Copy(card.Value, 6, card67, 0, 2); Array.Copy(ctq.Value.Value, 0, ctq12, 0, 2); if (Formatting.ByteArrayToHexString(card67) == Formatting.ByteArrayToHexString(ctq12)) { cvm = KernelCVMEnum.CONFIRMATION_CODE_VERIFIED; } else { database.DeclineRequiredByReaderIndicator = true; } } else { if (acType == ACTypeEnum.ARQC) { cvm = KernelCVMEnum.CONFIRMATION_CODE_VERIFIED; } else { database.DeclineRequiredByReaderIndicator = true; } } } } if (!ctq.Value.OnlinePINRequired && !ctq.Value.ConsumerDeviceCVMPerformed) { if (ttq.Value.SignatureSupported && ctq.Value.SignatureRequired) { cvm = KernelCVMEnum.OBTAIN_SIGNATURE; } } #endregion } } if (cvm == KernelCVMEnum.N_A && ttq.Value.CVMRequired) { cvm = KernelCVMEnum.NO_CVM; database.DeclineRequiredByReaderIndicator = true; } if (cvm == KernelCVMEnum.N_A) { cvm = KernelCVMEnum.NO_CVM; } return(cvm); }