Do the following on Linux (this is for Ubuntu/Debian – you might need root access):
sudo apt install libpcsclite-dev swig libpcsc-perl pcsc-tools python3-dev libudev-dev python3-pyscard python3-pyserial
If this doesn't work, then get Pyserial
from here
pcsc
related libs:sudo apt install libusb-dev libccid pcscd libpcsclite1
sudo apt install libpcsc-perl pcsc-tools
On Arch Linux, get the following packages (reference the Arch wiki if you need to):
yay -S swig flex libusb ccid pcsclite pcsc-perl pcsc-tools python-pyscard python-pyserial
You may need to start the pcscd
daemon:
systemctl start pcscd.service
See details here.
For Windows drivers you can check here. However, we recommend using Linux, as the instructions below apply for the Linux installation.
Try this with your card in the smartcard reader:
pcsc_scan
This should show you applications on the card. If not, don't worry, we'll do it ourselves below.
Start with files for accessing the card data in this archive.
Create a file named terminal.txt
that will be populated as mentioned below. This file should end with a line containing the string 0000000000
.
After updating this file (see below), we can run the terminal in this manner:
python3 sclink.py --scterminal terminal.txt gg
We shall now first select the main financial application on the card via the general 1PAY.SYS.DDF01
file available on some EMV cards followed by the selection of the Application ID. See EMV Book 1, sections 11.3 and 12 for details.
1PAY.SYS.DDF01
selection method described below, but you may need to use the Application ID list method or some other variant, as explained in the EMV Book 1, chapter 12.
In summary, the main steps are these:
SELECT
command with 1PAY.SYS.DDF01
: 00A404000E315041592E5359532E4444463031
01
, concatenated with the record number encoded in the last 3 bits): (SFI << 3) | REC_NUM
. E.g. If SFI=01
and REC_NUM=1
, we get the Reference Control parameter (P2) 0x0C
for the READ RECORD
command, leading to the READ RECORD
command 00B2010C00
.READ RECORD
commands of the form 00B2010C00
, 00B2020C00
, etc. Check the responses by decoding them with emvlabSELECT
, e.g. 00A4040007XXXXXXXXXXXXXX
(replace the X values based on the Application ID response to the 00B2XXX
command above).
E.g. to get something like 00A4040007A0000000041010
(if the application has 7 bytes – 14 hex characters for the Application ID).
00A4040007A0000000041010
(this must be updated for your card, based on the response to the 00B2XXX
command above).GET PROCESSING OPTS
: 80A80000028300
Now your terminal.txt
file should look something like this (but again, replace the Application ID with the correct one and also use the correct READ RECORD
commands – from your trials).
00A404000E315041592E5359532E4444463031 00B2010C00 00A4040007A0000000041010 80A80000028300 0000000000
As mentioned above, now run this terminal emulator with the following code:
python3 sclink.py --scterminal terminal.txt gg
Your next goal is to be able to read all the application files with READ RECORD
commands (for each file).
In order to find out the present files (which differ from card to card), you need to issue the GET PROCESSING OPTS
command above (80A80000028300
).
In response you should get the Application Interchange Profile (AIP) bytes (2 bytes, coded according to Book 3, Appendix C) followed by a list of Application File Locators (AFL, encoded as explained in Book 3, Section 10.2).
After you decode this (TLV decoder might help), you will find one or more groups of 4 bytes as follows:
SFI << 3
record_number
record_number
88
) where the AIP (2 bytes) and the list of AFLs (each of 4 bytes) are just concatenated, i.e. you have something like 88 <LEN> <AIP> <AFL1> <AFL2> ... <AFLn>
, where n>=1
. Each AFL is encoded as mentioned above.
SFI is like a directory with multiple records that can be read.
To read a file, you need to issue a READ RECORD
command which looks like this:
00B2 <record_number> <SFI || 100>
The <record_number>
is a byte (you need to write a READ RECORD
command for each record_number
).
<SFI || 100>
is a byte which contains the SFI number in the first 5 bits and 100 in the last 3 bits. This is the same as SFI << 3 + 0x04
.
For example, if your AFL shows like 10 01 05 01
, then you might want to read records between 01 and 05 using SFI 01 + 0x04
, i.e. issuing READ RECORD
commands like this:
00 B2 01 14 00
Using the READ RECORD
commands mentioned earlier and the TLV decoder, find the public keys in your card, in particular:
After you get all the public key data, use an INTERNAL AUTHENTICATE
command similar to this: 00880000043085C163
.
See the file trace_emv.txt
for an example of trace as a model for the set of commands you might have to issue (i.e. to add to your terminal.txt
file).
As discussed during the lecture (see als EMV Book 2, section 6), modern EMV cards generally support dynamic signature generation (DDA). This works as follows:
INTERNAL AUTHENTICATE
command with some random data (typically 4 bytes)INTERNAL AUTHENTICATE
command
An example of an INTERNAL AUTHENTICATE
command is the following: 00880000043085C163
. You can look at the file trace_emv.txt
for an example of trace.
terminal.txt
), try using one from here
A short list might be this one:
// EMV.AIDLIST: EMV.AIDLIST = new Array(); EMV.AIDLIST[0] = { aid : "A00000002501", partial : true, name : "AMEX" }; EMV.AIDLIST[1] = { aid : "A0000000031010", partial : false, name : "VISA" }; EMV.AIDLIST[2] = { aid : "A0000000041010", partial : false, name : "MC" };
Check that you obtained a correct DDA signature and a successful 9000
response.
To verify the DDA signature obtained earlier, the terminal must have access to the root CA public keys. You may find some of these available here, here, here, or here.
You will need to know the card type (AMEX, VISA, Mastercard, etc.) and CA public key index, which is given by the ICC (see tag 8F
).
INTERNAL AUTHENTICATE
command)At each step, the verification step includes decryption of the data and checking that the hash over the fields mentioned in Book 2 of EMV matches the hash in the decrypted data.
In short, you need to do the following (see EMV Book 2, sections 6, 6.1, 6.2, 6.3, 6.4 and 6.5)
To recover the data from the issuer public key certificate (same applies to the other signatures), you may also find useful the following notes (which are based on the EMV specs mentioned above, please refer to those).
# Start with a SEQUENCE asn1=SEQUENCE:pubkeyinfo # pubkeyinfo contains an algorithm identifier and the public key wrapped # in a BIT STRING [pubkeyinfo] algorithm=SEQUENCE:rsa_alg pubkey=BITWRAP,SEQUENCE:rsapubkey # algorithm ID for RSA is just an OID and a NULL [rsa_alg] algorithm=OID:rsaEncryption parameter=NULL # Actual public key: modulus and exponent [rsapubkey] n=INTEGER:0x%%MODULUS%% e=INTEGER:0x%%EXPONENT%%
MODULUS
and EXPONENT
part by the modulus and exponent bytes given in the list of public CA root public keys for your card. Say the resulting file is named ca_pk.asn1
.openssl asn1
parser to obtain a public key in DER format as follows:<code> openssl asn1parse -genconf ca_pk.asn1 -out ca_pk.der -noout </code>
issuer_pk.bytes
and then convert this to a binary file as follows:<code> cat issuer_pk.bytes | xxd -r -p > issuer_pk.bin </code>
openssl
as follows:<code> openssl rsautl -verify -in issuer_pk_cert.bin -inkey ca_pk.der -pubin -keyform DER -raw </code>
<code> openssl rsautl -verify -in issuer_pk_cert.bin -inkey ca_pk.der -pubin -keyform DER -raw | xxd -p </code>
To understand the meaning of the decrypted bytes, please refer to the respective EMV documentation (in particular sections 6.2-6.5 in book 2). For example, for the Issuer public key certificate, to obtain the actual issuer public key you need to ignore the first 15 bytes (metadata) as well as the last 21 bytes (hash result and trailer value BC
). The reminder bytes are the first part of the Issuer Public key. For the second part of the Issuer Public key (which you need to concatenate to the first part to get the full public key), please see the card response with tag 92
(Issuer Public Key reminder).
Apply the same/similar process to get the ICC public key and finally to decrypt/verify the DDA signature.
BC
The hash contained in the DDA reponse is computed over the signature bytes (N - 21 bytes) concatenated with the data sent for the DDA signature (typically the 4 random/unpredictable bytes). Hence, if you recompute the hash over the N-21 signature bytes concatenated with the 4 random bytes and this matches the 20 bytes of the hash in the DDA response this should confirm that the 4 random bytes were correctly input into the signature generation.
If you don't manage to get a signature from your card, use these responses from a card (decode them with TLV decode):
Start from the following responses of a card (decode them with TLV decode)
> 00 B2 01 14 8A < 70 81 87 5F 25 03 08 02 01 5F 24 03 12 02 29 5A 08 54 00 49 51 48 65 15 96 5F 34 01 00 9F 07 02 FF 00 8E 14 00 00 00 00 00 00 00 00 42 01 44 03 41 03 42 03 5E 03 1F 03 8C 21 9F 02 06 9F 03 06 9F 1A 02 95 05 5F 2A 02 9A 03 9C 01 9F 37 04 9F 35 01 9F 45 02 9F 4C 08 9F 34 03 8D 0C 91 0A 8A 02 95 05 9F 37 04 9F 4C 08 9F 0D 05 F8 50 AC 08 00 9F 0E 05 00 00 00 00 00 9F 0F 05 F8 70 AC 98 00 5F 28 02 06 42 9F 4A 01 82
> 00 B2 02 14 47 < 70 45 9F 08 02 00 02 57 13 54 00 49 51 48 65 15 96 D1 20 22 01 00 00 08 28 00 00 0F 5F 20 17 43 48 4F 55 44 41 52 59 20 2F 4F 4D 41 52 20 53 41 4C 49 4D 20 44 4C 5F 30 02 02 01 9F 42 02 09 78 9F 44 01 02 8F 01 04
> 00 B2 03 14 96 < 70 81 93 90 81 90 0B 69 37 0D CF E1 E7 B0 9C 00 6F CC 12 91 38 C0 7A 69 80 87 3C 1E 0A 60 04 E6 8E 23 F5 BF B7 51 08 28 00 8B 37 F4 C3 D3 30 6A 0D AE 70 92 51 2F FB B1 E8 1E AE 26 23 1A 0D BF C8 30 B3 1C F1 F6 81 9C F3 12 37 FE 74 B3 5C 5B 57 62 0A 4D C1 96 ED 06 CC 94 45 AC 0A 5B 00 BB 8E BA 7F B4 1D 97 4C A1 F9 DD A4 45 1E B3 2E FC 55 5A 16 9D 60 09 47 4E 97 09 2B 33 21 AD D5 9D 1C 35 30 11 CC C1 C1 D6 19 65 B9 12 0E 07 FC 8F B3 72 4A C0 3A 15
> 00 B2 04 14 CA < 70 81 C7 9F 32 01 03 92 24 EF 2F D9 E8 3B D9 0C 88 A1 A6 58 84 B3 5A 63 69 08 40 36 59 83 1A FB 41 74 3C 61 E5 0F CE 32 49 1C D3 9A 81 93 81 90 86 09 6D 87 91 88 BB 1C 0C 5C C2 3D E0 85 79 96 E8 50 46 9B FF 6A F9 39 C7 3C D6 DE 78 67 75 F3 F7 1E C1 94 B0 05 2E B1 CE C5 2B 02 BD 41 CD 2D BA A5 E0 84 C5 29 00 68 90 17 FD 57 A8 4B 47 BC 8D 33 CD 1E D5 B4 81 87 B1 E0 82 F2 5B 4E F1 32 89 65 5A 2E 66 90 1F 98 96 9D 9E 9C C3 A7 30 D0 84 D5 FA DD 83 EA A7 9B 28 2B 02 E4 AA CB 5C E8 FC AC 77 0A FD EA EB 4B 8E 37 51 AD D8 25 F3 7B 36 DB 5E 45 BE D7 23 3A 50 85 29 8E 98 0B 07 5C 9F 49 03 9F 37 04 9F 47 01 03
> 00 B2 05 14 B4 < 70 81 B1 9F 46 81 90 8A A7 53 01 F7 40 51 03 68 95 94 6E EC CE 31 CF 9E CA A4 5E 77 FF 4F A3 39 B2 BF F9 00 49 15 26 A0 82 1F 5B 42 F5 7A 78 BD F8 4A 5B 6F C6 37 56 1B 1B F5 FB 68 C9 2E 58 C4 31 F1 D6 85 DE 5C F7 C1 9D BF 3A 05 E9 46 DC 6A C7 E6 E7 4B 43 A8 6F C0 FE 1C E9 6F C2 EB 86 F2 05 0B C1 AC 0F 70 1D B0 A9 38 84 2D BD AA F0 2D B7 9B C9 32 D2 0E 62 62 8C C4 01 F4 FA 19 93 36 0B 7C 30 FD A6 6C CF 35 C3 8F FF A1 71 19 4C 58 53 E1 E9 F0 08 59 8B 9F 48 1A F0 62 87 E0 BA F1 0B 92 F5 8E 4A 7A 09 8C 49 EF 3E 38 31 58 F6 FF B3 45 39 85
> 00 88 00 00 04 30 85 C1 63 < [] 61 87 135 > 00 C0 00 00 87 < 77 81 84 9F 4B 81 80 99 0B 9E 27 E7 51 B7 45 5F F8 64 82 3C 82 35 94 CD E0 26 AB 9A D9 1D 02 7F 6E B8 5E DE 27 23 B7 81 40 0D BD 85 FD 20 21 07 08 A3 6C B3 09 51 33 B2 D7 30 BF 12 8B 23 C9 4D 87 3F 28 56 63 1C 19 F5 21 BB BC E2 2F 45 B2 C9 0A 7E B2 F5 C7 02 03 3C B3 AB 1C 06 F5 5A CB 44 3A E0 93 84 42 33 FF 16 D0 CE BB 75 6C E1 39 09 A6 39 5A 89 48 D1 9A BF D8 5E 29 43 0F A0 CC 16 90 7A 5C 92 CA 74 3F
For this card the public key modulus is this (1152 bit):
A6DA428387A502D7DDFB7A74D3F412BE762627197B25435B7A81716A700157DDD06F7CC99D6CA28C2470527E2C03616B9C59217357C2674F583B3BA5C7DCF2838692D023E3562420B4615C439CA97C44DC9A249CFCE7B3BFB22F68228C3AF13329AA4A613CF8DD853502373D62E49AB256D2BC17120E54AEDCED6D96A4287ACC5C04677D4A5A320DB8BEE2F775E5FEC5
And the exponent is 0x03
.
In case of big big trouble, here is the ASN1 file that you should obtain for the Issuer Public Key:
# Start with a SEQUENCE asn1=SEQUENCE:pubkeyinfo # pubkeyinfo contains an algorithm identifier and the public key wrapped # in a BIT STRING [pubkeyinfo] algorithm=SEQUENCE:rsa_alg pubkey=BITWRAP,SEQUENCE:rsapubkey # algorithm ID for RSA is just an OID and a NULL [rsa_alg] algorithm=OID:rsaEncryption parameter=NULL # Actual public key: modulus and exponent [rsapubkey] n=INTEGER:0xcb3a3f60cceccabb300a57d0c7c7fc974a34d8fa4728b9bb4719fec80a41b0cd04eb2c9fdfdd9139f87de2b3cbee69ecdf2889a37888beadc7a5ed5cc51da52940b000ef806ab277d0276386493da941f390f8a1354a3040dc84a7611b0a6e46874efd463a0f0607459ea58eEF2FD9E83BD90C88A1A65884B35A636908403659831AFB41743C61E50FCE32491CD39A81 e=INTEGER:0x3