Exemplo n.º 1
0
        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);
        }