pax_global_header 0000666 0000000 0000000 00000000064 13143103647 0014514 g ustar 00root root 0000000 0000000 52 comment=594f18ab55688e4c1ad6542e4a342b0d25baef57
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/ 0000775 0000000 0000000 00000000000 13143103647 0026060 5 ustar 00root root 0000000 0000000 ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/.cproject 0000664 0000000 0000000 00000066657 13143103647 0027716 0 ustar 00root root 0000000 0000000
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/.gitignore 0000664 0000000 0000000 00000000242 13143103647 0030046 0 ustar 00root root 0000000 0000000 language.settings.xml
*.o
/win32_debug/src/
/win32_release/src/
/win64_debug/src/
/win64_release/src/
/win64_release/
/win32_debug/
/win32_release/
/win64_debug/
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/.gitmodules 0000664 0000000 0000000 00000000135 13143103647 0030234 0 ustar 00root root 0000000 0000000 [submodule "lib"]
path = lib
url = https://git.d-logic.net/nfc-rfid-reader-sdk/ufr-lib.git
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/.project 0000664 0000000 0000000 00000001413 13143103647 0027526 0 ustar 00root root 0000000 0000000
ufr-apdu-credit_card_reader
org.eclipse.cdt.managedbuilder.core.genmakebuilder
clean,full,incremental,
org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
full,incremental,
org.eclipse.cdt.core.cnature
org.eclipse.cdt.managedbuilder.core.managedBuildNature
org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/.settings/ 0000775 0000000 0000000 00000000000 13143103647 0027776 5 ustar 00root root 0000000 0000000 org.eclipse.cdt.core.prefs 0000664 0000000 0000000 00000005122 13143103647 0034672 0 ustar 00root root 0000000 0000000 ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/.settings eclipse.preferences.version=1
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/MINGW_HOME/delimiter=;
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/MINGW_HOME/operation=replace
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/MINGW_HOME/value=C\:\\mingw-w64\\x86_64-5.1.0-posix-seh-rt_v4-rev0\\mingw64
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/append=true
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/appendContributed=true
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/MINGW_HOME/delimiter=;
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/MINGW_HOME/operation=replace
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/MINGW_HOME/value=C\:\\mingw-w64\\i686-5.1.0-posix-dwarf-rt_v4-rev0\\mingw32
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/append=true
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/appendContributed=true
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/MINGW_HOME/delimiter=;
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/MINGW_HOME/operation=replace
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/MINGW_HOME/value=C\:\\mingw-w64\\i686-5.1.0-posix-dwarf-rt_v4-rev0\\mingw32
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/append=true
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/appendContributed=true
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/MINGW_HOME/delimiter=;
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/MINGW_HOME/operation=replace
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/MINGW_HOME/value=C\:\\mingw-w64\\x86_64-5.1.0-posix-seh-rt_v4-rev0\\mingw64
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/append=true
environment/project/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/appendContributed=true
org.eclipse.cdt.managedbuilder.core.prefs 0000664 0000000 0000000 00000012562 13143103647 0037642 0 ustar 00root root 0000000 0000000 ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/.settings eclipse.preferences.version=1
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/CPATH/delimiter=;
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/CPATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/C_INCLUDE_PATH/delimiter=;
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/C_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/append=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/appendContributed=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/CPATH/delimiter=;
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/CPATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/C_INCLUDE_PATH/delimiter=;
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/C_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/append=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/appendContributed=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/CPATH/delimiter=;
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/CPATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/C_INCLUDE_PATH/delimiter=;
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/C_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/append=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/appendContributed=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/CPATH/delimiter=;
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/CPATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/C_INCLUDE_PATH/delimiter=;
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/C_INCLUDE_PATH/operation=remove
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/append=true
environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/appendContributed=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/LIBRARY_PATH/delimiter=;
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/LIBRARY_PATH/operation=remove
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/append=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1226322284/appendContributed=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/LIBRARY_PATH/delimiter=;
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/LIBRARY_PATH/operation=remove
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/append=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369.2075570673/appendContributed=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/LIBRARY_PATH/delimiter=;
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/LIBRARY_PATH/operation=remove
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/append=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958.1777558369/appendContributed=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/LIBRARY_PATH/delimiter=;
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/LIBRARY_PATH/operation=remove
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/append=true
environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1272368177.226908958/appendContributed=true
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/README.md 0000664 0000000 0000000 00000002150 13143103647 0027335 0 ustar 00root root 0000000 0000000 # Example of APDU communication between EMV card and uFR Series readers
ECLIPSE project, written in GCC. Shows usage of uRF Series reader's API, performing APDU communication with EMV contactless card. Reading public data only.
## Getting Started
Download project, compile and run.
Run appropriate binary and follow the menu and instructions.
### Prerequisites
uFR Series reader, minimal firmware version 3.9.39, minimal library version 4.0.26.
Eclipse environment.
### Installing
No installation needed. Precompiled binaries available for Win32 and Win64 platforms, both Debug and Release.
Other supproted platforms are in TODO list, coming soon.
## Compiling
Use Eclipse for compiling, this is Eclipse ready project.
## License
This project is licensed under the ..... License - see the [LICENSE.md](LICENSE.md) file for details
## Acknowledgments
* Purpose of this example is to provide additional info about usage of firmware and API specific features of uFR Series devices.
* It is specific to mentioned hardware ONLY and some other hardware might have different approach, please bear that in mind.
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/lib/ 0000775 0000000 0000000 00000000000 13143103647 0026626 5 ustar 00root root 0000000 0000000 ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/ 0000775 0000000 0000000 00000000000 13143103647 0026647 5 ustar 00root root 0000000 0000000 ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/emv.c 0000664 0000000 0000000 00000043406 13143103647 0027611 0 ustar 00root root 0000000 0000000 /*
* emv.c
*
* Created on: 25.07.2017.
* Author: d-logic
*/
#include
#include
#include
#include "uFR.h"
#include "utils.h"
#include "iso3166.h"
#include "iso4217.h"
#include "emv.h"
//------------------------------------------------------------------------------
emv_tags_t emv_tags[] = {
{0x9f01, "Acquirer Identifier", BIN, 2},
{0x9f02, "Amount, Authorised (Numeric)", BIN, 2},
{0x9f03, "Amount, Other (Numeric)", BIN, 2},
{0x9f04, "Amount, Other (Binary)", BIN, 2},
{0x9f05, "Application Discretionary Data", BIN, 2},
{0x9f06, "Application Identifier (AID) - terminal", BIN, 2},
{0x9f07, "Application Usage Control", BIN, 2},
{0x9f08, "Application Version Number", BIN, 2},
{0x9f09, "Application Version Number", BIN, 2},
{0x9f0b, "Cardholder Name Extended", BIN, 2},
{0xbf0c, "FCI Issuer Discretionary Data", NODE, 2},
{0x9f0d, "Issuer Action Code - Default", BIN, 2},
{0x9f0e, "Issuer Action Code - Denial", BIN, 2},
{0x9f0f, "Issuer Action Code - Online", BIN, 2},
{0x9f10, "Issuer Application Data", BIN, 2},
{0x9f11, "Issuer Code Table Index", BIN, 2},
{0x9f12, "Application Preferred Name", BIN, 2},
{0x9f13, "Last Online Application Transaction Counter (ATC) Register", BIN, 2},
{0x9f14, "Lower Consecutive Offline Limit", BIN, 2},
{0x9f15, "Merchant Category Code", BIN, 2},
{0x9f16, "Merchant Identifier", BIN, 2},
{0x9f17, "Personal Identification Number (PIN) Try Counter", BIN, 2},
{0x9f18, "Issuer Script Identifier", BIN, 2},
{0x9f1a, "Terminal Country Code", ISO3166_COUNTRY, 2},
{0x9f1b, "Terminal Floor Limit", BIN, 2},
{0x9f1c, "Terminal Identification", BIN, 2},
{0x9f1d, "Terminal Risk Management Data", BIN, 2},
{0x9f1e, "Interface Device (IFD) Serial Number", BIN, 2},
{0x9f1f, "Track 1 Discretionary Data", BIN, 2},
{0x5f20, "Cardholder Name", STR, 2},
{0x9f21, "Transaction Time", BIN, 2},
{0x9f22, "Certification Authority Public Key Index", BIN, 2},
{0x9f23, "Upper Consecutive Offline Limit", BIN, 2},
{0x5f24, "Application Expiration Date", DATE_YMD, 2},
{0x5f25, "Application Effective Date", DATE_YMD, 2},
{0x9f26, "Application Cryptogram", BIN, 2},
{0x9f27, "Cryptogram Information Data", BIN, 2},
{0x5f28, "Issuer Country Code", ISO3166_COUNTRY, 2},
{0x5f2a, "Transaction Currency Code", ISO4217_CURRENCY, 2},
{0x5f2d, "Language Preference", LANGUAGE_CODE_PAIRS, 2},
{0x9f2e, "Integrated Circuit Card (ICC) PIN Encipherment Public Key Exponent", BIN, 2},
{0x9f2f, "Integrated Circuit Card (ICC) PIN Encipherment Public Key Remainder", BIN, 2},
{0x5f30, "Service Code", BIN, 2},
{0x9f32, "Issuer Public Key Exponent", BIN, 2},
{0x9f33, "Terminal Capabilities", BIN, 2},
{0x5f34, "Application PAN Sequence Number (PSN)", BIN, 2},
{0x9f35, "Terminal Type", BIN, 2},
{0x5f36, "Transaction Currency Exponent", BIN, 2},
{0x9f37, "Unpredictable Number", BIN, 2},
{0x9f38, "Processing Options Data Object List (PDOL)", TL_LIST, 2},
{0x9f34, "Cardholder Verification Method (CVM) Results", BIN, 2},
{0x9f3a, "Amount, Reference Currency", BIN, 2},
{0x9f3b, "Application Reference Currency", BIN, 2},
{0x9f3c, "Transaction Reference Currency Code", BIN, 2},
{0x9f3d, "Transaction Reference Currency Exponent", BIN, 2},
{0x9f40, "Additional Terminal Capabilities", BIN, 2},
{0x9f41, "Transaction Sequence Counter", BIN, 2},
{0x9f43, "Application Reference Currency Exponent", BIN, 2},
{0x9f44, "Application Currency Exponent", BIN, 2},
{0x9f2d, "Integrated Circuit Card (ICC) PIN Encipherment Public Key Certificate", BIN, 2},
{0x9f46, "Integrated Circuit Card (ICC) Public Key Certificate", BIN, 2},
{0x9f47, "Integrated Circuit Card (ICC) Public Key Exponent", BIN, 2},
{0x9f48, "Integrated Circuit Card (ICC) Public Key Remainder", BIN, 2},
{0x9f49, "Dynamic Data Authentication Data Object List (DDOL)", BIN, 2},
{0x9f4a, "Static Data Authentication Tag List", BIN, 2},
{0x9f4b, "Signed Dynamic Application Data", BIN, 2},
{0x9f4c, "ICC Dynamic Number", BIN, 2},
{0x9f4d, "Log Entry", BIN, 2},
{0x9f4e, "Merchant Name and Location", BIN, 2},
{0x9f51, "Application Currency Code", BIN, 2},
{0x9f52, "Card Verification Results (CVR)", BIN, 2},
{0x5f53, "International Bank Account Number (IBAN)", BIN, 2},
{0x5f54, "Bank Identifier Code (BIC)", BIN, 2},
{0x5f55, "Issuer Country Code (alpha2 format)", BIN, 2},
{0x5f56, "Issuer Country Code (alpha3 format)", BIN, 2},
{0x9f58, "Lower Consecutive Offline Limit (Card Check)", BIN, 2},
{0x9f59, "Upper Consecutive Offline Limit (Card Check)", BIN, 2},
{0x9f5c, "Cumulative Total Transaction Amount Upper Limit", BIN, 2},
{0x9f72, "Consecutive Transaction Limit (International - Country)", BIN, 2},
{0x9f65, "Track 2 Bit Map for CVC3", BIN, 2},
{0x9f66, "Terminal Transaction Qualifiers (TTQ)", BIN, 2},
{0x9f68, "Mag Stripe CVM List", BIN, 2},
{0x9f69, "Unpredictable Number Data Object List (UDOL)", BIN, 2},
{0x9f6b, "Track 2 Data", BIN, 2},
{0x9f6c, "Mag Stripe Application Version Number (Card)", BIN, 2},
{0x9f6e, "Third Party Data", BIN, 2},
{0x9f74, "VLP Issuer Authorization Code", BIN, 2},
{0x9f75, "Cumulative Total Transaction Amount Limit - Dual Currency", BIN, 2},
{0x9f76, "Secondary Application Currency Code", ISO4217_CURRENCY, 2},
{0x9f7d, "Unknown Tag", BIN, 2},
{0x9f7f, "Card Production Life Cycle (CPLC) History File Identifiers", BIN, 2},
{0x9f45, "Data Authentication Code", BIN, 2},
{0x9f57, "Issuer Country Code", BIN, 2},
{0x9f39, "Point-of-Service (POS) Entry Mode", BIN, 2},
{0x9f73, "Currency Conversion Factor", BIN, 2},
{0x9f42, "Application Currency Code", ISO4217_CURRENCY, 2},
{0x9f56, "Issuer Authentication Indicator", BIN, 2},
{0x9f20, "Track 2 Discretionary Data", BIN, 2},
{0xdf01, "Reference PIN", BIN, 2},
{0x9f36, "Application Transaction Counter (ATC)", BIN, 2},
{0x9f4f, "Log Format", TL_LIST, 2},
{0x5f50, "Issuer URL", BIN, 2},
{0x9f5a, "Issuer URL2", BIN, 2},
{0x9f53, "Consecutive Transaction Limit (International)", BIN, 2},
{0x9f54, "Cumulative Total Transaction Amount Limit", BIN, 2},
{0x9f55, "Geographic Indicator", BIN, 2},
{0x42, "Issuer Identification Number (IIN)", BIN, 1},
{0x4f, "Application Identifier (AID)", BIN, 1},
{0x50, "Application Label", STR, 1},
{0x57, "Track 2 Equivalent Data", BIN, 1},
{0x5a, "Application Primary Account Number (PAN)", BCD_4BY4, 1},
{0x61, "Application Template", NODE, 1},
{0x6f, "File Control Information (FCI) Template", NODE, 1},
{0x70, "Response Message Template / AEF Data Template", NODE, 1},
{0x71, "Issuer Script Template 1", BIN, 1},
{0x72, "Issuer Script Template 2", BIN, 1},
{0x73, "Directory Discretionary Template", BIN, 1},
{0x77, "Response Message Template Format 2", NODE, 1},
{0x80, "Response Message Template Format 1", BIN, 1},
{0x81, "Amount, Authorised (Binary)", BIN, 1},
{0x82, "Application Interchange Profile", BIN, 1},
{0x83, "Command Template", BIN, 1},
{0x84, "Dedicated File (DF) Name", BIN_OR_STR, 1},
{0x86, "Issuer Script Command", BIN, 1},
{0x87, "Application Priority Indicator", BIN, 1},
{0x88, "Short File Identifier (SFI)", BIN, 1},
{0x89, "Authorisation Code", BIN, 1},
{0x8a, "Authorisation Response Code", BIN, 1},
{0x8c, "Card Risk Management Data Object List 1 (CDOL1)", BIN, 1},
{0x8d, "Card Risk Management Data Object List 2 (CDOL2)", BIN, 1},
{0x8e, "Cardholder Verification Method (CVM) List", BIN, 1},
{0x8f, "Certification Authority Public Key Index", BIN, 1},
{0x90, "Issuer Public Key Certificate", BIN, 1},
{0x91, "Issuer Authentication Data", BIN, 1},
{0x92, "Issuer Public Key Remainder", BIN, 1},
{0x93, "Signed Static Application Data", BIN, 1},
{0x94, "Application File Locator (AFL)", BIN, 1},
{0x95, "Terminal Verification Results", BIN, 1},
{0x97, "Transaction Certificate Data Object List (TDOL)", BIN, 1},
{0x98, "Transaction Certificate (TC) Hash Value", BIN, 1},
{0x99, "Transaction Personal Identification Number (PIN) Data", BIN, 1},
{0x9a, "Transaction Date", DATE_YMD, 1},
{0x9b, "Transaction Status Information", BIN, 1},
{0x9c, "Transaction Type", BIN, 1},
{0x9d, "Directory Definition File (DDF) Name", BIN, 1},
{0xa5, "File Control Information (FCI) Proprietary Template", NODE, 1},
{0, "UNKNOWN TAG", BIN, 0}
};
char * months[] = {"", "jan.", "feb.", "mar.", "apr.", "may ", "jun.", "jul.", "aug.", "sep.", "oct.", "nov.", "dec."};
//------------------------------------------------------------------------------
emv_tag_index_t findEmvTagIndex(emv_tag_t tag)
{
emv_tag_index_t i = 0;
do {
if (emv_tags[i].tag == tag)
break;
i++;
} while (emv_tags[i].tag_id_len != 0);
return i;
}
//------------------------------------------------------------------------------
void print_tab(int tabulator)
{
for (int i = 0; i < tabulator; i++)
printf(" ");
}
//------------------------------------------------------------------------------
void printEmvNode(emv_tree_node_t *tag_node, int tabulator)
{
char *s;
int temp;
bool end_ln = true;
print_tab(tabulator);
printf("<> tag=");
switch (tag_node->tag_bytes) {
case 1:
printf("%02X", tag_node->tag);
break;
case 2:
printf("%04X", tag_node->tag);
break;
case 3:
printf("%06X", tag_node->tag);
break;
default:
printf("%08X", tag_node->tag);
break;
}
printf(" length=%d\n", tag_node->value_len);
print_tab(tabulator);
printf(" desc: %s\n", tag_node->description);
// print value:
if (tag_node->value) {
print_tab(tabulator);
printf(" value: ");
switch (tag_node->tag_type) {
case STR:
printf("\"%s\"", (char *) tag_node->value);
break;
case LANGUAGE_CODE_PAIRS:
if (!tag_node->value_len || tag_node->value_len % 2) {
print_hex(tag_node->value, tag_node->value_len, NULL);
} else {
temp = 0;
while (temp < tag_node->value_len) {
s = malloc(3);
if (s != NULL) {
memcpy(s, tag_node->value + temp, 2);
s[2] = '\0';
printf("%s", s);
free(s);
} else {
print_hex(tag_node->value, tag_node->value_len, NULL);
break;
}
temp += 2;
if (temp < tag_node->value_len) {
printf(", ");
}
}
}
break;
case BCD_4BY4:
if (tag_node->value_len == 8)
{
print_hex(tag_node->value, 2, NULL);
printf("-");
print_hex(tag_node->value + 2, 2, NULL);
printf("-");
print_hex(tag_node->value + 4, 2, NULL);
printf("-");
print_hex(tag_node->value + 6, 2, NULL);
}
else
printf("%d", (int)*((uint8_t *)tag_node->value));
break;
case DEC_UINT8:
printf("%d", (int)*((uint8_t *)tag_node->value));
break;
case DEC_UINT16:
printf("%d", (int)*((uint16_t *)tag_node->value));
break;
case DEC_UINT32:
printf("%d", (int)*((uint32_t *)tag_node->value));
break;
case ISO3166_COUNTRY:
temp = findCountryIndexByNumCode(bin_bcd_to_i(tag_node->value, 2));
printf("%s (%s)", iso3166_country_codes[temp].alpha2_code, iso3166_country_codes[temp].country);
break;
case ISO4217_CURRENCY:
temp = findCurrencyIndexByNumCode(bin_bcd_to_i(tag_node->value, 2));
printf("%s (%s)", iso4217_currency_codes[temp].alpha_code, iso4217_currency_codes[temp].currency);
break;
case DATE_YMD:
if (tag_node->value_len == 3)
{
print_hex(tag_node->value + 2, 1, NULL);
printf(". %s 20", months[bin_bcd_to_i(tag_node->value + 1, 1)]);
print_hex(tag_node->value, 1, NULL);
}
else
print_hex(tag_node->value, tag_node->value_len, NULL);
break;
case BIN_OR_STR:
if (isByteArrayPrintable(tag_node->value, tag_node->value_len)) {
s = malloc(tag_node->value_len + 1);
if (s != NULL) {
memcpy(s, tag_node->value, tag_node->value_len);
s[tag_node->value_len] = '\0';
printf("\"%s\"", s);
free(s);
} else {
print_hex(tag_node->value, tag_node->value_len, NULL);
}
} else
print_hex(tag_node->value, tag_node->value_len, NULL);
break;
case TL_LIST:
print_hex_ln(tag_node->value, tag_node->value_len, NULL);
print_tab(tabulator + TAB_STEP);
printf("parsed list (from value):\n");
printEmvBranch(tag_node->tl_list_format, tabulator + 2 * TAB_STEP);
end_ln = false;
break;
case BIN:
print_hex(tag_node->value, tag_node->value_len, NULL);
break;
default:
break;
}
if (end_ln)
printf("\n");
}
}
//------------------------------------------------------------------------------
void printEmvBranch(emv_tree_node_t *tag_node, int tabulator)
{
while (tag_node)
{
printEmvNode(tag_node, tabulator);
if (tag_node->subnode != NULL) {
printEmvBranch(tag_node->subnode, tabulator + TAB_STEP);
}
tag_node = tag_node->next;
}
}
//------------------------------------------------------------------------------
EMV_STATUS getSfi(emv_tree_node_t *tag_node, uint8_t *sfi) {
if (!tag_node)
return EMV_ERR_TAG_NOT_FOUND;
if (tag_node->tag == 0x88) {
if (tag_node->value_len == 1) {
*sfi = tag_node->value[0];
return EMV_OK;
} else {
return EMV_ERR_TAG_WRONG_SIZE;
}
} else {
if (tag_node->subnode) {
return getSfi(tag_node->subnode, sfi);
} else {
return getSfi(tag_node->next, sfi);
}
}
}
//------------------------------------------------------------------------------
EMV_STATUS getAID(emv_tree_node_t *tag_node, uint8_t *aid, uint8_t *aid_len)
{
if (!tag_node)
return EMV_ERR_TAG_NOT_FOUND;
if (tag_node->tag == 0x4F) {
if (tag_node->value_len < 17) {
memcpy(aid, tag_node->value, tag_node->value_len);
*aid_len = (uint8_t)tag_node->value_len;
return EMV_OK;
} else {
return EMV_ERR_TAG_WRONG_SIZE;
}
} else {
if (tag_node->subnode) {
return getAID(tag_node->subnode, aid, aid_len);
} else {
return getAID(tag_node->next, aid, aid_len);
}
}
}
//------------------------------------------------------------------------------
EMV_STATUS parseEmvTag(uint8_t *tag_ptr, emv_tag_t *tag, uint8_t **tag_val, int32_t *tag_len, int32_t *tag_len_len, int32_t *tag_val_len)
{
// Tag parsing rules: there is at least 2 bytes if (MSB & 0x1F) == 0x1F
// and if (2nd_byte & 0x80) == 0x80 there is third byte:
*tag = *tag_ptr++;
*tag_len = 1;
if ((*tag & 0x1F) == 0x1F) {
*tag <<= 8;
*tag |= *tag_ptr;
(*tag_len)++;
if ((*tag_ptr++ & 0x80) == 0x80) {
*tag <<= 8;
*tag |= *tag_ptr++;
(*tag_len)++;
}
}
// Length:
*tag_len_len = 1;
*tag_val_len = *tag_ptr;
if ((*tag_ptr & 0x80) == 0x80) {
*tag_len_len += *tag_ptr & 0x7F;
}
if (*tag_len_len > MAX_TAG_LEN_BYTES)
return EMV_ERR_MAX_TAG_LEN_BYTES_EXCEEDED;
tag_ptr++;
if (*tag_len_len > 1) {
*tag_val_len = 0;
for (int i = *tag_len_len - 1 ; i > 0; i--) {
*tag_val_len |= *tag_ptr++ << ((i - 1) * 8);
}
}
*tag_val = tag_ptr;
return EMV_OK;
}
//------------------------------------------------------------------------------
EMV_STATUS newEmvTag(emv_tree_node_t **head, uint8_t *input, int32_t input_bytes_left, bool is_list_format)
{
emv_tree_node_t *p;
emv_tag_index_t tag_index = 0;
emv_tag_t tag = 0;
uint8_t *tag_val;
int32_t tag_len = 0, tag_len_len = 0, tag_val_len = 0;
int32_t temp;
bool is_node_type;
EMV_STATUS status;
status = parseEmvTag(input, &tag, &tag_val, &tag_len, &tag_len_len, &tag_val_len);
if (status != EMV_OK) {
return status;
}
tag_index = findEmvTagIndex(tag);
is_node_type = (emv_tags[tag_index].tag_type == NODE);
temp = tag_len + tag_len_len;
if (!is_node_type && !is_list_format) {
temp += tag_val_len;
}
input_bytes_left -= temp;
input += temp;
p = malloc(sizeof(emv_tree_node_t));
if (p == NULL) {
return SYS_ERR_OUT_OF_MEMORY;
} else {
*head = p;
}
p->is_node_type = is_node_type;
p->tag = tag;
p->tag_bytes = tag_len;
p->tag_type = emv_tags[tag_index].tag_type;
p->description = emv_tags[tag_index].description; // pointer to constant in "code segment"
p->tl_list_format = NULL;
p->subnode = NULL;
p->next = NULL;
p->value = NULL;
p->value_len = tag_val_len;
if (!(p->is_node_type) && !is_list_format && tag_val_len) {
if (p->tag_type == STR)
temp = tag_val_len + 1;
else
temp = tag_val_len;
p->value = malloc(temp);
if (p->value == NULL) {
return SYS_ERR_OUT_OF_MEMORY;
}
p->value_len = tag_val_len;
memcpy(p->value, tag_val, tag_val_len);
if (p->tag_type == STR)
((char *)(p->value))[tag_val_len] = '\0';
}
if (p->tag_type == TL_LIST) {
status = newEmvTag(&(p->tl_list_format), p->value, p->value_len, true);
}
if ((input_bytes_left < 0) || (is_node_type && (input_bytes_left != tag_val_len)))
return EMV_ERR_WRONG_INPUT_DATA;
else if (input_bytes_left > 0)
{
// Parsing not finished:
if (p->is_node_type) {
status = newEmvTag(&(p->subnode), input, input_bytes_left, false);
} else {
status = newEmvTag(&(p->next), input, input_bytes_left, is_list_format);
}
if (status != EMV_OK) {
return status;
}
}
return EMV_OK;
}
//------------------------------------------------------------------------------
void emvTreeCleanup(emv_tree_node_t *head) {
emv_tree_node_t *temp;
while (head) {
if (head->subnode) {
emvTreeCleanup(head->subnode);
}
if (head->value)
free(head->value);
temp = head->next;
free(head);
head = temp;
}
}
//------------------------------------------------------------------------------
// uint8_t *r_apdu - minimum of the 256 bytes have to be allocated before call
EMV_STATUS emvReadRecord(uint8_t *r_apdu, uint32_t *Ne, uint8_t sfi, uint8_t record, uint8_t sw[2]) {
UFR_STATUS status;
uint16_t *sw16_ptr = (uint16_t *) sw;
sfi <<= 3;
sfi |= 4;
*Ne = 256;
status = APDUTransceive(0x00, 0xB2, record, sfi, NULL, 0, r_apdu, Ne, 1, sw);
if (status != UFR_OK)
return EMV_ERR_IN_CARD_READER;
if (sw[0] == 0x6C) {
*Ne = sw[1];
status = APDUTransceive(0x00, 0xB2, record, sfi, NULL, 0, r_apdu, Ne, 1, sw);
if (status != UFR_OK)
return EMV_ERR_IN_CARD_READER;
} else if (*sw16_ptr == 0x8262)
*sw16_ptr = 0x90;
if (*sw16_ptr != 0x90)
return EMV_ERR_READING_RECORD;
return EMV_OK;
}
//------------------------------------------------------------------------------
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/emv.h 0000664 0000000 0000000 00000004546 13143103647 0027620 0 ustar 00root root 0000000 0000000 /*
* emv.h
*
* Created on: 25.07.2017.
* Author: d-logic
*/
#ifndef EMV_H_
#define EMV_H_
//------------------------------------------------------------------------------
#include
#include
#include
//------------------------------------------------------------------------------
#define MAX_TAG_LEN_BYTES 3
#define TAB_STEP 3
//==============================================================================
typedef enum E_TAG_TYPE {
STR = 10,
LANGUAGE_CODE_PAIRS,
BCD_4BY4,
DEC_UINT8,
DEC_UINT16,
DEC_UINT32,
ISO3166_COUNTRY,
ISO4217_CURRENCY,
DATE_YMD,
BIN_OR_STR,
BIN,
//-------------------
TL_LIST,
NODE,
//-------------------
} tag_type_t;
//------------------------------------------------------------------------------
typedef enum E_EMV_STATUS {
EMV_OK,
SYS_ERR_OUT_OF_MEMORY,
EMV_ERR_WRONG_INPUT_DATA,
EMV_ERR_MAX_TAG_LEN_BYTES_EXCEEDED,
EMV_ERR_TAG_NOT_FOUND,
EMV_ERR_TAG_WRONG_SIZE,
EMV_ERR_IN_CARD_READER,
EMV_ERR_READING_RECORD
} EMV_STATUS;
//==============================================================================
typedef uint32_t emv_tag_t;
typedef uint8_t emv_tag_index_t;
//------------------------------------------------------------------------------
typedef struct emv_tags_s {
emv_tag_t tag;
char *description;
tag_type_t tag_type;
uint8_t tag_id_len;
} emv_tags_t;
//------------------------------------------------------------------------------
typedef struct emv_tree_node_s emv_tree_node_t;
struct emv_tree_node_s {
emv_tag_t tag;
uint8_t tag_bytes;
char *description;
tag_type_t tag_type;
bool is_node_type;
uint8_t *value;
uint32_t value_len;
emv_tree_node_t *tl_list_format;
emv_tree_node_t *next;
emv_tree_node_t *subnode;
};
EMV_STATUS getSfi(emv_tree_node_t *tag_node, uint8_t *sfi);
EMV_STATUS getAID(emv_tree_node_t *tag_node, uint8_t *aid, uint8_t *aid_len);
void printEmvBranch(emv_tree_node_t *tag_node, int tabulator);
EMV_STATUS newEmvTag(emv_tree_node_t **head, uint8_t *input, int32_t input_bytes_left, bool is_list_format);
void emvTreeCleanup(emv_tree_node_t *head);
// emvReadRecord()
// uint8_t *r_apdu - minimum of the 256 bytes have to be allocated before call
EMV_STATUS emvReadRecord(uint8_t *r_apdu, uint32_t *Ne, uint8_t sfi, uint8_t record, uint8_t sw[2]);
//==============================================================================
#endif /* EMV_H_ */
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/ini.h 0000664 0000000 0000000 00000000601 13143103647 0027574 0 ustar 00root root 0000000 0000000 /*
* ini.h
*/
#ifndef INI_H_
#define INI_H_
#define APP_VERSION "1.0"
#define EXIT_ON_WRONG_FW_DEPENDENCY
#define MIN_DEPEND_FW_VER_MAJOR 3
#define MIN_DEPEND_FW_VER_MINOR 9
#define MIN_DEPEND_FW_VER_BUILD 41
#define EXIT_ON_WRONG_LIB_DEPENDENCY
#define MIN_DEPEND_LIB_VER_MAJOR 4
#define MIN_DEPEND_LIB_VER_MINOR 0
#define MIN_DEPEND_LIB_VER_BUILD 27
#endif /* INI_H_ */
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/iso3166.c 0000664 0000000 0000000 00000024241 13143103647 0030130 0 ustar 00root root 0000000 0000000 /*
* iso3166.c
*
* Created on: 09.08.2017.
* Author: d-logic
*/
#include "iso3166.h"
iso3166_country_code_t iso3166_country_codes[] = {
{ 4, "AF", "AFG", "Afghanistan" },
{ 8, "AL", "ALB", "Albania" },
{ 10, "AQ", "ATA", "Antarctica" },
{ 12, "DZ", "DZA", "Algeria" },
{ 16, "AS", "ASM", "American Samoa" },
{ 20, "AD", "AND", "Andorra" },
{ 24, "AO", "AGO", "Angola" },
{ 28, "AG", "ATG", "Antigua and Barbuda" },
{ 31, "AZ", "AZE", "Azerbaijan" },
{ 32, "AR", "ARG", "Argentina" },
{ 36, "AU", "AUS", "Australia" },
{ 40, "AT", "AUT", "Austria" },
{ 44, "BS", "BHS", "Bahamas" },
{ 48, "BH", "BHR", "Bahrain" },
{ 50, "BD", "BGD", "Bangladesh" },
{ 51, "AM", "ARM", "Armenia" },
{ 52, "BB", "BRB", "Barbados" },
{ 56, "BE", "BEL", "Belgium" },
{ 60, "BM", "BMU", "Bermuda" },
{ 64, "BT", "BTN", "Bhutan" },
{ 68, "BO", "BOL", "Bolivia (Plurinational State of)" },
{ 70, "BA", "BIH", "Bosnia and Herzegovina" },
{ 72, "BW", "BWA", "Botswana" },
{ 74, "BV", "BVT", "Bouvet Island" },
{ 76, "BR", "BRA", "Brazil" },
{ 84, "BZ", "BLZ", "Belize" },
{ 86, "IO", "IOT", "British Indian Ocean Territory" },
{ 90, "SB", "SLB", "Solomon Islands" },
{ 92, "VG", "VGB", "Virgin Islands (British)" },
{ 96, "BN", "BRN", "Brunei Darussalam" },
{ 100, "BG", "BGR", "Bulgaria" },
{ 104, "MM", "MMR", "Myanmar" },
{ 108, "BI", "BDI", "Burundi" },
{ 112, "BY", "BLR", "Belarus" },
{ 116, "KH", "KHM", "Cambodia" },
{ 120, "CM", "CMR", "Cameroon" },
{ 124, "CA", "CAN", "Canada" },
{ 132, "CV", "CPV", "Cabo Verde" },
{ 136, "KY", "CYM", "Cayman Islands" },
{ 140, "CF", "CAF", "Central African Republic" },
{ 144, "LK", "LKA", "Sri Lanka" },
{ 148, "TD", "TCD", "Chad" },
{ 152, "CL", "CHL", "Chile" },
{ 156, "CN", "CHN", "China" },
{ 158, "TW", "TWN", "Taiwan \"Province of China\"" },
{ 162, "CX", "CXR", "Christmas Island" },
{ 166, "CC", "CCK", "Cocos (Keeling) Islands" },
{ 170, "CO", "COL", "Colombia" },
{ 174, "KM", "COM", "Comoros" },
{ 175, "YT", "MYT", "Mayotte" },
{ 178, "CG", "COG", "Congo" },
{ 180, "CD", "COD", "Congo (Democratic Republic of the)" },
{ 184, "CK", "COK", "Cook Islands" },
{ 188, "CR", "CRI", "Costa Rica" },
{ 191, "HR", "HRV", "Croatia" },
{ 192, "CU", "CUB", "Cuba" },
{ 196, "CY", "CYP", "Cyprus" },
{ 203, "CZ", "CZE", "Czechia" },
{ 204, "BJ", "BEN", "Benin" },
{ 208, "DK", "DNK", "Denmark" },
{ 212, "DM", "DMA", "Dominica" },
{ 214, "DO", "DOM", "Dominican Republic" },
{ 218, "EC", "ECU", "Ecuador" },
{ 222, "SV", "SLV", "El Salvador" },
{ 226, "GQ", "GNQ", "Equatorial Guinea" },
{ 231, "ET", "ETH", "Ethiopia" },
{ 232, "ER", "ERI", "Eritrea" },
{ 233, "EE", "EST", "Estonia" },
{ 234, "FO", "FRO", "Faroe Islands" },
{ 238, "FK", "FLK", "Falkland Islands (Malvinas)" },
{ 239, "GS", "SGS", "South Georgia and the South Sandwich Islands" },
{ 242, "FJ", "FJI", "Fiji" },
{ 246, "FI", "FIN", "Finland" },
{ 248, "AX", "ALA", "Aland Islands" },
{ 250, "FR", "FRA", "France" },
{ 254, "GF", "GUF", "French Guiana" },
{ 258, "PF", "PYF", "French Polynesia" },
{ 260, "TF", "ATF", "French Southern Territories" },
{ 262, "DJ", "DJI", "Djibouti" },
{ 266, "GA", "GAB", "Gabon" },
{ 268, "GE", "GEO", "Georgia" },
{ 270, "GM", "GMB", "Gambia" },
{ 275, "PS", "PSE", "Palestine \"State of\"" },
{ 276, "DE", "DEU", "Germany" },
{ 288, "GH", "GHA", "Ghana" },
{ 292, "GI", "GIB", "Gibraltar" },
{ 296, "KI", "KIR", "Kiribati" },
{ 300, "GR", "GRC", "Greece" },
{ 304, "GL", "GRL", "Greenland" },
{ 308, "GD", "GRD", "Grenada" },
{ 312, "GP", "GLP", "Guadeloupe" },
{ 316, "GU", "GUM", "Guam" },
{ 320, "GT", "GTM", "Guatemala" },
{ 324, "GN", "GIN", "Guinea" },
{ 328, "GY", "GUY", "Guyana" },
{ 332, "HT", "HTI", "Haiti" },
{ 334, "HM", "HMD", "Heard Island and McDonald Islands" },
{ 336, "VA", "VAT", "Holy See" },
{ 340, "HN", "HND", "Honduras" },
{ 344, "HK", "HKG", "Hong Kong" },
{ 348, "HU", "HUN", "Hungary" },
{ 352, "IS", "ISL", "Iceland" },
{ 356, "IN", "IND", "India" },
{ 360, "ID", "IDN", "Indonesia" },
{ 364, "IR", "IRN", "Iran (Islamic Republic of)" },
{ 368, "IQ", "IRQ", "Iraq" },
{ 372, "IE", "IRL", "Ireland" },
{ 376, "IL", "ISR", "Israel" },
{ 380, "IT", "ITA", "Italy" },
{ 384, "CI", "CIV", "Ivory Coast" },
{ 388, "JM", "JAM", "Jamaica" },
{ 392, "JP", "JPN", "Japan" },
{ 398, "KZ", "KAZ", "Kazakhstan" },
{ 400, "JO", "JOR", "Jordan" },
{ 404, "KE", "KEN", "Kenya" },
{ 408, "KP", "PRK", "Korea (Democratic People's Republic of)" },
{ 410, "KR", "KOR", "Korea (Republic of)" },
{ 414, "KW", "KWT", "Kuwait" },
{ 417, "KG", "KGZ", "Kyrgyzstan" },
{ 418, "LA", "LAO", "Lao People's Democratic Republic" },
{ 422, "LB", "LBN", "Lebanon" },
{ 426, "LS", "LSO", "Lesotho" },
{ 428, "LV", "LVA", "Latvia" },
{ 430, "LR", "LBR", "Liberia" },
{ 434, "LY", "LBY", "Libya" },
{ 438, "LI", "LIE", "Liechtenstein" },
{ 440, "LT", "LTU", "Lithuania" },
{ 442, "LU", "LUX", "Luxembourg" },
{ 446, "MO", "MAC", "Macao" },
{ 450, "MG", "MDG", "Madagascar" },
{ 454, "MW", "MWI", "Malawi" },
{ 458, "MY", "MYS", "Malaysia" },
{ 462, "MV", "MDV", "Maldives" },
{ 466, "ML", "MLI", "Mali" },
{ 470, "MT", "MLT", "Malta" },
{ 474, "MQ", "MTQ", "Martinique" },
{ 478, "MR", "MRT", "Mauritania" },
{ 480, "MU", "MUS", "Mauritius" },
{ 484, "MX", "MEX", "Mexico" },
{ 492, "MC", "MCO", "Monaco" },
{ 496, "MN", "MNG", "Mongolia" },
{ 498, "MD", "MDA", "Moldova (Republic of)" },
{ 499, "ME", "MNE", "Montenegro" },
{ 500, "MS", "MSR", "Montserrat" },
{ 504, "MA", "MAR", "Morocco" },
{ 508, "MZ", "MOZ", "Mozambique" },
{ 512, "OM", "OMN", "Oman" },
{ 516, "NA", "NAM", "Namibia" },
{ 520, "NR", "NRU", "Nauru" },
{ 524, "NP", "NPL", "Nepal" },
{ 528, "NL", "NLD", "Netherlands" },
{ 531, "CW", "CUW", "Curacao" },
{ 533, "AW", "ABW", "Aruba" },
{ 534, "SX", "SXM", "Sint Maarten (Dutch part)" },
{ 535, "BQ", "BES", "Bonaire \"Sint Eustatius and Saba\"" },
{ 540, "NC", "NCL", "New Caledonia" },
{ 548, "VU", "VUT", "Vanuatu" },
{ 554, "NZ", "NZL", "New Zealand" },
{ 558, "NI", "NIC", "Nicaragua" },
{ 562, "NE", "NER", "Niger" },
{ 566, "NG", "NGA", "Nigeria" },
{ 570, "NU", "NIU", "Niue" },
{ 574, "NF", "NFK", "Norfolk Island" },
{ 578, "NO", "NOR", "Norway" },
{ 580, "MP", "MNP", "Northern Mariana Islands" },
{ 581, "UM", "UMI", "United States Minor Outlying Islands" },
{ 583, "FM", "FSM", "Micronesia (Federated States of)" },
{ 584, "MH", "MHL", "Marshall Islands" },
{ 585, "PW", "PLW", "Palau" },
{ 586, "PK", "PAK", "Pakistan" },
{ 591, "PA", "PAN", "Panama" },
{ 598, "PG", "PNG", "Papua New Guinea" },
{ 600, "PY", "PRY", "Paraguay" },
{ 604, "PE", "PER", "Peru" },
{ 608, "PH", "PHL", "Philippines" },
{ 612, "PN", "PCN", "Pitcairn" },
{ 616, "PL", "POL", "Poland" },
{ 620, "PT", "PRT", "Portugal" },
{ 624, "GW", "GNB", "Guinea-Bissau" },
{ 626, "TL", "TLS", "Timor-Leste" },
{ 630, "PR", "PRI", "Puerto Rico" },
{ 634, "QA", "QAT", "Qatar" },
{ 638, "RE", "REU", "Reunion" },
{ 642, "RO", "ROU", "Romania" },
{ 643, "RU", "RUS", "Russian Federation" },
{ 646, "RW", "RWA", "Rwanda" },
{ 652, "BL", "BLM", "Saint Barthelemy" },
{ 654, "SH", "SHN", "Saint Helena \"Ascension and Tristan da Cunha\"" },
{ 659, "KN", "KNA", "Saint Kitts and Nevis" },
{ 660, "AI", "AIA", "Anguilla" },
{ 662, "LC", "LCA", "Saint Lucia" },
{ 663, "MF", "MAF", "Saint Martin (French part)" },
{ 666, "PM", "SPM", "Saint Pierre and Miquelon" },
{ 670, "VC", "VCT", "Saint Vincent and the Grenadines" },
{ 674, "SM", "SMR", "San Marino" },
{ 678, "ST", "STP", "Sao Tome and Principe" },
{ 682, "SA", "SAU", "Saudi Arabia" },
{ 686, "SN", "SEN", "Senegal" },
{ 688, "RS", "SRB", "Serbia" },
{ 690, "SC", "SYC", "Seychelles" },
{ 694, "SL", "SLE", "Sierra Leone" },
{ 702, "SG", "SGP", "Singapore" },
{ 703, "SK", "SVK", "Slovakia" },
{ 704, "VN", "VNM", "Viet Nam" },
{ 705, "SI", "SVN", "Slovenia" },
{ 706, "SO", "SOM", "Somalia" },
{ 710, "ZA", "ZAF", "South Africa" },
{ 716, "ZW", "ZWE", "Zimbabwe" },
{ 724, "ES", "ESP", "Spain" },
{ 728, "SS", "SSD", "South Sudan" },
{ 729, "SD", "SDN", "Sudan" },
{ 732, "EH", "ESH", "Western Sahara" },
{ 740, "SR", "SUR", "Suriname" },
{ 744, "SJ", "SJM", "Svalbard and Jan Mayen" },
{ 748, "SZ", "SWZ", "Swaziland" },
{ 752, "SE", "SWE", "Sweden" },
{ 756, "CH", "CHE", "Switzerland" },
{ 760, "SY", "SYR", "Syrian Arab Republic" },
{ 762, "TJ", "TJK", "Tajikistan" },
{ 764, "TH", "THA", "Thailand" },
{ 768, "TG", "TGO", "Togo" },
{ 772, "TK", "TKL", "Tokelau" },
{ 776, "TO", "TON", "Tonga" },
{ 780, "TT", "TTO", "Trinidad and Tobago" },
{ 784, "AE", "ARE", "United Arab Emirates" },
{ 788, "TN", "TUN", "Tunisia" },
{ 792, "TR", "TUR", "Turkey" },
{ 795, "TM", "TKM", "Turkmenistan" },
{ 796, "TC", "TCA", "Turks and Caicos Islands" },
{ 798, "TV", "TUV", "Tuvalu" },
{ 800, "UG", "UGA", "Uganda" },
{ 804, "UA", "UKR", "Ukraine" },
{ 807, "MK", "MKD", "Macedonia (the former Yugoslav Republic of)" },
{ 818, "EG", "EGY", "Egypt" },
{ 826, "GB", "GBR", "United Kingdom of Great Britain and Northern Ireland" },
{ 831, "GG", "GGY", "Guernsey" },
{ 832, "JE", "JEY", "Jersey" },
{ 833, "IM", "IMN", "Isle of Man" },
{ 834, "TZ", "TZA", "Tanzania \"United Republic of\"" },
{ 840, "US", "USA", "United States of America" },
{ 850, "VI", "VIR", "Virgin Islands (U.S.)" },
{ 854, "BF", "BFA", "Burkina Faso" },
{ 858, "UY", "URY", "Uruguay" },
{ 860, "UZ", "UZB", "Uzbekistan" },
{ 862, "VE", "VEN", "Venezuela (Bolivarian Republic of)" },
{ 876, "WF", "WLF", "Wallis and Futuna" },
{ 882, "WS", "WSM", "Samoa" },
{ 887, "YE", "YEM", "Yemen" },
{ 894, "ZM", "ZMB", "Zambia" },
{ 0, "--", "---", "Unknown country" }
};
//------------------------------------------------------------------------------
int findCountryIndexByNumCode(uint16_t num_code)
{
int i = 0;
do {
if (iso3166_country_codes[i].num_code == num_code)
break;
i++;
} while (iso3166_country_codes[i].num_code != 0);
return i;
}
//------------------------------------------------------------------------------
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/iso3166.h 0000664 0000000 0000000 00000001336 13143103647 0030135 0 ustar 00root root 0000000 0000000 /*
* iso3166.h
*
* Created on: 10.08.2017.
* Author: Zborac
*/
#ifndef ISO3166_H_
#define ISO3166_H_
#include
//==============================================================================
typedef struct iso3166_country_code_s {
uint16_t num_code;
char *alpha2_code;
char *alpha3_code;
char *country;
} iso3166_country_code_t;
//------------------------------------------------------------------------------
extern iso3166_country_code_t iso3166_country_codes[];
//------------------------------------------------------------------------------
int findCountryIndexByNumCode(uint16_t num_code);
//==============================================================================
#endif /* ISO3166_H_ */
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/iso4217.c 0000664 0000000 0000000 00000014234 13143103647 0030127 0 ustar 00root root 0000000 0000000 /*
* iso4217_currency_codes.c
*
* Created on: 09.08.2017.
* Author: d-logic
*/
#include "iso4217.h"
iso4217_currency_code_t iso4217_currency_codes[] = {
{ 8, "ALL", "Albania Lek" },
{ 12, "DZD", "Algeria Dinar" },
{ 32, "ARS", "Argentina Peso" },
{ 36, "AUD", "Australia Dollar" },
{ 44, "BSD", "Bahamas Dollar" },
{ 48, "BHD", "Bahrain Dinar" },
{ 50, "BDT", "Bangladesh Taka" },
{ 51, "AMD", "Armenia Dram" },
{ 52, "BBD", "Barbados Dollar" },
{ 60, "BMD", "Bermuda Dollar" },
{ 64, "BTN", "Bhutan Ngultrum" },
{ 68, "BOB", "Bolivia Bolíviano" },
{ 72, "BWP", "Botswana Pula" },
{ 84, "BZD", "Belize Dollar" },
{ 90, "SBD", "Solomon Islands Dollar" },
{ 96, "BND", "Brunei Darussalam Dollar" },
{ 104, "MMK", "Myanmar (Burma) Kyat" },
{ 108, "BIF", "Burundi Franc" },
{ 116, "KHR", "Cambodia Riel" },
{ 124, "CAD", "Canada Dollar" },
{ 132, "CVE", "Cape Verde Escudo" },
{ 136, "KYD", "Cayman Islands Dollar" },
{ 144, "LKR", "Sri Lanka Rupee" },
{ 152, "CLP", "Chile Peso" },
{ 156, "CNY", "China Yuan Renminbi" },
{ 170, "COP", "Colombia Peso" },
{ 174, "KMF", "Comorian Franc" },
{ 188, "CRC", "Costa Rica Colon" },
{ 191, "HRK", "Croatia Kuna" },
{ 192, "CUP", "Cuba Peso" },
{ 203, "CZK", "Czech Republic Koruna" },
{ 208, "DKK", "Denmark Krone" },
{ 214, "DOP", "Dominican Republic Peso" },
{ 222, "SVC", "El Salvador Colon" },
{ 230, "ETB", "Ethiopia Birr" },
{ 232, "ERN", "Eritrea Nakfa" },
{ 238, "FKP", "Falkland Islands (Malvinas) Pound" },
{ 242, "FJD", "Fiji Dollar" },
{ 262, "DJF", "Djibouti Franc" },
{ 270, "GMD", "Gambia Dalasi" },
{ 292, "GIP", "Gibraltar Pound" },
{ 320, "GTQ", "Guatemala Quetzal" },
{ 324, "GNF", "Guinea Franc" },
{ 328, "GYD", "Guyana Dollar" },
{ 332, "HTG", "Haiti Gourde" },
{ 340, "HNL", "Honduras Lempira" },
{ 344, "HKD", "Hong Kong Dollar" },
{ 348, "HUF", "Hungary Forint" },
{ 352, "ISK", "Iceland Krona" },
{ 356, "INR", "India Rupee" },
{ 360, "IDR", "Indonesia Rupiah" },
{ 364, "IRR", "Iran Rial" },
{ 368, "IQD", "Iraq Dinar" },
{ 376, "ILS", "Israel Shekel" },
{ 388, "JMD", "Jamaica Dollar" },
{ 392, "JPY", "Japan Yen" },
{ 398, "KZT", "Kazakhstan Tenge" },
{ 400, "JOD", "Jordan Dinar" },
{ 404, "KES", "Kenya Shilling" },
{ 408, "KPW", "Korea (North) Won" },
{ 410, "KRW", "Korea (South) Won" },
{ 414, "KWD", "Kuwait Dinar" },
{ 417, "KGS", "Kyrgyzstan Som" },
{ 418, "LAK", "Laos Kip" },
{ 422, "LBP", "Lebanon Pound" },
{ 426, "LSL", "Lesotho Loti" },
{ 430, "LRD", "Liberia Dollar" },
{ 434, "LYD", "Libya Dinar" },
{ 446, "MOP", "Macau Pataca" },
{ 454, "MWK", "Malawi Kwacha" },
{ 458, "MYR", "Malaysia Ringgit" },
{ 462, "MVR", "Maldives (Maldive Islands) Rufiyaa" },
{ 478, "MRO", "Mauritania Ouguiya" },
{ 480, "MUR", "Mauritius Rupee" },
{ 484, "MXN", "Mexico Peso" },
{ 496, "MNT", "Mongolia Tughrik" },
{ 498, "MDL", "Moldova Leu" },
{ 504, "MAD", "Morocco Dirham" },
{ 512, "OMR", "Oman Rial" },
{ 516, "NAD", "Namibia Dollar" },
{ 524, "NPR", "Nepal Rupee" },
{ 532, "ANG", "Netherlands Antilles Guilder" },
{ 533, "AWG", "Aruba Guilder" },
{ 548, "VUV", "Vanuatu Vatu" },
{ 554, "NZD", "New Zealand Dollar" },
{ 558, "NIO", "Nicaragua Cordoba" },
{ 566, "NGN", "Nigeria Naira" },
{ 578, "NOK", "Norway Krone" },
{ 586, "PKR", "Pakistan Rupee" },
{ 590, "PAB", "Panama Balboa" },
{ 598, "PGK", "Papua New Guinea Kina" },
{ 600, "PYG", "Paraguay Guarani" },
{ 604, "PEN", "Peru Sol" },
{ 608, "PHP", "Philippines Peso" },
{ 634, "QAR", "Qatar Riyal" },
{ 643, "RUB", "Russia Ruble" },
{ 646, "RWF", "Rwanda Franc" },
{ 654, "SHP", "Saint Helena Pound" },
{ 678, "STD", "Sao Tome and Principe dobra" },
{ 682, "SAR", "Saudi Arabia Riyal" },
{ 690, "SCR", "Seychelles Rupee" },
{ 694, "SLL", "Sierra Leone Leone" },
{ 702, "SGD", "Singapore Dollar" },
{ 704, "VND", "Viet Nam Dong" },
{ 706, "SOS", "Somalia Shilling" },
{ 710, "ZAR", "South Africa Rand" },
{ 728, "SSP", "South Sudanese pound" },
{ 748, "SZL", "Swaziland Lilangeni" },
{ 752, "SEK", "Sweden Krona" },
{ 756, "CHF", "Switzerland Franc" },
{ 760, "SYP", "Syria Pound" },
{ 764, "THB", "Thailand Baht" },
{ 776, "TOP", "Tonga Pa‘anga" },
{ 780, "TTD", "Trinidad and Tobago Dollar" },
{ 784, "AED", "United Arab Emirates Dirham" },
{ 788, "TND", "Tunisia Dinar" },
{ 800, "UGX", "Uganda Shilling" },
{ 807, "MKD", "Macedonia Denar" },
{ 818, "EGP", "Egypt Pound" },
{ 826, "GBP", "United Kingdom Pound" },
{ 834, "TZS", "Tanzania Shilling" },
{ 840, "USD", "United States Dollar" },
{ 858, "UYU", "Uruguay Peso" },
{ 860, "UZS", "Uzbekistan Som" },
{ 882, "WST", "Samoa Tala" },
{ 886, "YER", "Yemen Rial" },
{ 901, "TWD", "Taiwan New Dollar" },
{ 931, "CUC", "Cuba Convertible Peso" },
{ 932, "ZWL", "Zimbabwe Dollar" },
{ 933, "BYN", "Belarus Ruble" },
{ 934, "TMT", "Turkmenistan Manat" },
{ 936, "GHS", "Ghana Cedi" },
{ 937, "VEF", "Venezuela Bolívar" },
{ 938, "SDG", "Sudan Pound" },
{ 941, "RSD", "Serbia Dinar" },
{ 943, "MZN", "Mozambique Metical" },
{ 944, "AZN", "Azerbaijan Manat" },
{ 946, "RON", "Romania Leu" },
{ 949, "TRY", "Turkey Lira" },
{ 950, "XAF", "CFA franc BEAC" },
{ 951, "XCD", "East Caribbean Dollar" },
{ 952, "XOF", "CFA franc BCEAO" },
{ 953, "XPF", "CFP franc (franc Pacifique)" },
{ 960, "XDR", "IMF Special Drawing Rights" },
{ 967, "ZMW", "Zambia Kwacha" },
{ 968, "SRD", "Suriname Dollar" },
{ 969, "MGA", "Madagascar Ariary" },
{ 971, "AFN", "Afghanistan Afghani" },
{ 972, "TJS", "Tajikistan Somoni" },
{ 973, "AOA", "Angola Kwanza" },
{ 975, "BGN", "Bulgaria Lev" },
{ 976, "CDF", "Congo/Kinshasa Franc" },
{ 977, "BAM", "Bosnia and Herzegovina Convertible Marka" },
{ 978, "EUR", "Euro" },
{ 980, "UAH", "Ukraine Hryvnia" },
{ 981, "GEL", "Georgia Lari" },
{ 985, "PLN", "Poland Zloty" },
{ 986, "BRL", "Brazil Real" },
{ 0, "---", "Unknown currency" }
};
//------------------------------------------------------------------------------
int findCurrencyIndexByNumCode(uint16_t num_code)
{
int i = 0;
do {
if (iso4217_currency_codes[i].num_code == num_code)
break;
i++;
} while (iso4217_currency_codes[i].num_code != 0);
return i;
}
//------------------------------------------------------------------------------
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/iso4217.h 0000664 0000000 0000000 00000001317 13143103647 0030132 0 ustar 00root root 0000000 0000000 /*
* iso4217.h
*
* Created on: 09.08.2017.
* Author: d-logic
*/
#ifndef ISO4217_H_
#define ISO4217_H_
#include
//==============================================================================
typedef struct iso4217_currency_code_s {
uint16_t num_code;
char *alpha_code;
char *currency;
} iso4217_currency_code_t;
//------------------------------------------------------------------------------
extern iso4217_currency_code_t iso4217_currency_codes[];
//------------------------------------------------------------------------------
int findCurrencyIndexByNumCode(uint16_t num_code);
//==============================================================================
#endif /* ISO4217_H_ */
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/main.c 0000664 0000000 0000000 00000040236 13143103647 0027744 0 ustar 00root root 0000000 0000000 /*
============================================================================
Project Name: uFR APDU Credit Card Reader Example
Name : main.c
Author : d-logic
Version :
Copyright : 2017.
Description : uFR APDU Credit Card Reader Example in C, (C99)
Dependencies: uFR firmware - min. version 3.9.39
uFRCoder library - min. version 4.0.26
============================================================================
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "ini.h"
#include "emv.h"
#include "uFR.h"
#include "utils.h"
//------------------------------------------------------------------------------
#define RAW_RES_MAX_LEN 258
#define MAX_AID_LEN 16
//------------------------------------------------------------------------------
typedef enum E_MENU_ITEMS {
TOP_MENU_LEVEL, APDU_MENU_LEVEL
} menu_levels_t;
menu_levels_t menu_level = TOP_MENU_LEVEL;
//------------------------------------------------------------------------------
void menu(char key);
void usage(void);
UFR_STATUS NewCardInField(uint8_t sak, uint8_t *uid, uint8_t uid_size);
void checkEmvPse(const char *df_name, const char *szTitlePse);
void checkEmvPse1(void);
void checkEmvPse2(void);
void tryEmvPseCardRead(const char *df_name, const char *szTitlePse);
void tryEmvPse1CardRead(void);
void tryEmvPse2CardRead(void);
//------------------------------------------------------------------------------
int main(void) {
char kbd_key;
bool card_in_field = false;
uint8_t old_sak = 0, old_uid_size = 0, old_uid[10];
uint8_t sak, uid_size, uid[10];
UFR_STATUS status;
usage();
printf(" --------------------------------------------------\n");
printf(" Please wait while opening uFR NFC reader.\n");
printf(" --------------------------------------------------\n");
status = ReaderOpen();
if (status != UFR_OK) {
printf(" Error while opening device, status is: 0x%08X\n", status);
getchar();
return EXIT_FAILURE;
}
if (!CheckDependencies()) {
ReaderClose();
getchar();
return EXIT_FAILURE;
}
status = ReaderReset();
if (status != UFR_OK) {
printf(" Error while opening device, status is: 0x%08X\n", status);
getchar();
return EXIT_FAILURE;
}
printf(" --------------------------------------------------\n");
printf(" uFR NFC reader successfully opened.\n");
printf(" --------------------------------------------------\n");
do {
while (!_kbhit()) {
status = GetCardIdEx(&sak, uid, &uid_size);
switch (status) {
case UFR_OK:
if (card_in_field) {
if (old_sak != sak || old_uid_size != uid_size || memcmp(old_uid, uid, uid_size)) {
old_sak = sak;
old_uid_size = uid_size;
memcpy(old_uid, uid, uid_size);
NewCardInField(sak, uid, uid_size);
}
} else {
old_sak = sak;
old_uid_size = uid_size;
memcpy(old_uid, uid, uid_size);
NewCardInField(sak, uid, uid_size);
card_in_field = true;
}
break;
case UFR_NO_CARD:
menu_level = TOP_MENU_LEVEL;
card_in_field = false;
status = UFR_OK;
break;
default:
ReaderClose();
printf(" Fatal error while trying to read card, status is: 0x%08X\n", status);
getchar();
return EXIT_FAILURE;
}
Sleep(500);
}
kbd_key = _getch();
menu(kbd_key);
} while (kbd_key != '\x1b');
ReaderClose();
return EXIT_SUCCESS;
}
//------------------------------------------------------------------------------
void menu(char key) {
switch (key) {
case '1':
if (menu_level == APDU_MENU_LEVEL)
checkEmvPse1();
break;
case '2':
if (menu_level == APDU_MENU_LEVEL)
checkEmvPse2();
break;
case '3':
if (menu_level == APDU_MENU_LEVEL)
tryEmvPse1CardRead();
break;
case '4':
if (menu_level == APDU_MENU_LEVEL)
tryEmvPse2CardRead();
break;
case '\x1b':
break;
default:
usage();
break;
}
}
//------------------------------------------------------------------------------
void usage(void) {
switch (menu_level) {
case APDU_MENU_LEVEL:
printf(" -------------------------------------------------------------------\n");
printf(" ISO14443-4 tag detected:\n");
printf(" -------------------------------------------------------------------\n");
printf(" (1) - Check if the card support Payment System Environment (PSE1)\n"
" (2) - Check if the card support Payment System Environment (PSE2)\n"
" (3) - Read and parse EMV card supporting PSE1\n"
" (4) - Read and parse EMV card supporting PSE2\n");
printf(" -------------------------------------------------------------------\n");
break;
default:
printf(" +------------------------------------------------+\n"
" | APDU usage with uFR example |\n"
" | version "APP_VERSION" |\n"
" +------------------------------------------------+\n");
printf(" When You put ISO14443-4 tag in the reader field,\n"
" You will be prompted for appropriate scenario.\n"
"\n"
" For exit, hit escape.\n");
printf(" --------------------------------------------------\n");
break;
}
}
//------------------------------------------------------------------------------
UFR_STATUS NewCardInField(uint8_t sak, uint8_t *uid, uint8_t uid_size) {
UFR_STATUS status;
uint8_t dl_card_type;
status = GetDlogicCardType(&dl_card_type);
if (status != UFR_OK)
return status;
printf(" \a-------------------------------------------------------------------\n");
printf(" Card type: %s, sak = 0x%02X, uid[%d] = ", GetDlTypeName(dl_card_type), sak, uid_size);
print_hex_ln(uid, uid_size, ":");
printf(" -------------------------------------------------------------------\n");
if (dl_card_type == DL_UNKNOWN_ISO_14443_4) {
menu_level = APDU_MENU_LEVEL;
usage();
} else if (menu_level == APDU_MENU_LEVEL) {
menu_level = TOP_MENU_LEVEL;
}
return UFR_OK;
}
//------------------------------------------------------------------------------
void checkEmvPse(const char *df_name, const char *szTitlePse) {
EMV_STATUS emv_status;
UFR_STATUS status;
emv_tree_node_t *head = NULL, *tail = NULL;
uint8_t r_apdu[RAW_RES_MAX_LEN];
uint32_t Ne; // without SW
uint8_t sw[2];
uint8_t sfi, record, cnt;
uint16_t *sw16_ptr = (uint16_t *) &sw;
emv_tree_node_t *temp = NULL;
printf(" ===================================================================\n");
printf(" Checking if if the card support Payment System Environment (%s) \n", szTitlePse);
printf(" -------------------------------------------------------------------\n");
do {
status = SetISO14443_4_Mode();
if (status != UFR_OK) {
printf(" Error while switching into ISO 14443-4 mode, uFR status is: 0x%08X\n", status);
break;
}
printf(" 1. Issuing \"Select PSE\" command (\"%s\"):\n"
" [C] 00 A4 04 00 ", df_name);
print_hex((const uint8_t *)df_name, strlen(df_name), " ");
printf(" 00\n");
Ne = 256;
status = APDUTransceive(0x00, 0xA4, 0x04, 0x00, (const uint8_t *)df_name, strlen(df_name), r_apdu, &Ne, 1, sw);
if (status != UFR_OK) {
printf(" Error while executing APDU command, uFR status is: 0x%08X\n", status);
break;
} else {
if (*sw16_ptr != 0x90) {
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
printf(" Could not continue execution due to an APDU error.\n");
break;
}
if (Ne) {
printf(" APDU command executed: response data length = %d bytes\n", (int) Ne);
printf(" [R] ");
print_hex_ln(r_apdu, Ne, " ");
}
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
}
emv_status = newEmvTag(&head, r_apdu, Ne, false);
if (emv_status) {
printf(" EMV parsing error code: 0x%08X", emv_status);
break;
}
emv_status = getSfi(head, &sfi);
if (emv_status == EMV_OK) {
// There is SFI:
cnt = 2;
record = 1;
do {
printf("\n %d. Issuing \"Read Record\" command (record = %d, sfi = %d):\n"
" [C] 00 B2 %02X %02X 00\n", cnt, record, sfi, record, (sfi << 3) | 4);
emv_status = emvReadRecord(r_apdu, &Ne, sfi, record, sw);
if (emv_status == EMV_OK) {
emv_status = newEmvTag(&temp, r_apdu, Ne, false);
if (record == 1)
head->next = tail = temp;
else {
tail->next = temp;
tail = tail->next;
}
if (Ne) {
printf(" APDU command executed: response data length = %d bytes\n", (int) Ne);
printf(" [R] ");
print_hex_ln(r_apdu, Ne, " ");
}
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
} else {
if (*sw16_ptr != 0x90) {
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
printf(" There is no records.\n");
}
}
record++;
cnt++;
} while (emv_status == EMV_OK);
}
printf("\n-------------------------------------------------------------------\n");
printEmvBranch(head, 0);
printf(" -------------------------------------------------------------------\n");
printf(" Card support Payment System Environment (%s)\n", szTitlePse);
} while (0);
printf(" ===================================================================\n");
emvTreeCleanup(head);
s_block_deselect(100);
}
//------------------------------------------------------------------------------
void checkEmvPse1(void) {
checkEmvPse("1PAY.SYS.DDF01", "PSE1");
}
//------------------------------------------------------------------------------
void checkEmvPse2(void) {
checkEmvPse("2PAY.SYS.DDF01", "PSE2");
}
//------------------------------------------------------------------------------
void tryEmvPseCardRead(const char *df_name, const char *szTitlePse) {
EMV_STATUS emv_status;
UFR_STATUS status;
bool head_attached = false;
emv_tree_node_t *head = NULL, *tail = NULL;
char *sz_hex_r_apdu;
uint8_t r_apdu[RAW_RES_MAX_LEN];
uint32_t Ne; // without SW
uint8_t sw[2], aid[MAX_AID_LEN];
uint8_t sfi, record, cnt = 1, aid_len;
uint16_t *sw16_ptr = (uint16_t *) &sw;
emv_tree_node_t *temp = NULL;
printf(" ===================================================================\n");
printf(" Read and parse EMV card supporting %s \n", szTitlePse);
printf(" -------------------------------------------------------------------\n");
do {
status = SetISO14443_4_Mode();
if (status != UFR_OK) {
printf(" Error while switching into ISO 14443-4 mode, uFR status is: 0x%08X\n", status);
break;
}
printf(" %d. Issuing \"Select PSE\" command (\"%s\"):\n"
" [C] 00 A4 04 00 %02X ", cnt++, df_name, (unsigned)strlen(df_name));
print_hex((const uint8_t *)df_name, strlen(df_name), " ");
printf(" 00\n");
Ne = 256;
status = APDUTransceive(0x00, 0xA4, 0x04, 0x00, (const uint8_t *)df_name, strlen(df_name), r_apdu, &Ne, 1, sw);
if (status != UFR_OK) {
printf(" Error while executing APDU command, uFR status is: 0x%08X\n", status);
break;
} else {
if (*sw16_ptr != 0x90) {
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
printf(" Could not continue execution due to an APDU error.\n");
break;
}
if (Ne) {
printf(" APDU command executed: response data length = %d bytes\n", (int) Ne);
printf(" [R] ");
print_hex_ln(r_apdu, Ne, " ");
}
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
}
emv_status = newEmvTag(&head, r_apdu, Ne, false);
if (emv_status) {
printf(" EMV parsing error code: 0x%08X", emv_status);
break;
}
emv_status = getSfi(head, &sfi);
if (emv_status == EMV_OK) {
// There is SFI:
record = 1;
do {
printf("\n %d. Issuing \"Read Record\" command (record = %d, sfi = %d):\n"
" [C] 00 B2 %02X %02X 00\n", cnt, record, sfi, record, (sfi << 3) | 4);
emv_status = emvReadRecord(r_apdu, &Ne, sfi, record, sw);
if (emv_status == EMV_OK) {
emv_status = newEmvTag(&temp, r_apdu, Ne, false);
if (!head_attached) {
head->next = tail = temp;
head_attached = true;
} else {
tail->next = temp;
tail = tail->next;
}
if (Ne) {
printf(" APDU command executed: response data length = %d bytes\n", (int) Ne);
printf(" [R] ");
print_hex_ln(r_apdu, Ne, " ");
}
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
} else {
if (*sw16_ptr != 0x90) {
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
printf(" There is no records.\n");
}
}
record++;
cnt++;
} while (emv_status == EMV_OK);
}
emv_status = getAID(head, aid, &aid_len);
if (emv_status == EMV_OK) {
printf("\n %d. Issuing \"Select the application\" command:\n"
" [C] 00 A4 04 00 %02X ", cnt++, aid_len);
print_hex((const uint8_t *)aid, aid_len, " ");
printf(" 00\n");
Ne = 256;
status = APDUTransceive(0x00, 0xA4, 0x04, 0x00, (const uint8_t *)aid, aid_len, r_apdu, &Ne, 1, sw);
if (status != UFR_OK) {
printf(" Error while executing APDU command, uFR status is: 0x%08X\n", status);
break;
} else {
if (*sw16_ptr != 0x90) {
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
printf(" Could not continue execution due to an APDU error.\n");
break;
}
if (Ne) {
printf(" APDU command executed: response data length = %d bytes\n", (int) Ne);
printf(" [R] ");
print_hex_ln(r_apdu, Ne, " ");
}
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
}
emv_status = newEmvTag(&temp, r_apdu, Ne, false);
if (!head_attached) {
head->next = tail = temp;
head_attached = true;
} else {
tail->next = temp;
tail = tail->next;
}
// Ovde se mora, ako postoji PDOL, sračunati dužinu bajtova i to poslati u narednoj komandi.
// Ako PDOL sadrži Terminal Capabilities Tag '9F33' onda po mnogima se mogu poslati sve nule.
// Ako PDOL sadrži Terminal Transaction Qualifiers (TTQ) Tag '9F66' onda tu treba postaviti bar "28 00 00 00"
// da ne bi kartica vratila grešku "69 85" = "Conditions of use not satisfied". Radi i sa
// "20 00 00 00".
// Posle ovoga pronaći Application File Locator (AFL) Tag '94' za dalje parsiranje - "sfi" & "record range".
// Ako ne postoji PDOL, Onda se šalje GPO komanda u formi: "80 A8 00 00 02 83 00 00" nakon koje se očekuje
// da kartica vrati Response Message Template Format 1 Tag '80' {Contains the data objects (without tags and lengths)
// returned by the ICC in response to a command}. U tom slučaju prva dva bajta u okviru vraćene binarne vrednosti
// Taga '80' predstavljaju AIP a ostatak AFL u grupama po 4 bajta koje treba parsirati isto kao Tag '94':
// - prvi bajt je SFI šiftovan 3 bajta levo (za read record cmd samo treba još orovati sa 4)
// - drugi bajt je prvi record tog SFI-a
// - treći bajt je poslednji record tog SFI-a
// - broj zapisa koji učestvuju u "offline data authentication" tog SFI-a počevši od prvog record-a.
printf("\n %d. Issuing \"Get processing options\" command:\n"
" [C] 80 A8 00 00 15 83 13 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n", cnt++);
status = ApduCommand("80 A8 00 00 15 83 13 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", &sz_hex_r_apdu, sw);
if (status != UFR_OK) {
printf(" Error while executing APDU command, uFR status is: 0x%08X\n", status);
break;
} else {
Ne = strlen(sz_hex_r_apdu) / 2;
if (Ne) {
printf(" APDU command executed: response data length = %d bytes\n", (int) Ne);
printf(" [R] %s\n", sz_hex_r_apdu);
}
printf(" [SW] ");
print_hex_ln(sw, 2, " ");
if (*sw16_ptr != 0x90) {
printf(" Could not continue execution due to an APDU error.\n");
} else {
hex2bin(r_apdu, sz_hex_r_apdu);
emv_status = newEmvTag(&temp, r_apdu, Ne, false);
tail->next = temp;
tail = tail->next;
}
}
}
printf("\n-------------------------------------------------------------------\n");
printEmvBranch(head, 0);
} while (0);
printf(" ===================================================================\n");
emvTreeCleanup(head);
s_block_deselect(100);
}
//------------------------------------------------------------------------------
void tryEmvPse1CardRead(void) {
tryEmvPseCardRead("1PAY.SYS.DDF01", "PSE1");
}
//------------------------------------------------------------------------------
void tryEmvPse2CardRead(void) {
tryEmvPseCardRead("2PAY.SYS.DDF01", "PSE2");
}
//------------------------------------------------------------------------------
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/uFR.c 0000664 0000000 0000000 00000011152 13143103647 0027507 0 ustar 00root root 0000000 0000000 /*
* uFR.c
*/
#include
#include
#include
#include
#include
#include
#include
#include "ini.h"
#include "utils.h"
//------------------------------------------------------------------------------
UFR_STATUS ApduCommand(const char *apdu, char **response, uint8_t *sw) {
UFR_STATUS status;
status = APDUHexStrTransceive(apdu, response);
if (status)
return status;
// printf("DEBUG >>> %d\n\n\n", (int)strlen(*response));
if (strlen(*response) % 2)
return UFR_PARAMETERS_ERROR;
if (strlen(*response) >= 4) {
hex2bin(sw, *response + strlen(*response) - 4);
*(*response + strlen(*response) - 4) = '\0';
}
else
return UFR_PARAMETERS_ERROR;
return UFR_OK;
}
//------------------------------------------------------------------------------
bool CheckDependencies(void) {
#if defined(EXIT_ON_WRONG_FW_DEPENDENCY) || defined(EXIT_ON_WRONG_LIB_DEPENDENCY)
uint8_t version_major, version_minor, build;
bool wrong_version = false;
#endif
UFR_STATUS status;
#ifdef EXIT_ON_WRONG_LIB_DEPENDENCY
uint32_t dwDllVersion = 0;
dwDllVersion = GetDllVersion();
// "explode" the dll version:
version_major = LOBYTE(LOWORD(dwDllVersion));
version_minor = HIBYTE(LOWORD(dwDllVersion));
// Get the dll build number.
build = HIWORD(dwDllVersion);
if (version_major < MIN_DEPEND_LIB_VER_MAJOR) {
wrong_version = true;
} else if (version_major == MIN_DEPEND_LIB_VER_MAJOR && version_minor < MIN_DEPEND_LIB_VER_MINOR) {
wrong_version = true;
} else if (version_major == MIN_DEPEND_LIB_VER_MAJOR && version_minor == MIN_DEPEND_LIB_VER_MINOR && build < MIN_DEPEND_LIB_VER_BUILD) {
wrong_version = true;
}
if (wrong_version) {
printf("Wrong uFCoder library version (%d.%d.%d).\n"
"Please update uFCoder library to at last %d.%d.%d version.\n",
version_major, version_minor, build,
MIN_DEPEND_LIB_VER_MAJOR, MIN_DEPEND_LIB_VER_MINOR, MIN_DEPEND_LIB_VER_BUILD);
return false;
}
#endif
#ifdef EXIT_ON_WRONG_FW_DEPENDENCY
wrong_version = false;
status = GetReaderFirmwareVersion(&version_major, &version_minor);
if (status != UFR_OK) {
printf(" Error while checking device version, status is: 0x%08X\n", status);
return false;
}
status = GetBuildNumber(&build);
if (status != UFR_OK) {
printf(" Error while checking device version, status is: 0x%08X\n", status);
return false;
}
if (version_major < MIN_DEPEND_FW_VER_MAJOR) {
wrong_version = true;
} else if (version_major == MIN_DEPEND_FW_VER_MAJOR && version_minor < MIN_DEPEND_FW_VER_MINOR) {
wrong_version = true;
} else if (version_major == MIN_DEPEND_FW_VER_MAJOR && version_minor == MIN_DEPEND_FW_VER_MINOR && build < MIN_DEPEND_FW_VER_BUILD) {
wrong_version = true;
}
if (wrong_version) {
printf("Wrong uFR NFC reader firmware version (%d.%d.%d).\n"
"Please update uFR firmware to at last %d.%d.%d version.\n", version_major, version_minor, build,
MIN_DEPEND_FW_VER_MAJOR, MIN_DEPEND_FW_VER_MINOR, MIN_DEPEND_FW_VER_BUILD);
return false;
}
#endif
return true;
}
//------------------------------------------------------------------------------
const char *GetDlTypeName(uint8_t dl_type_code) {
switch (dl_type_code) {
case DL_MIFARE_ULTRALIGHT:
return "DL_MIFARE_ULTRALIGHT";
case DL_MIFARE_ULTRALIGHT_EV1_11:
return "DL_MIFARE_ULTRALIGHT_EV1_11";
case DL_MIFARE_ULTRALIGHT_EV1_21:
return "DL_MIFARE_ULTRALIGHT_EV1_21";
case DL_MIFARE_ULTRALIGHT_C:
return "DL_MIFARE_ULTRALIGHT_C";
case DL_NTAG_203:
return "DL_NTAG_203";
case DL_NTAG_210:
return "DL_NTAG_210";
case DL_NTAG_212:
return "DL_NTAG_212";
case DL_NTAG_213:
return "DL_NTAG_213";
case DL_NTAG_215:
return "DL_NTAG_215";
case DL_NTAG_216:
return "DL_NTAG_216";
case DL_MIKRON_MIK640D:
return "DL_MIKRON_MIK640D";
case DL_MIFARE_MINI:
return "DL_MIFARE_MINI";
case DL_MIFARE_CLASSIC_1K:
return "DL_MIFARE_CLASSIC_1K";
case DL_MIFARE_CLASSIC_4K:
return "DL_MIFARE_CLASSIC_4K";
case DL_MIFARE_PLUS_S_2K:
return "DL_MIFARE_PLUS_S_2K";
case DL_MIFARE_PLUS_S_4K:
return "DL_MIFARE_PLUS_S_4K";
case DL_MIFARE_PLUS_X_2K:
return "DL_MIFARE_PLUS_X_2K";
case DL_MIFARE_PLUS_X_4K:
return "DL_MIFARE_PLUS_X_4K";
case DL_MIFARE_DESFIRE:
return "DL_MIFARE_DESFIRE";
case DL_MIFARE_DESFIRE_EV1_2K:
return "DL_MIFARE_DESFIRE_EV1_2K";
case DL_MIFARE_DESFIRE_EV1_4K:
return "DL_MIFARE_DESFIRE_EV1_4K";
case DL_MIFARE_DESFIRE_EV1_8K:
return "DL_MIFARE_DESFIRE_EV1_8K";
case DL_UNKNOWN_ISO_14443_4:
return "DL_GENERIC_ISO_14443_4";
case DL_IMEI_UID:
return "DL_IMEI_UID";
}
return "UNSUPPORTED CARD";
}
//------------------------------------------------------------------------------
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/uFR.h 0000664 0000000 0000000 00000000732 13143103647 0027516 0 ustar 00root root 0000000 0000000 /*
* uFR.h
*/
#ifndef UFR_H_
#define UFR_H_
#include "inttypes.h"
#include "stdbool.h"
#include "ini.h"
#define MIN_APDU_HEX_STR_LEN 5
//------------------------------------------------------------------------------
UFR_STATUS ApduCommand(const char *apdu, char **response, uint8_t *sw);
bool CheckDependencies(void);
const char *GetDlTypeName(uint8_t dl_type_code);
//------------------------------------------------------------------------------
#endif /* UFR_H_ */
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/utils.c 0000664 0000000 0000000 00000004625 13143103647 0030162 0 ustar 00root root 0000000 0000000 /*
* utils.c
*/
#include
#include
#include
#include
#include
#include "ini.h"
#include "utils.h"
//------------------------------------------------------------------------------
void print_ln_len(char symbol, uint8_t cnt) {
for (int i = 0; i < cnt; i++)
printf("%c", symbol);
printf("\n");
}
//------------------------------------------------------------------------------
inline void print_ln(char symbol) {
print_ln_len(symbol, DEFAULT_LINE_LEN);
}
//------------------------------------------------------------------------------
void print_hex(const uint8_t *data, uint32_t len, const char *delimiter) {
for (int i = 0; i < len; i++) {
printf("%02X", data[i]);
if ((delimiter != NULL) && (i < (len - 1)))
printf("%c", *delimiter);
}
}
//------------------------------------------------------------------------------
void print_hex_ln(const uint8_t *data, uint32_t len, const char *delimiter) {
print_hex(data, len, delimiter);
printf("\n");
}
//------------------------------------------------------------------------------
int bin_bcd_to_i(const uint8_t *bin, uint32_t len) {
int result = 0, dec = 1;
for (int i = len; i > 0; i--) {
result += (bin[i - 1] & 0x0F) * dec;
dec *= 10;
result += (bin[i - 1] >> 4) * dec;
dec *= 10;
}
return result;
}
//------------------------------------------------------------------------------
bool isByteArrayPrintable(const uint8_t *arr, uint32_t len) {
for (int i = 0; i < len; i++) {
if (!isprint(arr[i])) {
return false;
}
}
return true;
}
//------------------------------------------------------------------------------
size_t hex2bin(uint8_t *dst, const char *src) {
size_t dst_len = 0;
char s_tmp[3];
s_tmp[2] = '\0';
while (*src) {
while (((char)*src < '0' || (char)*src > '9')
&& ((char)*src < 'a' || (char)*src > 'f')
&& ((char)*src < 'A' || (char)*src > 'F'))
src++; // skip delimiters, white spaces, etc.
s_tmp[0] = (char) *src++;
// Must be pair of the hex digits:
if (!(*src))
break;
// And again, must be pair of the hex digits:
if (((char)*src < '0' || (char)*src > '9')
&& ((char)*src < 'a' || (char)*src > 'f')
&& ((char)*src < 'A' || (char)*src > 'F'))
break;
s_tmp[1] = (char) *src++;
*dst++ = strtoul(s_tmp, NULL, 16);
dst_len++;
}
return dst_len;
}
//==============================================================================
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/src/utils.h 0000664 0000000 0000000 00000000777 13143103647 0030173 0 ustar 00root root 0000000 0000000 /*
* utils.h
*/
#ifndef UTILS_H_
#define UTILS_H_
#include
#define DEFAULT_LINE_LEN 60
void print_ln_len(char symbol, uint8_t cnt);
void print_ln(char symbol);
void print_hex(const uint8_t *data, uint32_t len, const char *delimiter);
void print_hex_ln(const uint8_t *data, uint32_t len, const char *delimiter);
int bin_bcd_to_i(const uint8_t *bin, uint32_t len);
bool isByteArrayPrintable(const uint8_t *s, uint32_t len);
size_t hex2bin(uint8_t *dst, const char *src);
#endif /* UTILS_H_ */
ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/win32_debug/ 0000775 0000000 0000000 00000000000 13143103647 0030170 5 ustar 00root root 0000000 0000000 run_me.cmd 0000664 0000000 0000000 00000000114 13143103647 0032057 0 ustar 00root root 0000000 0000000 ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/win32_debug @echo off
set path=..\lib\windows\x86;%path%
ufr-apdu-credit_card_reader.exe ufr-apdu-credit_card_reader.exe 0000664 0000000 0000000 00007452370 13143103647 0036144 0 ustar 00root root 0000000 0000000 ufr-apdu-credit_card_reader-examples-c-594f18ab55688e4c1ad6542e4a342b0d25baef57/win32_debug MZ @ !L!This program cannot be run in DOS mode.
$ PE L ԂY " f @ @ B .text " ` P`.data @
&