public KernelDatabaseBase(PublicKeyCertificateManager publicKeyCertificateManager) { PublicKeyCertificateManager = publicKeyCertificateManager; KernelConfigurationData = new KernelConfigurationData(); TagsToReadYet = new TLVList(); StaticDataToBeAuthenticated = new StaticDataToBeAuthenticatedList(this); }
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); }
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); }