コード例 #1
0
 public KernelDatabaseBase(PublicKeyCertificateManager publicKeyCertificateManager)
 {
     PublicKeyCertificateManager = publicKeyCertificateManager;
     KernelConfigurationData     = new KernelConfigurationData();
     TagsToReadYet = new TLVList();
     StaticDataToBeAuthenticated = new StaticDataToBeAuthenticatedList(this);
 }
コード例 #2
0
        public static ICCDynamicData VerifySDAD(ICCDynamicDataType iccDDType, bool isFirstGenAC, KernelDatabaseBase database, StaticDataToBeAuthenticatedList staticDataToBeAuthenticated, CAPublicKeyCertificate caPublicKey, CardResponse genACCardResponse)
        {
            EMVGenerateACResponse genAcResponse = (genACCardResponse.ApduResponse as EMVGenerateACResponse);

            //section 6.6.2 of EMV book 2 - CDA

            //1.If the Signed Dynamic Application Data has a length different from the
            //length of the ICC Public Key Modulus, CDA has failed
            byte[] sdadRaw = genAcResponse.SignedDynamicApplicationData.Value;
            IssuerPublicKeyCertificate ipk = IssuerPublicKeyCertificate.BuildAndValidatePublicKey(database, caPublicKey.Modulus, caPublicKey.Exponent);

            if (ipk == null)
            {
                return(null);
            }
            IccPublicKeyCertificate iccpk = IccPublicKeyCertificate.BuildAndValidatePublicKey(database, staticDataToBeAuthenticated, ipk.Modulus, ipk.Exponent);

            if (iccpk == null)
            {
                return(null);
            }

            if (sdadRaw.Length != iccpk.Modulus.Length)
            {
                return(null);
            }

            //2.To obtain the recovered data specified in Table 22, apply the recovery
            //function as specified in Annex A2.1 on the Signed Dynamic Application
            //Data using the ICC Public Key in conjunction with the corresponding
            //algorithm.If the Recovered Data Trailer is not equal to 'BC', CDA has
            //failed
            byte[] decrypted = PublicKeyCertificate.DecryptRSA(sdadRaw, iccpk.Modulus, iccpk.Exponent);
            SDAD   sdad      = new SDAD(decrypted);

            //3.Check the Recovered Data Header. If it is not '6A', CDA has failed.
            if (sdad.DataHeader != 0x6A)
            {
                return(null);
            }
            //4.Check the Signed Data Format. If it is not '05', CDA has failed.
            if (sdad.SignedDataFormat != 0x05)
            {
                return(null);
            }

            //5. Retrieve from the ICC Dynamic Data the data specified in Table 19
            ICCDynamicData iccDD = new ICCDynamicData(database, sdad.ICCDynamicData, iccDDType);

            //6.Check that the Cryptogram Information Data retrieved from the ICC
            //Dynamic Data is equal to the Cryptogram Information Data obtained from
            //the response to the GENERATE AC command. If this is not the case, CDA
            //has failed.
            if (genAcResponse.CryptogramInformationData.Value[0] != iccDD.CryptogramInformationData)
            {
                return(null);
            }

            //7.Concatenate from left to right the second to the sixth data elements in
            //Table 22(that is, Signed Data Format through Pad Pattern), followed by
            //the Unpredictable Number.
            byte[] unpredicatbleNumber = database.Get(EMVTagsEnum.UNPREDICTABLE_NUMBER_9F37_KRN).Value;
            byte[] dataForHash         = sdad.Concat(unpredicatbleNumber);

            //8.Apply the indicated hash algorithm (derived from the Hash Algorithm
            //Indicator) to the result of the concatenation of the previous step to
            //produce the hash result.
            byte[] hash = SHA1.Create().ComputeHash(dataForHash);

            //9.Compare the calculated hash result from the previous step with the
            //recovered Hash Result.If they are not the same, CDA has failed.
            if (Formatting.ByteArrayToHexString(sdad.HashResult) != Formatting.ByteArrayToHexString(hash))
            {
                return(null);
            }

            //10. Concatenate from left to right the values of the following data elements:
            List <byte[]> result = new List <byte[]>();

            if (isFirstGenAC)
            {
                //-The values of the data elements specified by, and in the order they
                //appear in the PDOL, and sent by the terminal in the GET
                //PROCESSING OPTIONS command.
                result.Add(database.Get(EMVTagsEnum.PDOL_RELATED_DATA_DF8111_KRN2).Value);
                //-The values of the data elements specified by, and in the order they
                //appear in the CDOL1, and sent by the terminal in the first
                //GENERATE AC command.
                result.Add(database.Get(EMVTagsEnum.CDOL1_RELATED_DATA_DF8107_KRN2).Value);
                //-The tags, lengths, and values of the data elements returned by the ICC
                //in the response to the GENERATE AC command in the order they are
                //returned, with the exception of the Signed Dynamic Application Data.
                foreach (TLV tlv in genAcResponse.GetResponseTags())
                {
                    if (tlv.Tag.TagLable != EMVTagsEnum.SIGNED_DYNAMIC_APPLICATION_DATA_9F4B_KRN.Tag)
                    {
                        result.Add(tlv.Serialize());
                    }
                }
            }
            else
            {
                //-The values of the data elements specified by, and in the order they
                //appear in the PDOL, and sent by the terminal in the GET
                //PROCESSING OPTIONS command.
                result.Add(database.Get(EMVTagsEnum.PDOL_RELATED_DATA_DF8111_KRN2).Value);
                //-The values of the data elements specified by, and in the order they
                //appear in the CDOL1, and sent by the terminal in the first
                //GENERATE AC command.
                result.Add(database.Get(EMVTagsEnum.CDOL1_RELATED_DATA_DF8107_KRN2).Value);
                //-The values of the data elements specified by, and in the order they
                //appear in the CDOL2, and sent by the terminal in the second
                //GENERATE AC command.
                TLV cdol2 = database.Get(EMVTagsEnum.CARD_RISK_MANAGEMENT_DATA_OBJECT_LIST_2_CDOL2_8D_KRN);
                if (cdol2 != null)
                {
                    result.Add(CommonRoutines.PackRelatedDataTag(database, cdol2));
                }
                //-The tags, lengths, and values of the data elements returned by the ICC
                //in the response to the GENERATE AC command in the order they are
                //returned, with the exception of the Signed Dynamic Application Data.
                foreach (TLV tlv in genAcResponse.GetResponseTags())
                {
                    if (tlv.Tag.TagLable != EMVTagsEnum.SIGNED_DYNAMIC_APPLICATION_DATA_9F4B_KRN.Tag)
                    {
                        result.Add(tlv.Serialize());
                    }
                }
            }
            byte[] transactionHashData = result.SelectMany(a => a).ToArray();

            //11.Apply the indicated hash algorithm (derived from the Hash Algorithm
            //Indicator) to the result of the concatenation of the previous step to
            //produce the Transaction Data Hash Code.
            byte[] transactionHash = SHA1.Create().ComputeHash(transactionHashData);

            //12.Compare the calculated Transaction Data Hash Code from the previous
            //step with the Transaction Data Hash Code retrieved from the ICC
            //Dynamic Data in Step 5.If they are not the same, CDA has failed.
            if (Formatting.ByteArrayToHexString(iccDD.TransactionDataHashCode) != Formatting.ByteArrayToHexString(transactionHash))
            {
                return(null);
            }

            return(iccDD);
        }
