emv-card-simulator

Introduction: JavaCard implementation of an EMV card for payment terminal testing
More: Author   ReportBugs   
Tags:

Build and test

JavaCard implementation of an EMV card for payment terminal functional and security testing / fuzzing.

If you need a payment terminal simulator for testing, try emvpt project.

Building

Cloning project

git clone --recurse-submodules https://github.com/mrautio/emv-card-simulator.git

Docker build

If you don't want to install Java8/Gradle(>6), you may use Docker:

docker build -t emvcard-builder -f Dockerfile .

Gradle build

If you have all developer tools existing, or enter to nix-shell, then you can just use Gradle:

gradle build

Private test cards

Card setup APDU files in a git ignored private/cards directory are tested against emvpt with contact and contactless transactions, emvpt settings are in private/config/settings.yaml.

gradle testPrivateCards

Library

lib packages the simulator applets with a host API (emvcardsimulator.api) for embedding the simulator to other applications.

gradle -p lib build
EmvCard card = new EmvCard(EmvCard.PROTOCOL_CONTACTLESS);
card.personalize(ApduScript.bundled("card_setup_ppse_apdus.yaml"));
card.personalize(ApduScript.bundled("card_setup_app_apdus.yaml"));
byte[] response = card.transmit(commandApdu);

A script may describe the card in a card_information entry, it is not sent to the card and the other tools skip it:

- card_information:
    title: 'Test card'
- req: '00 A4 04 00 07 AF FF FF FF FF 12 34'
  res: '90 00'

Applets are installed when a script selects them. The APDU scripts of src/main/rust/config are bundled, and the ones of src/test/java/config with a test/ prefix, e.g. test/card_setup_app_visa_contactless_apdus.yaml.

Fault injection

Each applet has a table of eight faults for terminal fuzzing and fault testing, see src/main/rust/config/setup_fuzzing_apdus.yaml.

SET FAULT    80 11 <entry 00-07> 00 Lc <kind> <INS> <interface> <trigger mode> <n> <kind specific data>   (Lc 00 clears the entry)
RESET        80 07 00 00 00              clear the faults and the fallback READ RECORD of the applet
SEED         80 07 00 01 02 <seed>       card wide seed of the fault random numbers, 0000 uses the card's random generator

A fault applies to a command when its trigger fires. Triggers are evaluated once per command, setup commands and GET RESPONSE are not counted, GET RESPONSE keeps the faults of the command whose response it returns.

Field Values
INS INS of the matching commands, 00 any command
Interface 00 both, 01 contact, 02 contactless
Trigger mode 00 always, 01 randomly 1 in n, 02 once on the nth matching command, 03 every nth matching command
Kind Kind specific data
01 tag value tag (1-3 bytes) || offset || length || strategy || argument. Strategies: 00 random, 01 XOR argument (00 flips one random bit), 02 fill with argument, 03 boundary values 00 01 7F 80 FE FF in turn, 04 increment by the number of firings. The value is extended to offset + length bytes (at most 255) and the tag length is encoded for the mutated value.
02 tag encoding tag (1-3 bytes) || mode || argument 1 || argument 2. Modes: 01 length + signed argument 1, 02 long form length of argument 1 (1-4) bytes, 03 indefinite length 80 (argument 1 not 00 appends 00 00), 04 only the first tag byte announcing a subsequent byte, 05 constructed bit set, 06 argument 1 padding bytes of argument 2 before the tag, 07 omitted, 08 duplicated
03 status word SW1 SW2 || 00 command is not processed and has no response data, 01 command is processed and its response data is sent
04 response chain mode || argument. Modes: 01 GET RESPONSE repeats the same part and 61xx forever, 02 61xx announces argument bytes, 03 6Cxx gives argument as the exact length, 04 last argument bytes of the response are not sent, 05 response is sent in parts of argument bytes with 61xx, also with T=1 and contactless
05 delay number of busy-wait units (2 bytes) before the command is processed, the duration of a unit depends on the card. A real card may send waiting time extensions while busy.

Random values come from the seeded generator when a seed is set, its sequence restarts when the seed is set, when the faults are cleared and at card reset. A tag's random value is the same in all of its serializations of a command, e.g. in the response and the CDA hash. For example, the second GENERATE AC after the fault is set returns 6985 without processing:

80 11 00 00 08 03 AE 00 02 02 69 85 00

Update dependencies

Run the GitHub Actions Workflow.

Deploying to a SmartCard

If you have a SmartCard reader and a Global Platform compliant SmartCard, then you can deploy the application to an actual SmartCard. Common installation issue is to use incorrect JavaCard SDK version, set correct with jc_version.

# Deploy payment selection app to a JavaCard 2 SmartCard 
gradle deployPse -Pjc_version=2.2.2
# Deploy contactless payment selection app (PPSE) to a JavaCard 2 SmartCard
gradle deployPpse -Pjc_version=2.2.2
# Deploy the payment app to a JavaCard 2 SmartCard 
gradle deployPaymentApp -Pjc_version=2.2.2
Apps
About Me
GitHub: Trinea
Facebook: Dev Tools
AI Daily Digest