コード例 #3
0
        internal static IccPublicKeyCertificate BuildAndValidatePublicKey(KernelDatabaseBase database, StaticDataToBeAuthenticatedList staticDataToBeAuthenticated, byte[] issuerPublicKeyModulus, byte[] issuerPublicKeyExponent)
        {
            //section 6.4 EMV 4.3 Book 2

            TLV iccPublicKeyCertificate = database.Get(EMVTagsEnum.INTEGRATED_CIRCUIT_CARD_ICC_PUBLIC_KEY_CERTIFICATE_9F46_KRN);
            TLV iccPublicKeyExponent    = database.Get(EMVTagsEnum.INTEGRATED_CIRCUIT_CARD_ICC_PUBLIC_KEY_EXPONENT_9F47_KRN);
            TLV iccPublicKeyRemainder   = database.Get(EMVTagsEnum.INTEGRATED_CIRCUIT_CARD_ICC_PUBLIC_KEY_REMAINDER_9F48_KRN);

            if (iccPublicKeyCertificate.Value.Length != issuerPublicKeyModulus.Length)
            {
                return(null);
            }

            byte[] decrypt = DecryptRSA(iccPublicKeyCertificate.Value, issuerPublicKeyModulus, issuerPublicKeyExponent);

            IccPublicKeyCertificate iccCertData = new IccPublicKeyCertificate(decrypt, issuerPublicKeyModulus.Length,
                                                                              iccPublicKeyRemainder == null ? new byte[0] : iccPublicKeyRemainder.Value, iccPublicKeyExponent.Value, database.StaticDataToBeAuthenticated.BuildStaticDataToBeAuthenticated());

            if (iccCertData.RecoveredDataTrailer != 0xBC)
            {
                return(null);
            }

            if (iccCertData.RecoveredDataHeader != 0x6A)
            {
                return(null);
            }

            if (iccCertData.CertificateFormat != 0x04)
            {
                return(null);
            }

            if (!iccCertData.ValidateHash())
            {
                return(null);
            }

            string pan          = Formatting.ByteArrayToHexString(database.Get(EMVTagsEnum.APPLICATION_PRIMARY_ACCOUNT_NUMBER_PAN_5A_KRN).Value);
            string panToCompare = Formatting.ByteArrayToHexString(iccCertData.ApplicationPAN).Replace("FF", "");

            if (!pan.StartsWith(panToCompare))
            {
                return(null);
            }

            DateTime expiry = DateTime.ParseExact(Formatting.BcdToString(iccCertData.ExpiryDate), "MMyy", System.Globalization.CultureInfo.InvariantCulture);

            //TODO: if you have a test tool trying to use an expired cert then comment this test out or update your test tool
            //if (expiry <= DateTime.Now)
            //{
            //    Logger.Log("Error: Trying to use an expired issuer public key");
            //    return null;
            //}

            if (iccCertData.PublicKeyAlgorithmIndicator != 0x01)
            {
                return(null);
            }

            if (iccPublicKeyRemainder != null)
            {
                iccCertData.Modulus = Formatting.ConcatArrays(iccCertData.UnpaddedICCPublicKeyorLeftmostDigitsofIssuerPublicKey, iccPublicKeyRemainder.Value);
            }
            else
            {
                iccCertData.Modulus = iccCertData.UnpaddedICCPublicKeyorLeftmostDigitsofIssuerPublicKey;
            }

            return(iccCertData);
        }