Emv4 - more additions to hf emv exec
authorOleg Moiseenko <olegmsn@gmail.com>
Sat, 23 Dec 2017 15:46:43 +0000 (17:46 +0200)
committerpwpiwi <pwpiwi@users.noreply.github.com>
Sat, 23 Dec 2017 15:46:43 +0000 (16:46 +0100)
* added rsa polarssl and changed sha1 location to polarssl dir
* deleted old sha1
* added emv-tools pk files
* added polarrssl wrapper sketch to emv_tols
* added test command
* added crypto polarssl with sda test
* added crypto tests and crypto_polarssl sha logic
* added SDA,DDA,fDDA,CDA

42 files changed:
CHANGELOG.md
client/Makefile
client/emv/capk.txt [new file with mode: 0644]
client/emv/cmdemv.c
client/emv/cmdemv.h
client/emv/crypto.c [new file with mode: 0644]
client/emv/crypto.h [new file with mode: 0644]
client/emv/crypto_backend.h [new file with mode: 0644]
client/emv/crypto_polarssl.c [new file with mode: 0644]
client/emv/emv_pk.c [new file with mode: 0644]
client/emv/emv_pk.h [new file with mode: 0644]
client/emv/emv_pki.c [new file with mode: 0644]
client/emv/emv_pki.h [new file with mode: 0644]
client/emv/emv_pki_priv.c [new file with mode: 0644]
client/emv/emv_pki_priv.h [new file with mode: 0644]
client/emv/emv_tags.c
client/emv/emvcore.c
client/emv/emvcore.h
client/emv/test/cda_test.c [new file with mode: 0644]
client/emv/test/cda_test.h [new file with mode: 0644]
client/emv/test/crypto_test.c [new file with mode: 0644]
client/emv/test/crypto_test.h [new file with mode: 0644]
client/emv/test/cryptotest.c [new file with mode: 0644]
client/emv/test/cryptotest.h [new file with mode: 0644]
client/emv/test/dda_test.c [new file with mode: 0644]
client/emv/test/dda_test.h [new file with mode: 0644]
client/emv/test/sda_test.c [new file with mode: 0644]
client/emv/test/sda_test.h [new file with mode: 0644]
client/obj/emv/test/.dummy [new file with mode: 0644]
client/scripting.c
common/polarssl/aes.h
common/polarssl/bignum.c [new file with mode: 0644]
common/polarssl/bignum.h [new file with mode: 0644]
common/polarssl/bn_mul.h [new file with mode: 0644]
common/polarssl/des.c
common/polarssl/polarssl_config.h
common/polarssl/rsa.c [new file with mode: 0644]
common/polarssl/rsa.h [new file with mode: 0644]
common/polarssl/sha1.c [new file with mode: 0644]
common/polarssl/sha1.h [new file with mode: 0644]
common/sha1.c [deleted file]
common/sha1.h [deleted file]

index 644f6c0f7319b02ca4fe10fcef4e76fd8e72b235..4162c638d30e5d196700dda0c3f1dfbeee5effba 100644 (file)
@@ -44,6 +44,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 - Added `hf emv select` - command for select EMV application (Merlok)
 - Added `hf emv exec` - command for execute EMV transaction (Merlok)
 - Added to `hf emv exec` MSD path for VISA and Mastercard and some other compatible EMV cards (Merlok)
+- Added to `hf emv exec` SDA, DDA, fast DDA, CDA calculations for VISA and Mastercard and some other compatible EMV cards (Merlok)
+- Added `hf emv test` - crypto tests for DES, AES, SHA, RSA, SDA, DDA, CDA and some other crypto functions (Merlok)
 
 ## [3.0.1][2017-06-08]
 
index ec593558d83c1598237584222743ac98fa709f74..52a106bd454d9ebe55f08e9d5939ae53cd97f2a1 100644 (file)
@@ -20,7 +20,7 @@ OBJDIR = obj
 LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
 LUALIB = ../liblua/liblua.a
 LDFLAGS = $(ENV_LDFLAGS)
-CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall -g -O3
+CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall -g -O3
 CXXFLAGS = -I../include -Wall -O3
 
 LUAPLATFORM = generic
@@ -88,6 +88,9 @@ CMDSRCS =     crapto1/crapto1.c\
                        crapto1/crypto1.c\
                        polarssl/des.c \
                        polarssl/aes.c\
+                       polarssl/bignum.c\
+                       polarssl/rsa.c\
+                       polarssl/sha1.c\
                        mfkey.c\
                        loclass/cipher.c \
                        loclass/cipherutils.c \
@@ -107,12 +110,22 @@ CMDSRCS =         crapto1/crapto1.c\
                        ui.c \
                        cmddata.c \
                        lfdemod.c \
+                       emv/crypto_polarssl.c\
+                       emv/crypto.c\
+                       emv/emv_pk.c\
+                       emv/emv_pki.c\
+                       emv/emv_pki_priv.c\
+                       emv/test/cryptotest.c\
                        emv/apduinfo.c\
                        emv/dump.c\
                        emv/tlv.c\
                        emv/emv_tags.c\
                        emv/dol.c\
                        emv/emvcore.c\
+                       emv/test/crypto_test.c\
+                       emv/test/sda_test.c\
+                       emv/test/dda_test.c\
+                       emv/test/cda_test.c\
                        emv/cmdemv.c\
                        cmdhf.c \
                        cmdhf14a.c \
@@ -157,7 +170,6 @@ CMDSRCS =   crapto1/crapto1.c\
                        pm3_binlib.c\
                        pm3_bitlib.c\
                        protocols.c\
-                       sha1.c\
                        cmdcrc.c\
                        reveng/reveng.c\
                        reveng/cli.c\
diff --git a/client/emv/capk.txt b/client/emv/capk.txt
new file mode 100644 (file)
index 0000000..0925fba
--- /dev/null
@@ -0,0 +1,32 @@
+a0:00:00:00:03 01 091231 rsa 03 c6:96:03:42:13:d7:d8:54:69:84:57:9d:1d:0f:0e:a5:19:cf:f8:de:ff:c4:29:35:4c:f3:a8:71:a6:f7:18:3f:12:28:da:5c:74:70:c0:55:38:71:00:cb:93:5a:71:2c:4e:28:64:df:5d:64:ba:93:fe:7e:63:e7:1f:25:b1:e5:f5:29:85:75:eb:e1:c6:3a:a6:17:70:69:17:91:1d:c2:a7:5a:c2:8b:25:1c:7e:f4:0f:23:65:91:24:90:b9:39:bc:a2:12:4a:30:a2:8f:54:40:2c:34:ae:ca:33:1a:b6:7e:1e:79:b2:85:dd:57:71:b5:d9:ff:79:ea:63:0b:75 sha1 d3:4a:6a:77:60:11:c7:e7:ce:3a:ec:5f:03:ad:2f:8c:fc:55:03:cc
+a0:00:00:00:03 07 171231 rsa 03 a8:9f:25:a5:6f:a6:da:25:8c:8c:a8:b4:04:27:d9:27:b4:a1:eb:4d:7e:a3:26:bb:b1:2f:97:de:d7:0a:e5:e4:48:0f:c9:c5:e8:a9:72:17:71:10:a1:cc:31:8d:06:d2:f8:f5:c4:84:4a:c5:fa:79:a4:dc:47:0b:b1:1e:d6:35:69:9c:17:08:1b:90:f1:b9:84:f1:2e:92:c1:c5:29:27:6d:8a:f8:ec:7f:28:49:20:97:d8:cd:5b:ec:ea:16:fe:40:88:f6:cf:ab:4a:1b:42:32:8a:1b:99:6f:92:78:b0:b7:e3:31:1c:a5:ef:85:6c:2f:88:84:74:b8:36:12:a8:2e:4e:00:d0:cd:40:69:a6:78:31:40:43:3d:50:72:5f sha1 b4:bc:56:cc:4e:88:32:49:32:cb:c6:43:d6:89:8f:6f:e5:93:b1:72
+a0:00:00:00:03 08 221231 rsa 03 d9:fd:6e:d7:5d:51:d0:e3:06:64:bd:15:70:23:ea:a1:ff:a8:71:e4:da:65:67:2b:86:3d:25:5e:81:e1:37:a5:1d:e4:f7:2b:cc:9e:44:ac:e1:21:27:f8:7e:26:3d:3a:f9:dd:9c:f3:5c:a4:a7:b0:1e:90:70:00:ba:85:d2:49:54:c2:fc:a3:07:48:25:dd:d4:c0:c8:f1:86:cb:02:0f:68:3e:02:f2:de:ad:39:69:13:3f:06:f7:84:51:66:ac:eb:57:ca:0f:c2:60:34:45:46:98:11:d2:93:bf:ef:ba:fa:b5:76:31:b3:dd:91:e7:96:bf:85:0a:25:01:2f:1a:e3:8f:05:aa:5c:4d:6d:03:b1:dc:2e:56:86:12:78:59:38:bb:c9:b3:cd:3a:91:0c:1d:a5:5a:5a:92:18:ac:e0:f7:a2:12:87:75:26:82:f1:58:32:a6:78:d6:e1:ed:0b sha1 20:d2:13:12:69:55:de:20:5a:dc:2f:d2:82:2b:d2:2d:e2:1c:f9:a8
+a0:00:00:00:03 09 221231 rsa 03 9d:91:22:48:de:0a:4e:39:c1:a7:dd:e3:f6:d2:58:89:92:c1:a4:09:5a:fb:d1:82:4d:1b:a7:48:47:f2:bc:49:26:d2:ef:d9:04:b4:b5:49:54:cd:18:9a:54:c5:d1:17:96:54:f8:f9:b0:d2:ab:5f:03:57:eb:64:2f:ed:a9:5d:39:12:c6:57:69:45:fa:b8:97:e7:06:2c:aa:44:a4:aa:06:b8:fe:6e:3d:ba:18:af:6a:e3:73:8e:30:42:9e:e9:be:03:42:7c:9d:64:f6:95:fa:8c:ab:4b:fe:37:68:53:ea:34:ad:1d:76:bf:ca:d1:59:08:c0:77:ff:e6:dc:55:21:ec:ef:5d:27:8a:96:e2:6f:57:35:9f:fa:ed:a1:94:34:b9:37:f1:ad:99:9d:c5:c4:1e:b1:19:35:b4:4c:18:10:0e:85:7f:43:1a:4a:5a:6b:b6:51:14:f1:74:c2:d7:b5:9f:df:23:7d:6b:b1:dd:09:16:e6:44:d7:09:de:d5:64:81:47:7c:75:d9:5c:dd:68:25:46:15:f7:74:0e:c0:7f:33:0a:c5:d6:7b:cd:75:bf:23:d2:8a:14:08:26:c0:26:db:de:97:1a:37:cd:3e:f9:b8:df:64:4a:c3:85:01:05:01:ef:c6:50:9d:7a:41 sha1 1f:f8:0a:40:17:3f:52:d7:d2:7e:0f:26:a1:46:a1:c8:cc:b2:90:46
+a0:00:00:00:03 95 000000 rsa 03 be:9e:1f:a5:e9:a8:03:85:29:99:c4:ab:43:2d:b2:86:00:dc:d9:da:b7:6d:fa:aa:47:35:5a:0f:e3:7b:15:08:ac:6b:f3:88:60:d3:c6:c2:e5:b1:2a:3c:aa:f2:a7:00:5a:72:41:eb:aa:77:71:11:2c:74:cf:9a:06:34:65:2f:bc:a0:e5:98:0c:54:a6:47:61:ea:10:1a:11:4e:0f:0b:55:72:ad:d5:7d:01:0b:7c:9c:88:7e:10:4c:a4:ee:12:72:da:66:d9:97:b9:a9:0b:5a:6d:62:4a:b6:c5:7e:73:c8:f9:19:00:0e:b5:f6:84:89:8e:f8:c3:db:ef:b3:30:c6:26:60:be:d8:8e:a7:8e:90:9a:ff:05:f6:da:62:7b sha1 ee:15:11:ce:c7:10:20:a9:b9:04:43:b3:7b:1d:5f:6e:70:30:30:f6
+a0:00:00:00:03 92 000000 rsa 03 99:6a:f5:6f:56:91:87:d0:92:93:c1:48:10:45:0e:d8:ee:33:57:39:7b:18:a2:45:8e:fa:a9:2d:a3:b6:df:65:14:ec:06:01:95:31:8f:d4:3b:e9:b8:f0:cc:66:9e:3f:84:40:57:cb:dd:f8:bd:a1:91:bb:64:47:3b:c8:dc:9a:73:0d:b8:f6:b4:ed:e3:92:41:86:ff:d9:b8:c7:73:57:89:c2:3a:36:ba:0b:8a:f6:53:72:eb:57:ea:5d:89:e7:d1:4e:9c:7b:6b:55:74:60:f1:08:85:da:16:ac:92:3f:15:af:37:58:f0:f0:3e:bd:3c:5c:2c:94:9c:ba:30:6d:b4:4e:6a:2c:07:6c:5f:67:e2:81:d7:ef:56:78:5d:c4:d7:59:45:e4:91:f0:19:18:80:0a:9e:2d:c6:6f:60:08:05:66:ce:0d:af:8d:17:ea:d4:6a:d8:e3:0a:24:7c:9f sha1 42:9c:95:4a:38:59:ce:f9:12:95:f6:63:c9:63:e5:82:ed:6e:b2:53
+a0:00:00:00:03 94 000000 rsa 03 ac:d2:b1:23:02:ee:64:4f:3f:83:5a:bd:1f:c7:a6:f6:2c:ce:48:ff:ec:62:2a:a8:ef:06:2b:ef:6f:b8:ba:8b:c6:8b:bf:6a:b5:87:0e:ed:57:9b:c3:97:3e:12:13:03:d3:48:41:a7:96:d6:dc:bc:41:db:f9:e5:2c:46:09:79:5c:0c:cf:7e:e8:6f:a1:d5:cb:04:10:71:ed:2c:51:d2:20:2f:63:f1:15:6c:58:a9:2d:38:bc:60:bd:f4:24:e1:77:6e:2b:c9:64:80:78:a0:3b:36:fb:55:43:75:fc:53:d5:7c:73:f5:16:0e:a5:9f:3a:fc:53:98:ec:7b:67:75:8d:65:c9:bf:f7:82:8b:6b:82:d4:be:12:4a:41:6a:b7:30:19:14:31:1e:a4:62:c1:9f:77:1f:31:b3:b5:73:36:00:0d:ff:73:2d:3b:83:de:07:05:2d:73:03:54:d2:97:be:c7:28:71:dc:cf:0e:19:3f:17:1a:ba:27:ee:46:4c:6a:97:69:09:43:d5:9b:da:bb:2a:27:eb:71:ce:eb:da:fa:11:76:04:64:78:fd:62:fe:c4:52:d5:ca:39:32:96:53:0a:a3:f4:19:27:ad:fe:43:4a:2d:f2:ae:30:54:f8:84:06:57:a2:6e:0f:c6:17 sha1 c4:a3:c4:3c:cf:87:32:7d:13:6b:80:41:60:e4:7d:43:b6:0e:6e:0f
+a0:00:00:00:04 03 000000 rsa 03 c2:49:07:47:fe:17:eb:05:84:c8:8d:47:b1:60:27:04:15:0a:dc:88:c5:b9:98:bd:59:ce:04:3e:de:bf:0f:fe:e3:09:3a:c7:95:6a:d3:b6:ad:45:54:c6:de:19:a1:78:d6:da:29:5b:e1:5d:52:20:64:5e:3c:81:31:66:6f:a4:be:5b:84:fe:13:1e:a4:4b:03:93:07:63:8b:9e:74:a8:c4:25:64:f8:92:a6:4d:f1:cb:15:71:2b:73:6e:33:74:f1:bb:b6:81:93:71:60:2d:89:70:e9:7b:90:07:93:c7:c2:a8:9a:4a:16:49:a5:9b:e6:80:57:4d:d0:b6:01:45 sha1 5a:dd:f2:1d:09:27:86:61:14:11:79:cb:ef:f2:72:ea:38:4b:13:bb
+a0:00:00:00:04 04 000000 rsa 03 a6:da:42:83:87:a5:02:d7:dd:fb:7a:74:d3:f4:12:be:76:26:27:19:7b:25:43:5b:7a:81:71:6a:70:01:57:dd:d0:6f:7c:c9:9d:6c:a2:8c:24:70:52:7e:2c:03:61:6b:9c:59:21:73:57:c2:67:4f:58:3b:3b:a5:c7:dc:f2:83:86:92:d0:23:e3:56:24:20:b4:61:5c:43:9c:a9:7c:44:dc:9a:24:9c:fc:e7:b3:bf:b2:2f:68:22:8c:3a:f1:33:29:aa:4a:61:3c:f8:dd:85:35:02:37:3d:62:e4:9a:b2:56:d2:bc:17:12:0e:54:ae:dc:ed:6d:96:a4:28:7a:cc:5c:04:67:7d:4a:5a:32:0d:b8:be:e2:f7:75:e5:fe:c5 sha1 38:1a:03:5d:a5:8b:48:2e:e2:af:75:f4:c3:f2:ca:46:9b:a4:aa:6c
+a0:00:00:00:04 05 000000 rsa 03 b8:04:8a:bc:30:c9:0d:97:63:36:54:3e:3f:d7:09:1c:8f:e4:80:0d:f8:20:ed:55:e7:e9:48:13:ed:00:55:5b:57:3f:ec:a3:d8:4a:f6:13:1a:65:1d:66:cf:f4:28:4f:b1:3b:63:5e:dd:0e:e4:01:76:d8:bf:04:b7:fd:1c:7b:ac:f9:ac:73:27:df:aa:8a:a7:2d:10:db:3b:8e:70:b2:dd:d8:11:cb:41:96:52:5e:a3:86:ac:c3:3c:0d:9d:45:75:91:64:69:c4:e4:f5:3e:8e:1c:91:2c:c6:18:cb:22:dd:e7:c3:56:8e:90:02:2e:6b:ba:77:02:02:e4:52:2a:2d:d6:23:d1:80:e2:15:bd:1d:15:07:fe:3d:c9:0c:a3:10:d2:7b:3e:fc:cd:8f:83:de:30:52:ca:d1:e4:89:38:c6:8d:09:5a:ac:91:b5:f3:7e:28:bb:49:ec:7e:d5:97 sha1 eb:fa:0d:5d:06:d8:ce:70:2d:a3:ea:e8:90:70:1d:45:e2:74:c8:45
+a0:00:00:00:04 06 000000 rsa 03 cb:26:fc:83:0b:43:78:5b:2b:ce:37:c8:1e:d3:34:62:2f:96:22:f4:c8:9a:ae:64:10:46:b2:35:34:33:88:3f:30:7f:b7:c9:74:16:2d:a7:2f:7a:4e:c7:5d:9d:65:73:36:86:5b:8d:30:23:d3:d6:45:66:76:25:c9:a0:7a:6b:7a:13:7c:f0:c6:41:98:ae:38:fc:23:80:06:fb:26:03:f4:1f:4f:3b:b9:da:13:47:27:0f:2f:5d:8c:60:6e:42:09:58:c5:f7:d5:0a:71:de:30:14:2f:70:de:46:88:89:b5:e3:a0:86:95:b9:38:a5:0f:c9:80:39:3a:9c:bc:e4:4a:d2:d6:4f:63:0b:b3:3a:d3:f5:f5:fd:49:5d:31:f3:78:18:c1:d9:40:71:34:2e:07:f1:be:c2:19:4f:60:35:ba:5d:ed:39:36:50:0e:b8:2d:fd:a6:e8:af:b6:55:b1:ef:3d:0d:7e:bf:86:b6:6d:d9:f2:9f:6b:1d:32:4f:e8:b2:6c:e3:8a:b2:01:3d:d1:3f:61:1e:7a:59:4d:67:5c:44:32:35:0e:a2:44:cc:34:f3:87:3c:ba:06:59:29:87:a1:d7:e8:52:ad:c2:2e:f5:a2:ee:28:13:20:31:e4:8f:74:03:7e:3b:34:ab:74:7f sha1 f9:10:a1:50:4d:5f:fb:79:3d:94:f3:b5:00:76:5e:1a:bc:ad:72:d9
+a0:00:00:00:04 00 000000 rsa 03 9c:6b:e5:ad:b1:0b:4b:e3:dc:e2:09:9b:4b:21:06:72:b8:96:56:eb:a0:91:20:4f:61:3e:cc:62:3b:ed:c9:c6:d7:7b:66:0e:8b:ae:ea:7f:7c:e3:0f:1b:15:38:79:a4:e3:64:59:34:3d:1f:e4:7a:cd:bd:41:fc:d7:10:03:0c:2b:a1:d9:46:15:97:98:2c:6e:1b:dd:08:55:4b:72:6f:5e:ff:79:13:ce:59:e7:9e:35:72:95:c3:21:e2:6d:0b:8b:e2:70:a9:44:23:45:c7:53:e2:aa:2a:cf:c9:d3:08:50:60:2f:e6:ca:c0:0c:6d:df:6b:8d:9d:9b:48:79:b2:82:6b:04:2a:07:f0:e5:ae:52:6a:3d:3c:4d:22:c7:2b:9e:aa:52:ee:d8:89:38:66:f8:66:38:7a:c0:5a:13:99 sha1 ec:0a:59:d3:5d:19:f0:31:e9:e8:cb:ec:56:db:80:e2:2b:1d:e1:30
+a0:00:00:00:04 02 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 33:40:8b:96:c8:14:74:2a:d7:35:36:c7:2f:09:26:e4:47:1e:8e:47
+a0:00:00:00:04 05 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 53:d0:49:03:b4:96:f5:95:44:a8:43:09:af:16:92:51:f2:89:68:74
+a0:00:00:00:04 ef 000000 rsa 03 a1:91:cb:87:47:3f:29:34:9b:5d:60:a8:8b:3e:ae:e0:97:3a:a6:f1:a0:82:f3:58:d8:49:fd:df:f9:c0:91:f8:99:ed:a9:79:2c:af:09:ef:28:f5:d2:24:04:b8:8a:22:93:ee:bb:c1:94:9c:43:be:a4:d6:0c:fd:87:9a:15:39:54:4e:09:e0:f0:9f:60:f0:65:b2:bf:2a:13:ec:c7:05:f3:d4:68:b9:d3:3a:e7:7a:d9:d3:f1:9c:a4:0f:23:dc:f5:eb:7c:04:dc:8f:69:eb:a5:65:b1:eb:cb:46:86:cd:27:47:85:53:0f:f6:f6:e9:ee:43:aa:43:fd:b0:2c:e0:0d:ae:c1:5c:7b:8f:d6:a9:b3:94:ba:ba:41:9d:3f:6d:c8:5e:16:56:9b:e8:e7:69:89:68:8e:fe:a2:df:22:ff:7d:35:c0:43:33:8d:ea:a9:82:a0:2b:86:6d:e5:32:85:19:eb:bc:d6:f0:3c:dd:68:66:73:84:7f:84:db:65:1a:b8:6c:28:cf:14:62:56:2c:57:7b:85:35:64:a2:90:c8:55:6d:81:85:31:26:8d:25:cc:98:a4:cc:6a:0b:df:ff:da:2d:cc:a3:a9:4c:99:85:59:e3:07:fd:df:91:50:06:d9:a9:87:b0:7d:da:eb:3b sha1 21:76:6e:bb:0e:e1:22:af:b6:5d:78:45:b7:3d:b4:6b:ab:65:42:7a
+a0:00:00:00:04 f1 000000 rsa 03 a0:dc:f4:bd:e1:9c:35:46:b4:b6:f0:41:4d:17:4d:de:29:4a:ab:bb:82:8c:5a:83:4d:73:aa:e2:7c:99:b0:b0:53:a9:02:78:00:72:39:b6:45:9f:f0:bb:cd:7b:4b:9c:6c:50:ac:02:ce:91:36:8d:a1:bd:21:aa:ea:db:c6:53:47:33:7d:89:b6:8f:5c:99:a0:9d:05:be:02:dd:1f:8c:5b:a2:0e:2f:13:fb:2a:27:c4:1d:3f:85:ca:d5:cf:66:68:e7:58:51:ec:66:ed:bf:98:85:1f:d4:e4:2c:44:c1:d5:9f:59:84:70:3b:27:d5:b9:f2:1b:8f:a0:d9:32:79:fb:bf:69:e0:90:64:29:09:c9:ea:27:f8:98:95:95:41:aa:67:57:f5:f6:24:10:4f:6e:1d:3a:95:32:f2:a6:e5:15:15:ae:ad:1b:43:b3:d7:83:50:88:a2:fa:fa:7b:e7 sha1 d8:e6:8d:a1:67:ab:5a:85:d8:c3:d5:5e:cb:9b:05:17:a1:a5:b4:bb
+a0:00:00:00:04 f3 000000 rsa 03 98:f0:c7:70:f2:38:64:c2:e7:66:df:02:d1:e8:33:df:f4:ff:e9:2d:69:6e:16:42:f0:a8:8c:56:94:c6:47:9d:16:db:15:37:bf:e2:9e:4f:dc:6e:6e:8a:fd:1b:0e:b7:ea:01:24:72:3c:33:31:79:bf:19:e9:3f:10:65:8b:2f:77:6e:82:9e:87:da:ed:a9:c9:4a:8b:33:82:19:9a:35:0c:07:79:77:c9:7a:ff:08:fd:11:31:0a:c9:50:a7:2c:3c:a5:00:2e:f5:13:fc:cc:28:6e:64:6e:3c:53:87:53:5d:50:95:14:b3:b3:26:e1:23:4f:9c:b4:8c:36:dd:d4:4b:41:6d:23:65:40:34:a6:6f:40:3b:a5:11:c5:ef:a3 sha1 a6:9a:c7:60:3d:af:56:6e:97:2d:ed:c2:cb:43:3e:07:e8:b0:1a:9a
+a0:00:00:00:04 f5 000000 rsa 01:00:01 a6:e6:fb:72:17:95:06:f8:60:cc:ca:8c:27:f9:9c:ec:d9:4c:7d:4f:31:91:d3:03:bb:ee:37:48:1c:7a:a1:5f:23:3b:a7:55:e9:e4:37:63:45:a9:a6:7e:79:94:bd:c1:c6:80:bb:35:22:d8:c9:3e:b0:cc:c9:1a:d3:1a:d4:50:da:30:d3:37:66:2d:19:ac:03:e2:b4:ef:5f:6e:c1:82:82:d4:91:e1:97:67:d7:b2:45:42:df:de:ff:6f:62:18:55:03:53:20:69:bb:b3:69:e3:bb:9f:b1:9a:c6:f1:c3:0b:97:d2:49:ee:e7:64:e0:ba:c9:7f:25:c8:73:d9:73:95:3e:51:53:a4:20:64:bb:fa:bf:d0:6a:4b:b4:86:86:0b:f6:63:74:06:c9:fc:36:81:3a:4a:75:f7:5c:31:cc:a9:f6:9f:8d:e5:9a:de:ce:f6:bd:e7:e0:78:00:fc:be:03:5d:31:76:af:84:73:e2:3e:9a:a3:df:ee:22:11:96:d1:14:83:02:67:7c:72:0c:fe:25:44:a0:3d:b5:53:e7:f1:b8:42:7b:a1:cc:72:b0:f2:9b:12:df:ef:4c:08:1d:07:6d:35:3e:71:88:0a:ad:ff:38:63:52:af:0a:b7:b2:8e:d4:9e:1e:67:2d:11:f9 sha1 c2:23:98:04:c8:09:81:70:be:52:d6:d5:d4:15:9e:81:ce:84:66:bf
+a0:00:00:00:04 f6 000000 rsa 03 a2:5a:6b:d7:83:a5:ef:6b:8f:b6:f8:30:55:c2:60:f5:f9:9e:a1:66:78:f3:b9:05:3e:0f:64:98:e8:2c:3f:5d:1e:8c:38:f1:35:88:01:7e:2b:12:b3:d8:ff:6f:50:16:7f:46:44:29:10:72:9e:9e:4d:1b:37:39:e5:06:7c:0a:c7:a1:f4:48:7e:35:f6:75:bc:16:e2:33:31:51:65:cb:14:2b:fd:b2:5e:30:1a:63:2a:54:a3:37:1e:ba:b6:57:2d:ee:ba:f3:70:f3:37:f0:57:ee:73:b4:ae:46:d1:a8:bc:4d:a8:53:ec:3c:c1:2c:8c:bc:2d:a1:83:22:d6:85:30:c7:0b:22:bd:ac:35:1d:d3:60:68:ae:32:1e:11:ab:f2:64:f4:d3:56:9b:b7:12:14:54:50:05:55:8d:e2:60:83:c7:35:db:77:63:68:17:2f:e8:c2:f5:c8:5e:8b:5b:89:0c:c6:82:91:1d:2d:e7:1f:a6:26:b8:81:7f:cc:c0:89:22:b7:03:86:9f:3b:ae:ac:14:59:d7:7c:d8:53:76:bc:36:18:2f:42:38:31:4d:6c:42:12:fb:dd:7f:23:d3 sha1 50:29:09:ed:54:5e:3c:8d:bd:00:ea:58:2d:06:17:fe:e9:f6:f6:84
+a0:00:00:00:04 f7 000000 rsa 01:00:01 94:ea:62:f6:d5:83:20:e3:54:c0:22:ad:dc:f0:55:9d:8c:f2:06:cd:92:e8:69:56:49:05:ce:21:d7:20:f9:71:b7:ae:a3:74:83:0e:be:17:57:11:5a:85:e0:88:d4:1c:6b:77:cf:5e:c8:21:f3:0b:1d:89:04:17:bf:2f:a3:1e:59:08:de:d5:fa:67:7f:8c:7b:18:4a:d0:90:28:fd:de:96:b6:a6:10:98:50:aa:80:01:75:ea:bc:db:bb:68:4a:96:c2:eb:63:79:df:ea:08:d3:2f:e2:33:1f:e1:03:23:3a:d5:8d:cd:b1:e6:e0:77:cb:9f:24:ea:ec:5c:25:af sha1 ee:b0:dd:9b:24:77:be:e3:20:9a:91:4c:db:a9:4c:1c:4a:9b:de:d9
+a0:00:00:00:04 f8 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 f0:6e:cc:6d:2a:ae:bf:25:9b:7e:75:5a:38:d9:a9:b2:4e:2f:f3:dd
+a0:00:00:00:04 f9 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 33:67:12:dc:c2:85:54:80:9c:6a:a9:b0:23:58:de:6f:75:51:64:db
+a0:00:00:00:04 fa 000000 rsa 03 a9:0f:cd:55:aa:2d:5d:99:63:e3:5e:d0:f4:40:17:76:99:83:2f:49:c6:ba:b1:5c:da:e5:79:4b:e9:3f:93:4d:44:62:d5:d1:27:62:e4:8c:38:ba:83:d8:44:5d:ea:a7:41:95:a3:01:a1:02:b2:f1:14:ea:da:0d:18:0e:e5:e7:a5:c7:3e:0c:4e:11:f6:7a:43:dd:ab:5d:55:68:3b:14:74:cc:06:27:f4:4b:8d:30:88:a4:92:ff:aa:da:d4:f4:24:22:d0:e7:01:35:36:c3:c4:9a:d3:d0:fa:e9:64:59:b0:f6:b1:b6:05:65:38:a3:d6:d4:46:40:f9:44:67:b1:08:86:7d:ec:40:fa:ae:cd:74:0c:00:e2:b7:a8:85:2d sha1 5b:ed:40:68:d9:6e:a1:6d:2d:77:e0:3d:60:36:fc:7a:16:0e:a9:9c
+b0:12:34:56:78 00 000000 rsa 03 9c:6b:e5:ad:b1:0b:4b:e3:dc:e2:09:9b:4b:21:06:72:b8:96:56:eb:a0:91:20:4f:61:3e:cc:62:3b:ed:c9:c6:d7:7b:66:0e:8b:ae:ea:7f:7c:e3:0f:1b:15:38:79:a4:e3:64:59:34:3d:1f:e4:7a:cd:bd:41:fc:d7:10:03:0c:2b:a1:d9:46:15:97:98:2c:6e:1b:dd:08:55:4b:72:6f:5e:ff:79:13:ce:59:e7:9e:35:72:95:c3:21:e2:6d:0b:8b:e2:70:a9:44:23:45:c7:53:e2:aa:2a:cf:c9:d3:08:50:60:2f:e6:ca:c0:0c:6d:df:6b:8d:9d:9b:48:79:b2:82:6b:04:2a:07:f0:e5:ae:52:6a:3d:3c:4d:22:c7:2b:9e:aa:52:ee:d8:89:38:66:f8:66:38:7a:c0:5a:13:99 sha1 5d:29:70:e6:46:75:72:7e:60:46:07:65:a8:db:75:34:2a:e1:47:83
+b0:12:34:56:78 02 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 29:4b:e2:02:39:ab:15:24:5a:63:be:a4:6c:c6:c1:75:a2:55:62:d1
+b0:12:34:56:78 05 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 b9:a1:d6:5c:af:e0:6b:05:4e:dd:7e:a8:25:97:ab:85:f1:30:e6:63
+b0:12:34:56:78 f3 000000 rsa 01:00:01 94:ea:62:f6:d5:83:20:e3:54:c0:22:ad:dc:f0:55:9d:8c:f2:06:cd:92:e8:69:56:49:05:ce:21:d7:20:f9:71:b7:ae:a3:74:83:0e:be:17:57:11:5a:85:e0:88:d4:1c:6b:77:cf:5e:c8:21:f3:0b:1d:89:04:17:bf:2f:a3:1e:59:08:de:d5:fa:67:7f:8c:7b:18:4a:d0:90:28:fd:de:96:b6:a6:10:98:50:aa:80:01:75:ea:bc:db:bb:68:4a:96:c2:eb:63:79:df:ea:08:d3:2f:e2:33:1f:e1:03:23:3a:d5:8d:cd:b1:e6:e0:77:cb:9f:24:ea:ec:5c:25:af sha1 56:94:b0:d2:78:48:18:14:a0:5e:12:b5:58:ce:c1:23:48:65:aa:5d
+b0:12:34:56:78 f5 000000 rsa 03 a2:5a:6b:d7:83:a5:ef:6b:8f:b6:f8:30:55:c2:60:f5:f9:9e:a1:66:78:f3:b9:05:3e:0f:64:98:e8:2c:3f:5d:1e:8c:38:f1:35:88:01:7e:2b:12:b3:d8:ff:6f:50:16:7f:46:44:29:10:72:9e:9e:4d:1b:37:39:e5:06:7c:0a:c7:a1:f4:48:7e:35:f6:75:bc:16:e2:33:31:51:65:cb:14:2b:fd:b2:5e:30:1a:63:2a:54:a3:37:1e:ba:b6:57:2d:ee:ba:f3:70:f3:37:f0:57:ee:73:b4:ae:46:d1:a8:bc:4d:a8:53:ec:3c:c1:2c:8c:bc:2d:a1:83:22:d6:85:30:c7:0b:22:bd:ac:35:1d:d3:60:68:ae:32:1e:11:ab:f2:64:f4:d3:56:9b:b7:12:14:54:50:05:55:8d:e2:60:83:c7:35:db:77:63:68:17:2f:e8:c2:f5:c8:5e:8b:5b:89:0c:c6:82:91:1d:2d:e7:1f:a6:26:b8:81:7f:cc:c0:89:22:b7:03:86:9f:3b:ae:ac:14:59:d7:7c:d8:53:76:bc:36:18:2f:42:38:31:4d:6c:42:12:fb:dd:7f:23:d3 sha1 f7:5e:88:02:85:5c:9b:14:02:7e:51:73:45:71:7e:5c:36:35:b9:1b
+b0:12:34:56:78 f6 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 e9:40:6b:65:10:c1:43:ab:1e:9b:9d:79:a3:c1:df:f8:90:9a:34:7c
+b0:12:34:56:78 f7 000000 rsa 03 98:f0:c7:70:f2:38:64:c2:e7:66:df:02:d1:e8:33:df:f4:ff:e9:2d:69:6e:16:42:f0:a8:8c:56:94:c6:47:9d:16:db:15:37:bf:e2:9e:4f:dc:6e:6e:8a:fd:1b:0e:b7:ea:01:24:72:3c:33:31:79:bf:19:e9:3f:10:65:8b:2f:77:6e:82:9e:87:da:ed:a9:c9:4a:8b:33:82:19:9a:35:0c:07:79:77:c9:7a:ff:08:fd:11:31:0a:c9:50:a7:2c:3c:a5:00:2e:f5:13:fc:cc:28:6e:64:6e:3c:53:87:53:5d:50:95:14:b3:b3:26:e1:23:4f:9c:b4:8c:36:dd:d4:4b:41:6d:23:65:40:34:a6:6f:40:3b:a5:11:c5:ef:a3 sha1 f7:81:13:e8:60:f0:30:a8:72:92:3f:ce:93:e3:38:1c:77:a4:2a:30
+b0:12:34:56:78 f8 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 66:46:9c:88:e7:dc:11:15:29:c7:d3:79:d7:93:8c:8d:f3:e4:c2:5e
+b0:12:34:56:78 f9 000000 rsa 01:00:01 a6:e6:fb:72:17:95:06:f8:60:cc:ca:8c:27:f9:9c:ec:d9:4c:7d:4f:31:91:d3:03:bb:ee:37:48:1c:7a:a1:5f:23:3b:a7:55:e9:e4:37:63:45:a9:a6:7e:79:94:bd:c1:c6:80:bb:35:22:d8:c9:3e:b0:cc:c9:1a:d3:1a:d4:50:da:30:d3:37:66:2d:19:ac:03:e2:b4:ef:5f:6e:c1:82:82:d4:91:e1:97:67:d7:b2:45:42:df:de:ff:6f:62:18:55:03:53:20:69:bb:b3:69:e3:bb:9f:b1:9a:c6:f1:c3:0b:97:d2:49:ee:e7:64:e0:ba:c9:7f:25:c8:73:d9:73:95:3e:51:53:a4:20:64:bb:fa:bf:d0:6a:4b:b4:86:86:0b:f6:63:74:06:c9:fc:36:81:3a:4a:75:f7:5c:31:cc:a9:f6:9f:8d:e5:9a:de:ce:f6:bd:e7:e0:78:00:fc:be:03:5d:31:76:af:84:73:e2:3e:9a:a3:df:ee:22:11:96:d1:14:83:02:67:7c:72:0c:fe:25:44:a0:3d:b5:53:e7:f1:b8:42:7b:a1:cc:72:b0:f2:9b:12:df:ef:4c:08:1d:07:6d:35:3e:71:88:0a:ad:ff:38:63:52:af:0a:b7:b2:8e:d4:9e:1e:67:2d:11:f9 sha1 ae:ac:a4:54:80:c8:83:4c:b0:be:bd:cc:57:0b:7b:2b:74:bb:4b:79
index 92ae01f944c88a2fabcec2d35c361941e1d7fe04..42c8524aaaa897e80df91033e6b3dda6811060d0 100644 (file)
@@ -9,6 +9,7 @@
 //-----------------------------------------------------------------------------
 
 #include "cmdemv.h"
+#include "test/cryptotest.h"
 
 int UsageCmdHFEMVSelect(void) {
        PrintAndLog("HELP :  Executes select applet command:\n");
@@ -277,7 +278,7 @@ int CmdHFEMVPPSE(const char *cmd) {
 
 int UsageCmdHFEMVExec(void) {
        PrintAndLog("HELP :  Executes EMV contactless transaction:\n");
-       PrintAndLog("Usage:  hf emv exec [-s][-a][-t]\n");
+       PrintAndLog("Usage:  hf emv exec [-s][-a][-t][-f][-v][-c][-x][-g]\n");
        PrintAndLog("  Options:");
        PrintAndLog("  -s       : select card");
        PrintAndLog("  -a       : show APDU reqests and responses\n");
@@ -286,14 +287,16 @@ int UsageCmdHFEMVExec(void) {
        PrintAndLog("  -v       : transaction type - qVSDC or M/Chip.\n");
        PrintAndLog("  -c       : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
        PrintAndLog("  -x       : transaction type - VSDC. For test only. Not a standart behavior.\n");
+       PrintAndLog("  -g       : VISA. generate AC from GPO\n");
        PrintAndLog("By default : transaction type - MSD.\n");
        PrintAndLog("Samples:");
-       PrintAndLog(" hf emv pse -s -> select card");
-       PrintAndLog(" hf emv pse -s -t -a -> select card, show responses in TLV, show APDU");
+       PrintAndLog(" hf emv exec -s -a -t -> execute MSD transaction");
+       PrintAndLog(" hf emv exec -s -a -t -c -> execute CDA transaction");
        return 0;
 }
 
 #define TLV_ADD(tag, value)( tlvdb_add(tlvRoot, tlvdb_fixed(tag, sizeof(value) - 1, (const unsigned char *)value)) )
+#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;}
 
 int CmdHFEMVExec(const char *cmd) {
        bool activateField = false;
@@ -301,15 +304,22 @@ int CmdHFEMVExec(const char *cmd) {
        bool decodeTLV = false;
        bool forceSearch = false;
        enum TransactionType TrType = TT_MSD;
+       bool GenACGPO = false;
 
        uint8_t buf[APDU_RES_LEN] = {0};
        size_t len = 0;
        uint16_t sw = 0;
        uint8_t AID[APDU_AID_LEN] = {0};
        size_t AIDlen = 0;
+       uint8_t ODAiList[4096];
+       size_t ODAiListLen = 0;
        
        int res;
        
+       struct tlvdb *tlvSelect = NULL;
+       struct tlvdb *tlvRoot = NULL;
+       struct tlv *pdol_data_tlv = NULL;
+
        if (strlen(cmd) < 1) {
                UsageCmdHFEMVExec();
                return 0;
@@ -352,6 +362,10 @@ int CmdHFEMVExec(const char *cmd) {
                                case 'C':
                                        TrType = TT_CDA;
                                        break;
+                               case 'g':
+                               case 'G':
+                                       GenACGPO = true;
+                                       break;
                                default:
                                        PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
                                        return 1;
@@ -361,7 +375,6 @@ int CmdHFEMVExec(const char *cmd) {
 
        
        // init applets list tree
-       struct tlvdb *tlvSelect = NULL;
        const char *al = "Applets list";
        tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
 
@@ -385,8 +398,7 @@ int CmdHFEMVExec(const char *cmd) {
                PrintAndLog("\n* Search AID in list.");
                SetAPDULogging(false);
                if (EMVSearch(activateField, true, decodeTLV, tlvSelect)) {
-                       tlvdb_free(tlvSelect);
-                       return 2;
+                       dreturn(2);
                }
 
                // check search and select application id
@@ -395,14 +407,13 @@ int CmdHFEMVExec(const char *cmd) {
        }
        
        // Init TLV tree
-       struct tlvdb *tlvRoot = NULL;
        const char *alr = "Root terminal TLV tree";
        tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
        
        // check if we found EMV application on card
        if (!AIDlen) {
                PrintAndLog("Can't select AID. EMV AID not found");
-               return 2;
+               dreturn(2);
        }
        
        // Select
@@ -412,7 +423,7 @@ int CmdHFEMVExec(const char *cmd) {
        
        if (res) {      
                PrintAndLog("Can't select AID (%d). Exit...", res);
-               return 3;
+               dreturn(3);
        }
        
        if (decodeTLV)
@@ -422,25 +433,30 @@ int CmdHFEMVExec(const char *cmd) {
        PrintAndLog("\n* Init transaction parameters.");
 
     //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
+       char *qVSDC = "\x26\x00\x00\x00";
+       if (GenACGPO) {
+               qVSDC = "\x26\x80\x00\x00";
+       }
        switch(TrType) {
                case TT_MSD:
                        TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
                        break;
-               // not standart for contactless. just for test.
+               // not standard for contactless. just for test.
                case TT_VSDC:  
                        TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
                        break;
                case TT_QVSDCMCHIP:
-                       TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
+                       TLV_ADD(0x9F66, qVSDC); // qVSDC
                        break;
                case TT_CDA:
-                       TLV_ADD(0x9F66, "\x86\x80\x00\x00"); // CDA
+                       TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled)
                        break;
                default:
                        TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
                        break;
        }
-    //9F02:(Amount, Authorised (Numeric)) len:6
+       
+    //9F02:(Amount, authorized (Numeric)) len:6
        TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
     //9F1A:(Terminal Country Code) len:2
        TLV_ADD(0x9F1A, "ru");
@@ -459,17 +475,17 @@ int CmdHFEMVExec(const char *cmd) {
        TLVPrintFromTLV(tlvRoot); // TODO delete!!!
        
        PrintAndLog("\n* Calc PDOL.");
-       struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
+       pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
        if (!pdol_data_tlv){
                PrintAndLog("ERROR: can't create PDOL TLV.");
-               return 4;
+               dreturn(4);
        }
        
        size_t pdol_data_tlv_data_len;
        unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
        if (!pdol_data_tlv_data) {
                PrintAndLog("ERROR: can't create PDOL data.");
-               return 4;
+               dreturn(4);
        }
        PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
 
@@ -477,11 +493,11 @@ int CmdHFEMVExec(const char *cmd) {
        res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
        
        free(pdol_data_tlv_data);
-       free(pdol_data_tlv);
+       //free(pdol_data_tlv); --- free on exit.
        
        if (res) {      
                PrintAndLog("GPO error(%d): %4x. Exit...", res, sw);
-               return 5;
+               dreturn(5);
        }
 
        // process response template format 1 [id:80  2b AIP + x4b AFL] and format 2 [id:77 TLV]
@@ -567,9 +583,23 @@ int CmdHFEMVExec(const char *cmd) {
                                        PrintAndLog("");
                                }
                                
+                               // Build Input list for Offline Data Authentication
+                               // EMV 4.3 book3 10.3, page 96
                                if (SFIoffline) {
-                                       // here will be offline records storing...
-                                       // dont foget: if (sfi < 11)
+                                       if (SFI < 11) {
+                                               const unsigned char *abuf = buf;
+                                               size_t elmlen = len;
+                                               struct tlv e;
+                                               if (tlv_parse_tl(&abuf, &elmlen, &e)) {
+                                                       memcpy(&ODAiList[ODAiListLen], &buf[len - elmlen], elmlen);
+                                                       ODAiListLen += elmlen;
+                                               } else {
+                                                       PrintAndLog("ERROR SFI[%02x]. Creating input list for Offline Data Authentication error.", SFI);
+                                               }
+                                       } else {
+                                               memcpy(&ODAiList[ODAiListLen], buf, len);
+                                               ODAiListLen += len;
+                                       }
                                }
                        }
                }
@@ -577,6 +607,13 @@ int CmdHFEMVExec(const char *cmd) {
                break;
        }       
        
+       // copy Input list for Offline Data Authentication
+       if (ODAiListLen) {
+               struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag
+               tlvdb_add(tlvRoot, oda); 
+               PrintAndLog("* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen);
+       }
+       
        // get AIP
        const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);      
        uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
@@ -585,13 +622,13 @@ int CmdHFEMVExec(const char *cmd) {
        // SDA
        if (AIP & 0x0040) {
                PrintAndLog("\n* SDA");
-               trSDA(AID, AIDlen, tlvRoot);
+               trSDA(tlvRoot);
        }
 
        // DDA
        if (AIP & 0x0020) {
                PrintAndLog("\n* DDA");
-               
+               trDDA(decodeTLV, tlvRoot);
        }       
        
        // transaction check
@@ -644,11 +681,11 @@ int CmdHFEMVExec(const char *cmd) {
                        res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot);
                        if (res) {
                                PrintAndLog("ERROR GetChallenge. APDU error %4x", sw);
-                               return 5;
+                               dreturn(6);
                        }
                        if (len < 4) {
                                PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len);
-                               return 5;
+                               dreturn(6);
                        }
                        
                        // ICC Dynamic Number
@@ -663,7 +700,7 @@ int CmdHFEMVExec(const char *cmd) {
                        struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
                        if (!cdol_data_tlv){
                                PrintAndLog("ERROR: can't create CDOL1 TLV.");
-                               return 4;
+                               dreturn(6);
                        }
                        PrintAndLog("CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
                        
@@ -671,17 +708,25 @@ int CmdHFEMVExec(const char *cmd) {
                        // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
                        res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
                        
-                       free(cdol_data_tlv);
-                       
                        if (res) {      
                                PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
-                               return 5;
+                               dreturn(7);
                        }
                        
                        if (decodeTLV)
                                TLVPrintFromBuffer(buf, len);
                        
-                       PrintAndLog("* M/Chip transaction result:");
+                       // CDA
+                       PrintAndLog("\n* CDA:");
+                       struct tlvdb *ac_tlv = tlvdb_parse_multi(buf, len);
+                       res = trCDA(tlvRoot, ac_tlv, pdol_data_tlv, cdol_data_tlv);
+                       if (res) {      
+                               PrintAndLog("CDA error (%d)", res);
+                       }
+                       free(ac_tlv);
+                       free(cdol_data_tlv);
+                       
+                       PrintAndLog("\n* M/Chip transaction result:");
                        // 9F27: Cryptogram Information Data (CID)
                        const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL);
                        if (CID) {
@@ -743,7 +788,7 @@ int CmdHFEMVExec(const char *cmd) {
                                struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
                                if (!udol_data_tlv){
                                        PrintAndLog("ERROR: can't create UDOL TLV.");
-                                       return 4;
+                                       dreturn(8);
                                }
 
                                PrintAndLog("UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len));
@@ -753,24 +798,27 @@ int CmdHFEMVExec(const char *cmd) {
                                res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
                                if (res) {
                                        PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw);
-                                       return 5;
+                                       free(udol_data_tlv);
+                                       dreturn(9);
                                }
                                
                                if (decodeTLV) {
                                        TLVPrintFromBuffer(buf, len);
                                        PrintAndLog("");
                                }
+                               free(udol_data_tlv);
 
                        }
                } else {
                        PrintAndLog("ERROR MSD: Track2 data not found.");
                }
        }
-       
+
        // DropField
        DropField();
        
        // Destroy TLV's
+       free(pdol_data_tlv);
        tlvdb_free(tlvSelect);
        tlvdb_free(tlvRoot);
 
@@ -779,6 +827,10 @@ int CmdHFEMVExec(const char *cmd) {
        return 0;
 }
 
+int CmdHFEMVTest(const char *cmd) {
+       return ExecuteCryptoTests(true);
+}
+
 int CmdHelp(const char *Cmd);
 static command_t CommandTable[] =  {
        {"help",        CmdHelp,                1,      "This help"},
@@ -786,6 +838,7 @@ static command_t CommandTable[] =  {
        {"pse",         CmdHFEMVPPSE,   0,      "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."},
        {"search",      CmdHFEMVSearch, 0,      "Try to select all applets from applets list and print installed applets."},
        {"select",      CmdHFEMVSelect, 0,      "Select applet."},
+       {"test",        CmdHFEMVTest,   0,      "Crypto logic test."},
        {NULL, NULL, 0, NULL}
 };
 
index 78796efab65d4ba5b231a022316675a6636e2f98..b3f76508a85e9ef1ea8c7dc3ab324a8550f1276c 100644 (file)
@@ -15,6 +15,7 @@
 #include <stdlib.h>
 #include <inttypes.h>
 #include <string.h>
+#include <ctype.h>
 #include "proxmark3.h"
 #include "ui.h"
 #include "cmdparser.h"
diff --git a/client/emv/crypto.c b/client/emv/crypto.c
new file mode 100644 (file)
index 0000000..c8ced6d
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "crypto.h"
+#include "crypto_backend.h"
+
+#include <string.h>
+
+static struct crypto_backend *crypto_backend;
+
+static bool crypto_init(void)
+{
+       if (crypto_backend)
+               return true;
+
+       crypto_backend = crypto_polarssl_init(); 
+
+       if (!crypto_backend)
+               return false;
+
+       return true;
+}
+
+struct crypto_hash *crypto_hash_open(enum crypto_algo_hash hash)
+{
+       struct crypto_hash *ch;
+
+       if (!crypto_init())
+               return NULL;
+
+       ch = crypto_backend->hash_open(hash);
+       if (ch)
+               ch->algo = hash;
+
+       return ch;
+}
+
+void crypto_hash_close(struct crypto_hash *ch)
+{
+       ch->close(ch);
+}
+
+void crypto_hash_write(struct crypto_hash *ch, const unsigned char *buf, size_t len)
+{
+       ch->write(ch, buf, len);
+}
+
+unsigned char *crypto_hash_read(struct crypto_hash *ch)
+{
+       return ch->read(ch);
+}
+
+size_t crypto_hash_get_size(const struct crypto_hash *ch)
+{
+       return ch->get_size(ch);
+}
+
+struct crypto_pk *crypto_pk_open(enum crypto_algo_pk pk, ...)
+{
+       struct crypto_pk *cp;
+       va_list vl;
+
+       if (!crypto_init())
+               return NULL;
+
+       va_start(vl, pk);
+       cp = crypto_backend->pk_open(pk, vl);
+       va_end(vl);
+
+       if (cp)
+               cp->algo = pk;
+
+       return cp;
+}
+
+struct crypto_pk *crypto_pk_open_priv(enum crypto_algo_pk pk, ...)
+{
+       struct crypto_pk *cp;
+       va_list vl;
+
+       if (!crypto_init())
+               return NULL;
+
+       if (!crypto_backend->pk_open_priv)
+               return NULL;
+
+       va_start(vl, pk);
+       cp = crypto_backend->pk_open_priv(pk, vl);
+       va_end(vl);
+
+       if (cp)
+               cp->algo = pk;
+
+       return cp;
+}
+
+struct crypto_pk *crypto_pk_genkey(enum crypto_algo_pk pk, ...)
+{
+       struct crypto_pk *cp;
+       va_list vl;
+
+       if (!crypto_init())
+               return NULL;
+
+       if (!crypto_backend->pk_genkey)
+               return NULL;
+
+       va_start(vl, pk);
+       cp = crypto_backend->pk_genkey(pk, vl);
+       va_end(vl);
+
+       if (cp)
+               cp->algo = pk;
+
+       return cp;
+}
+
+void crypto_pk_close(struct crypto_pk *cp)
+{
+       cp->close(cp);
+}
+
+unsigned char *crypto_pk_encrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen)
+{
+       return cp->encrypt(cp, buf, len, clen);
+}
+
+unsigned char *crypto_pk_decrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen)
+{
+       if (!cp->decrypt) {
+               *clen = 0;
+
+               return NULL;
+       }
+
+       return cp->decrypt(cp, buf, len, clen);
+}
+
+enum crypto_algo_pk crypto_pk_get_algo(const struct crypto_pk *cp)
+{
+       if (!cp)
+               return PK_INVALID;
+
+       return cp->algo;
+}
+
+size_t crypto_pk_get_nbits(const struct crypto_pk *cp)
+{
+       if (!cp->get_nbits)
+               return 0;
+
+       return cp->get_nbits(cp);
+}
+
+unsigned char *crypto_pk_get_parameter(const struct crypto_pk *cp, unsigned param, size_t *plen)
+{
+       *plen = 0;
+
+       if (!cp->get_parameter)
+               return NULL;
+
+       return cp->get_parameter(cp, param, plen);
+}
diff --git a/client/emv/crypto.h b/client/emv/crypto.h
new file mode 100644 (file)
index 0000000..940e8b2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+enum crypto_algo_hash {
+       HASH_INVALID,
+       HASH_SHA_1,
+};
+
+struct crypto_hash *crypto_hash_open(enum crypto_algo_hash hash);
+void crypto_hash_close(struct crypto_hash *ch);
+void crypto_hash_write(struct crypto_hash *ch, const unsigned char *buf, size_t len);
+unsigned char *crypto_hash_read(struct crypto_hash *ch);
+size_t crypto_hash_get_size(const struct crypto_hash *ch);
+
+enum crypto_algo_pk {
+       PK_INVALID,
+       PK_RSA,
+};
+
+struct crypto_pk *crypto_pk_open(enum crypto_algo_pk pk, ...);
+struct crypto_pk *crypto_pk_open_priv(enum crypto_algo_pk pk, ...);
+struct crypto_pk *crypto_pk_genkey(enum crypto_algo_pk pk, ...);
+void crypto_pk_close(struct crypto_pk *cp);
+unsigned char *crypto_pk_encrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
+unsigned char *crypto_pk_decrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
+enum crypto_algo_pk crypto_pk_get_algo(const struct crypto_pk *cp);
+size_t crypto_pk_get_nbits(const struct crypto_pk *cp);
+unsigned char *crypto_pk_get_parameter(const struct crypto_pk *cp, unsigned param, size_t *plen);
+
+#endif
diff --git a/client/emv/crypto_backend.h b/client/emv/crypto_backend.h
new file mode 100644 (file)
index 0000000..a815ae1
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef CRYPTO_BACKEND_H
+#define CRYPTO_BACKEND_H
+
+#include "crypto.h"
+
+#include <stddef.h>
+#include <stdarg.h>
+
+struct crypto_hash {
+       enum crypto_algo_hash algo;
+       void (*write)(struct crypto_hash *ch, const unsigned char *buf, size_t len);
+       unsigned char *(*read)(struct crypto_hash *ch);
+       void (*close)(struct crypto_hash *ch);
+       size_t (*get_size)(const struct crypto_hash *ch);
+};
+
+struct crypto_pk {
+       enum crypto_algo_pk algo;
+       unsigned char *(*encrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
+       unsigned char *(*decrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
+       unsigned char *(*get_parameter)(const struct crypto_pk *cp, unsigned param, size_t *plen);
+       size_t (*get_nbits)(const struct crypto_pk *cp);
+       void (*close)(struct crypto_pk *cp);
+};
+
+struct crypto_backend {
+       struct crypto_hash *(*hash_open)(enum crypto_algo_hash hash);
+       struct crypto_pk *(*pk_open)(enum crypto_algo_pk pk, va_list vl);
+       struct crypto_pk *(*pk_open_priv)(enum crypto_algo_pk pk, va_list vl);
+       struct crypto_pk *(*pk_genkey)(enum crypto_algo_pk pk, va_list vl);
+};
+
+struct crypto_backend *crypto_polarssl_init(void);
+
+#endif
diff --git a/client/emv/crypto_polarssl.c b/client/emv/crypto_polarssl.c
new file mode 100644 (file)
index 0000000..760395c
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ * Copyright (C) 2017 Merlok
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "crypto.h"
+#include "crypto_backend.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rsa.h"
+#include "sha1.h"
+
+struct crypto_hash_polarssl {
+       struct crypto_hash ch;
+       sha1_context ctx;
+};
+
+static void crypto_hash_polarssl_close(struct crypto_hash *_ch)
+{
+       struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
+
+       free(ch);
+}
+
+static void crypto_hash_polarssl_write(struct crypto_hash *_ch, const unsigned char *buf, size_t len)
+{
+       struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
+
+       sha1_update(&(ch->ctx), buf, len);
+}
+
+static unsigned char *crypto_hash_polarssl_read(struct crypto_hash *_ch)
+{
+       struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
+
+       static unsigned char sha1sum[20];
+       sha1_finish(&(ch->ctx), sha1sum);
+       return sha1sum;
+}
+
+static size_t crypto_hash_polarssl_get_size(const struct crypto_hash *ch)
+{
+       if (ch->algo == HASH_SHA_1)
+               return 20;
+       else
+               return 0;
+}
+
+static struct crypto_hash *crypto_hash_polarssl_open(enum crypto_algo_hash hash)
+{
+       if (hash != HASH_SHA_1)
+               return NULL;
+
+       struct crypto_hash_polarssl *ch = malloc(sizeof(*ch));
+
+       sha1_starts(&(ch->ctx));
+
+       ch->ch.write = crypto_hash_polarssl_write;
+       ch->ch.read = crypto_hash_polarssl_read;
+       ch->ch.close = crypto_hash_polarssl_close;
+       ch->ch.get_size = crypto_hash_polarssl_get_size;
+
+       return &ch->ch;
+}
+
+struct crypto_pk_polarssl {
+       struct crypto_pk cp;
+       rsa_context ctx;
+};
+
+static struct crypto_pk *crypto_pk_polarssl_open_rsa(va_list vl)
+{
+       struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
+       memset(cp, 0x00, sizeof(*cp));
+
+       char *mod = va_arg(vl, char *);  // N
+       int modlen = va_arg(vl, size_t);
+       char *exp = va_arg(vl, char *);  // E
+       int explen = va_arg(vl, size_t);
+
+       rsa_init(&cp->ctx, RSA_PKCS_V15, 0);
+       
+       cp->ctx.len = modlen; // size(N) in bytes
+       mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
+       mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
+       
+       int res = rsa_check_pubkey(&cp->ctx);
+       if(res != 0) {
+               fprintf(stderr, "PolarSSL public key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
+
+               return NULL;
+       }
+
+       return &cp->cp;
+}
+
+static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl)
+{
+       struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
+       memset(cp, 0x00, sizeof(*cp));
+       char *mod = va_arg(vl, char *);
+       int modlen = va_arg(vl, size_t);
+       char *exp = va_arg(vl, char *);
+       int explen = va_arg(vl, size_t);
+       char *d = va_arg(vl, char *);
+       int dlen = va_arg(vl, size_t);
+       char *p = va_arg(vl, char *);
+       int plen = va_arg(vl, size_t);
+       char *q = va_arg(vl, char *);
+       int qlen = va_arg(vl, size_t);
+       char *dp = va_arg(vl, char *);
+       int dplen = va_arg(vl, size_t);
+       char *dq = va_arg(vl, char *);
+       int dqlen = va_arg(vl, size_t);
+       // calc QP via Q and P
+//     char *inv = va_arg(vl, char *);
+//     int invlen = va_arg(vl, size_t);        
+       
+       rsa_init(&cp->ctx, RSA_PKCS_V15, 0);
+       
+       cp->ctx.len = modlen; // size(N) in bytes
+       mpi_read_binary(&cp->ctx.N,  (const unsigned char *)mod, modlen);
+       mpi_read_binary(&cp->ctx.E,  (const unsigned char *)exp, explen);
+
+       mpi_read_binary(&cp->ctx.D,  (const unsigned char *)d, dlen);
+       mpi_read_binary(&cp->ctx.P,  (const unsigned char *)p, plen);
+       mpi_read_binary(&cp->ctx.Q,  (const unsigned char *)q, qlen);
+       mpi_read_binary(&cp->ctx.DP, (const unsigned char *)dp, dplen);
+       mpi_read_binary(&cp->ctx.DQ, (const unsigned char *)dq, dqlen);
+       mpi_inv_mod(&cp->ctx.QP, &cp->ctx.Q, &cp->ctx.P);
+       
+       int res = rsa_check_privkey(&cp->ctx);
+       if(res != 0) {
+               fprintf(stderr, "PolarSSL private key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
+               return NULL;
+       }
+
+       return &cp->cp;
+}
+
+static int myrand(void *rng_state, unsigned char *output, size_t len) {
+    size_t i;
+
+    if(rng_state != NULL)
+        rng_state = NULL;
+
+    for( i = 0; i < len; ++i )
+        output[i] = rand();
+    
+    return 0;
+}
+
+
+static struct crypto_pk *crypto_pk_polarssl_genkey_rsa(va_list vl)
+{
+       struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
+       memset(cp, 0x00, sizeof(*cp));
+       
+       int transient = va_arg(vl, int);
+       unsigned int nbits = va_arg(vl, unsigned int);
+       unsigned int exp = va_arg(vl, unsigned int);
+
+       if (transient) {
+       }
+       
+       int res = rsa_gen_key(&cp->ctx, &myrand, NULL, nbits, exp);
+       if (res) {
+               fprintf(stderr, "PolarSSL private key generation error res=%x exp=%d nbits=%d.\n", res * -1, exp, nbits);
+               return NULL;
+       }
+       
+       return &cp->cp;
+}
+
+static void crypto_pk_polarssl_close(struct crypto_pk *_cp)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+
+       rsa_free(&cp->ctx);
+       free(cp);
+}
+
+static unsigned char *crypto_pk_polarssl_encrypt(const struct crypto_pk *_cp, const unsigned char *buf, size_t len, size_t *clen)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+       int res;
+       unsigned char *result;
+       
+       *clen = 0;
+       size_t keylen = mpi_size(&cp->ctx.N);
+
+       result = malloc(keylen);
+       if (!result) {
+               printf("RSA encrypt failed. Can't allocate result memory.\n");
+               return NULL;
+       }
+
+       res = rsa_public(&cp->ctx, buf, result);
+       if(res) {
+               printf("RSA encrypt failed. Error: %x data len: %d key len: %d\n", res * -1, len, keylen);
+               return NULL;
+       }
+       
+       *clen = keylen;
+       
+       return result;
+}
+
+static unsigned char *crypto_pk_polarssl_decrypt(const struct crypto_pk *_cp, const unsigned char *buf, size_t len, size_t *clen)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+       int res;
+       unsigned char *result;
+       
+       *clen = 0;
+       size_t keylen = mpi_size(&cp->ctx.N);
+
+       result = malloc(keylen);
+       if (!result) {
+               printf("RSA encrypt failed. Can't allocate result memory.\n");
+               return NULL;
+       }
+
+       res = rsa_private(&cp->ctx, buf, result); // CHECK???
+       if(res) {
+               printf("RSA decrypt failed. Error: %x data len: %d key len: %d\n", res * -1, len, keylen);
+               return NULL;
+       }
+       
+       *clen = keylen;
+       
+       return result;
+}
+
+static size_t crypto_pk_polarssl_get_nbits(const struct crypto_pk *_cp)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+
+       return cp->ctx.len * 8;
+return 0;
+}
+
+static unsigned char *crypto_pk_polarssl_get_parameter(const struct crypto_pk *_cp, unsigned param, size_t *plen)
+{
+       struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
+       unsigned char *result = NULL;
+       switch(param){
+               // mod
+               case 0:
+                       *plen = mpi_size(&cp->ctx.N);
+                       result = malloc(*plen);
+                       memset(result, 0x00, *plen);
+                       mpi_write_binary(&cp->ctx.N, result, *plen);
+                       break;
+               // exp
+               case 1:
+                       *plen = mpi_size(&cp->ctx.E);
+                       result = malloc(*plen);
+                       memset(result, 0x00, *plen);
+                       mpi_write_binary(&cp->ctx.E, result, *plen);
+                       break;
+               default:
+                       printf("Error get parameter. Param=%d", param);
+                       break;
+       }
+       
+       return result;
+}
+
+static struct crypto_pk *crypto_pk_polarssl_open(enum crypto_algo_pk pk, va_list vl)
+{
+       struct crypto_pk *cp;
+
+       if (pk == PK_RSA)
+               cp = crypto_pk_polarssl_open_rsa(vl);
+       else
+               return NULL;
+
+       cp->close = crypto_pk_polarssl_close;
+       cp->encrypt = crypto_pk_polarssl_encrypt;
+       cp->get_parameter = crypto_pk_polarssl_get_parameter;
+       cp->get_nbits = crypto_pk_polarssl_get_nbits;
+
+       return cp;
+}
+
+static struct crypto_pk *crypto_pk_polarssl_open_priv(enum crypto_algo_pk pk, va_list vl)
+{
+       struct crypto_pk *cp;
+
+       if (pk == PK_RSA)
+               cp = crypto_pk_polarssl_open_priv_rsa(vl);
+       else
+               return NULL;
+
+       cp->close = crypto_pk_polarssl_close;
+       cp->encrypt = crypto_pk_polarssl_encrypt;
+       cp->decrypt = crypto_pk_polarssl_decrypt;
+       cp->get_parameter = crypto_pk_polarssl_get_parameter;
+       cp->get_nbits = crypto_pk_polarssl_get_nbits;
+
+       return cp;
+}
+
+static struct crypto_pk *crypto_pk_polarssl_genkey(enum crypto_algo_pk pk, va_list vl)
+{
+       struct crypto_pk *cp;
+
+       if (pk == PK_RSA)
+               cp = crypto_pk_polarssl_genkey_rsa(vl);
+       else
+               return NULL;
+
+       cp->close = crypto_pk_polarssl_close;
+       cp->encrypt = crypto_pk_polarssl_encrypt;
+       cp->decrypt = crypto_pk_polarssl_decrypt;
+       cp->get_parameter = crypto_pk_polarssl_get_parameter;
+       cp->get_nbits = crypto_pk_polarssl_get_nbits;
+
+       return cp;
+}
+
+static struct crypto_backend crypto_polarssl_backend = {
+       .hash_open = crypto_hash_polarssl_open,
+       .pk_open = crypto_pk_polarssl_open,
+       .pk_open_priv = crypto_pk_polarssl_open_priv,
+       .pk_genkey = crypto_pk_polarssl_genkey,
+};
+
+struct crypto_backend *crypto_polarssl_init(void)
+{
+       return &crypto_polarssl_backend;
+}
diff --git a/client/emv/emv_pk.c b/client/emv/emv_pk.c
new file mode 100644 (file)
index 0000000..b577855
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* For asprintf */
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "emv_pk.h"
+#include "crypto.h"
+#include "proxmark3.h"
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#define BCD(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
+               -1)
+
+#define HEX(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
+               ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
+               ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
+               -1)
+
+#define TOHEX(v) ((v) < 10 ? (v) + '0' : (v) - 10 + 'a')
+
+static ssize_t emv_pk_read_bin(char *buf, unsigned char *bin, size_t size, size_t *read)
+{
+       size_t left = size;
+       char *p = buf;
+       while (*p && *p == ' ')
+               p++;
+
+       while (left > 0) {
+               int c1, c2;
+               c1 = HEX(*p);
+               if (c1 == -1)
+                       return -(p - buf);
+               p++;
+               c2 = HEX(*p);
+               if (c2 == -1)
+                       return -(p - buf);
+               p++;
+               *bin = (c1 * 16 + c2);
+               bin ++;
+               left --;
+               if (*p == ':')
+                       p++;
+               else if (read) {
+                       *read = (size - left);
+                       break;
+               } else if (left == 0)
+                       break;
+               else
+                       return -(p - buf);
+       }
+
+       while (*p && *p == ' ')
+               p++;
+
+       p--;
+
+       return (p - buf);
+}
+
+static ssize_t emv_pk_read_ymv(char *buf, unsigned *ymv)
+{
+       int i;
+       unsigned char temp[3];
+       char *p = buf;
+
+       *ymv = 0;
+
+       while (*p && *p == ' ')
+               p++;
+
+       for (i = 0; i < 3; i++) {
+               int c1, c2;
+               c1 = BCD(*p);
+               if (c1 == -1)
+                       return -(p - buf);
+               p++;
+               c2 = BCD(*p);
+               if (c2 == -1)
+                       return -(p - buf);
+               p++;
+               temp[i] = (c1 * 16 + c2);
+       }
+
+       while (*p && *p == ' ')
+               p++;
+
+       p--;
+
+       if (temp[1] > 0x12 || temp[2] > 0x31)
+               return -(p - buf);
+
+       *ymv = (temp[0] * 0x10000 + temp[1] * 0x100 + temp[2]);
+
+       return (p - buf);
+}
+
+static ssize_t emv_pk_read_string(char *buf, char *str, size_t size)
+{
+       char *p = buf;
+       while (*p && *p == ' ')
+               p++;
+
+       while (size > 1) {
+               if (*p == ' ')
+                       break;
+               else if (*p < 0x20 || *p >= 0x7f)
+                       return -(p - buf);
+               *str = *p;
+               p++;
+               str ++;
+               size --;
+       }
+
+       *str = 0;
+
+       while (*p && *p == ' ')
+               p++;
+
+       p--;
+
+       return (p - buf);
+}
+
+
+struct emv_pk *emv_pk_parse_pk(char *buf)
+{
+       struct emv_pk *r = calloc(1, sizeof(*r));
+       ssize_t l;
+       char temp[10];
+
+       l = emv_pk_read_bin(buf, r->rid, 5, NULL);
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       l = emv_pk_read_bin(buf, &r->index, 1, NULL);
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       l = emv_pk_read_ymv(buf, &r->expire);
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       l = emv_pk_read_string(buf, temp, sizeof(temp));
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       if (!strcmp(temp, "rsa"))
+               r->pk_algo = PK_RSA;
+       else
+               goto out;
+
+       l = emv_pk_read_bin(buf, r->exp, sizeof(r->exp), &r->elen);
+       if (l <= 0)
+               goto out;
+       buf += l;
+
+       r->modulus = malloc(2048/8);
+       l = emv_pk_read_bin(buf, r->modulus, 2048/8, &r->mlen);
+       if (l <= 0)
+               goto out2;
+       buf += l;
+
+       l = emv_pk_read_string(buf, temp, sizeof(temp));
+       if (l <= 0)
+               goto out2;
+       buf += l;
+
+       if (!strcmp(temp, "sha1"))
+               r->hash_algo = HASH_SHA_1;
+       else
+               goto out2;
+
+       l = emv_pk_read_bin(buf, r->hash, 20, NULL);
+       if (l <= 0)
+               goto out2;
+
+       return r;
+
+out2:
+       free(r->modulus);
+out:
+       free(r);
+       return NULL;
+}
+
+static size_t emv_pk_write_bin(char *out, size_t outlen, const unsigned char *buf, size_t len)
+{
+       int i;
+       size_t pos = 0;
+
+       if (len == 0)
+               return 0;
+       if (outlen < len * 3)
+               return 0;
+
+       out[pos++] = TOHEX(buf[0] >> 4);
+       out[pos++] = TOHEX(buf[0] & 0xf);
+       for (i = 1; i < len; i++) {
+               out[pos++] = ':';
+               out[pos++] = TOHEX(buf[i] >> 4);
+               out[pos++] = TOHEX(buf[i] & 0xf);
+       }
+       out[pos++] = ' ';
+
+       return pos;
+}
+
+static size_t emv_pk_write_str(char *out, size_t outlen, const char *str)
+{
+       size_t len = strlen(str);
+
+       if (len == 0)
+               return 0;
+       if (outlen < len)
+               return 0;
+
+       memcpy(out, str, len);
+
+       return len;
+}
+
+char *emv_pk_dump_pk(const struct emv_pk *pk)
+{
+       size_t outsize = 1024; /* should be enough */
+       char *out = malloc(outsize); /* should be enough */
+       size_t outpos = 0;
+       size_t rc;
+
+       if (!out)
+               return NULL;
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->rid, 5);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, &pk->index, 1);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       if (outpos + 7 > outsize)
+               goto err;
+       out[outpos++] = TOHEX((pk->expire >> 20) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 16) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 12) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 8 ) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 4 ) & 0xf);
+       out[outpos++] = TOHEX((pk->expire >> 0 ) & 0xf);
+       out[outpos++] = ' ';
+
+       if (pk->pk_algo == PK_RSA) {
+               rc = emv_pk_write_str(out + outpos, outsize - outpos, "rsa");
+               if (rc == 0)
+                       goto err;
+               outpos += rc;
+               out[outpos++] = ' ';
+       } else {
+               if (outpos + 4 > outsize)
+                       goto err;
+               out[outpos++] = '?';
+               out[outpos++] = '?';
+               out[outpos++] = TOHEX(pk->pk_algo >> 4);
+               out[outpos++] = TOHEX(pk->pk_algo & 0xf);
+       }
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->exp, pk->elen);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->modulus, pk->mlen);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       if (pk->hash_algo == HASH_SHA_1) {
+               rc = emv_pk_write_str(out + outpos, outsize - outpos, "sha1");
+               if (rc == 0)
+                       goto err;
+               outpos += rc;
+               out[outpos++] = ' ';
+       } else {
+               if (outpos + 4 > outsize)
+                       goto err;
+               out[outpos++] = '?';
+               out[outpos++] = '?';
+               out[outpos++] = TOHEX(pk->pk_algo >> 4);
+               out[outpos++] = TOHEX(pk->pk_algo & 0xf);
+       }
+
+
+       rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->hash, 20);
+       if (rc == 0)
+               goto err;
+       outpos += rc;
+
+       out[outpos-1] = '\0';
+
+       return out;
+
+err:
+       free(out);
+       return NULL;
+}
+
+bool emv_pk_verify(const struct emv_pk *pk)
+{
+       struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
+       if (!ch)
+               return false;
+
+       crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
+       crypto_hash_write(ch, &pk->index, 1);
+       crypto_hash_write(ch, pk->modulus, pk->mlen);
+       crypto_hash_write(ch, pk->exp, pk->elen);
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               return false;
+       }
+
+       size_t hsize = crypto_hash_get_size(ch);
+       bool r = hsize && !memcmp(h, pk->hash, hsize) ? true : false;
+
+       crypto_hash_close(ch);
+
+       return r;
+}
+
+struct emv_pk *emv_pk_new(size_t modlen, size_t explen)
+{
+       struct emv_pk *pk;
+
+       /* Not supported ATM */
+       if (explen > 3)
+               return NULL;
+
+       pk = calloc(1, sizeof(*pk));
+       if (!pk)
+               return NULL;
+
+       pk->mlen = modlen;
+       pk->elen = explen;
+
+       pk->modulus = calloc(modlen, 1);
+       if (!pk->modulus) {
+               free(pk);
+               pk = NULL;
+       }
+
+       return pk;
+}
+
+void emv_pk_free(struct emv_pk *pk)
+{
+       if (!pk)
+               return;
+
+       free(pk->modulus);
+       free(pk);
+}
+
+static struct emv_pk *emv_pk_get_ca_pk_from_file(const char *fname,
+               const unsigned char *rid,
+               unsigned char idx)
+{
+       if  (!fname)
+               return NULL;
+
+       FILE *f = fopen(fname, "r");
+       if (!f) {
+               perror("fopen");
+               return NULL;
+       }
+
+       while (!feof(f)) {
+               char buf[2048];
+               if (fgets(buf, sizeof(buf), f) == NULL)
+                       break;
+
+               struct emv_pk *pk = emv_pk_parse_pk(buf);
+               if (!pk)
+                       continue;
+               if (memcmp(pk->rid, rid, 5) || pk->index != idx) {
+                       emv_pk_free(pk);
+                       continue;
+               }
+
+               fclose(f);
+
+               return pk;
+       }
+
+       fclose(f);
+
+       return NULL;
+}
+
+char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsigned char idx)
+{
+       if (!dirname)
+               dirname = ".";//openemv_config_get_str("capk.dir", NULL);
+
+       if (!dirname)
+               return NULL;
+
+       char *filename;
+       int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0",
+                       dirname,
+                       rid[0],
+                       rid[1],
+                       rid[2],
+                       rid[3],
+                       rid[4],
+                       idx);
+
+       if (ret <= 0)
+               return NULL;
+
+       return filename;
+}
+
+char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid)
+{
+       if (!dirname)
+               dirname = "."; //openemv_config_get_str("capk.dir", NULL);
+
+       if (!dirname)
+               return NULL;
+
+       char *filename;
+       int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks",
+                       dirname,
+                       rid[0],
+                       rid[1],
+                       rid[2],
+                       rid[3],
+                       rid[4]);
+
+       if (ret <= 0)
+               return NULL;
+
+       return filename;
+}
+
+struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx)
+{
+       struct emv_pk *pk = NULL;
+
+/*     if (!pk) {
+               char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
+               if (fname) {
+                       pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
+                       free(fname);
+               }
+       }
+
+       if (!pk) {
+               char *fname = emv_pk_get_ca_pk_rid_file(NULL, rid);
+               if (fname) {
+                       pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
+                       free(fname);
+               }
+       }
+*/
+       if (!pk) {
+               const char *relfname = "emv/capk.txt"; 
+
+               char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
+               strcpy(fname, get_my_executable_directory());
+               strcat(fname, relfname);
+
+               pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
+       }
+       if (!pk)
+               return NULL;
+
+       printf("Verifying CA PK for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...",
+                               pk->rid[0],
+                               pk->rid[1],
+                               pk->rid[2],
+                               pk->rid[3],
+                               pk->rid[4],
+                               pk->index,
+                               pk->mlen * 8);
+       if (emv_pk_verify(pk)) {
+               printf("OK\n");
+
+               return pk;
+       }
+
+       printf("Failed!\n");
+       emv_pk_free(pk);
+
+       return NULL;
+}
diff --git a/client/emv/emv_pk.h b/client/emv/emv_pk.h
new file mode 100644 (file)
index 0000000..e291a06
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef EMV_PK_H
+#define EMV_PK_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct emv_pk {
+       unsigned char rid[5];
+       unsigned char index;
+       unsigned char serial[3];
+       unsigned char pan[10];
+       unsigned char hash_algo;
+       unsigned char pk_algo;
+       unsigned char hash[20];
+       unsigned char exp[3];
+       size_t elen;
+       size_t mlen;
+       unsigned char *modulus;
+       unsigned int expire;
+};
+
+#define EXPIRE(yy, mm, dd)     0x ## yy ## mm ## dd
+
+struct emv_pk *emv_pk_parse_pk(char *buf);
+struct emv_pk *emv_pk_new(size_t modlen, size_t explen);
+void emv_pk_free(struct emv_pk *pk);
+char *emv_pk_dump_pk(const struct emv_pk *pk);
+bool emv_pk_verify(const struct emv_pk *pk);
+
+char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsigned char idx);
+char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid);
+struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx);
+#endif
diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c
new file mode 100644 (file)
index 0000000..7803060
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "emv_pki.h"
+#include "crypto.h"
+#include "dump.h"
+#include "util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+static const unsigned char empty_tlv_value[] = {};
+static const struct tlv empty_tlv = {.tag = 0x0, .len = 0, .value = empty_tlv_value};
+
+static size_t emv_pki_hash_psn[256] = { 0, 0, 11, 2, 17, 2, };
+
+static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
+               uint8_t msgtype,
+               size_t *len,
+               const struct tlv *cert_tlv,
+               ... /* A list of tlv pointers, end with NULL */
+               )
+{
+       struct crypto_pk *kcp;
+       unsigned char *data;
+       size_t data_len;
+       va_list vl;
+
+       if (!enc_pk)
+               return NULL;
+
+       if (!cert_tlv) {
+               printf("ERROR: Can't find certificate\n");
+               return NULL;
+       }
+
+       if (cert_tlv->len != enc_pk->mlen) {
+               printf("ERROR: Certificate length (%d) not equal key length (%d)\n", cert_tlv->len, enc_pk->mlen);
+               return NULL;
+       }
+       kcp = crypto_pk_open(enc_pk->pk_algo,
+                       enc_pk->modulus, enc_pk->mlen,
+                       enc_pk->exp, enc_pk->elen);
+       if (!kcp)
+               return NULL;
+
+       data = crypto_pk_encrypt(kcp, cert_tlv->value, cert_tlv->len, &data_len);
+       crypto_pk_close(kcp);
+
+/*     if (true){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }*/
+       
+       if (data[data_len-1] != 0xbc || data[0] != 0x6a || data[1] != msgtype) {
+               printf("ERROR: Certificate format\n");
+               free(data);
+               return NULL;
+       }
+
+       size_t hash_pos = emv_pki_hash_psn[msgtype];
+       if (hash_pos == 0 || hash_pos > data_len){
+               printf("ERROR: Cant get hash position in the certificate\n");
+               free(data);
+               return NULL;
+       }
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(data[hash_pos]);
+       if (!ch) {
+               printf("ERROR: Cant do hash\n");
+               free(data);
+               return NULL;
+       }
+
+       size_t hash_len = crypto_hash_get_size(ch);
+       crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
+
+       va_start(vl, cert_tlv);
+       while (true) {
+               const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
+               if (!add_tlv)
+                       break;
+
+               crypto_hash_write(ch, add_tlv->value, add_tlv->len);
+       }
+       va_end(vl);
+
+       if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) {
+               printf("ERROR: Calculated wrong hash\n");
+               printf("decoded:    %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
+               printf("calculated: %s\n",sprint_hex(crypto_hash_read(ch), hash_len));
+               crypto_hash_close(ch);
+               free(data);
+               return NULL;
+       }
+
+       crypto_hash_close(ch);
+
+       *len = data_len - hash_len - 1;
+
+       return data;
+}
+
+static unsigned emv_cn_length(const struct tlv *tlv)
+{
+       int i;
+
+       for (i = 0; i < tlv->len; i++) {
+               unsigned char c = tlv->value[i];
+
+               if (c >> 4 == 0xf)
+                       return 2 * i;
+
+               if ((c & 0xf) == 0xf)
+                       return 2 * i + 1;
+       }
+
+       return 2 * tlv->len;
+}
+
+static unsigned char emv_cn_get(const struct tlv *tlv, unsigned pos)
+{
+       if (pos > tlv->len * 2)
+               return 0xf;
+
+       unsigned char c = tlv->value[pos / 2];
+
+       if (pos % 2)
+               return c & 0xf;
+       else
+               return c >> 4;
+}
+
+static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
+               unsigned char msgtype,
+               const struct tlv *pan_tlv,
+               const struct tlv *cert_tlv,
+               const struct tlv *exp_tlv,
+               const struct tlv *rem_tlv,
+               const struct tlv *add_tlv,
+               bool showData
+               )
+{
+       size_t pan_length;
+       unsigned char *data;
+       size_t data_len;
+       size_t pk_len;
+
+       if (!cert_tlv || !exp_tlv || !pan_tlv)
+               return NULL;
+
+       if (!rem_tlv)
+               rem_tlv = &empty_tlv;
+
+       if (msgtype == 2)
+               pan_length = 4;
+       else if (msgtype == 4)
+               pan_length = 10;
+       else {
+               printf("ERROR: Message type must be 2 or 4\n");
+               return NULL;
+       }
+
+       data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
+                       cert_tlv,
+                       rem_tlv,
+                       exp_tlv,
+                       add_tlv,
+                       NULL);
+       if (!data || data_len < 11 + pan_length) {
+               printf("ERROR: Can't decode message\n");
+               return NULL;
+       }
+
+       if (showData){ 
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       /* Perform the rest of checks here */
+
+       struct tlv pan2_tlv = {
+               .tag = 0x5a,
+               .len = pan_length,
+               .value = &data[2],
+       };
+       unsigned pan_len = emv_cn_length(pan_tlv);
+       unsigned pan2_len = emv_cn_length(&pan2_tlv);
+
+       if (((msgtype == 2) && (pan2_len < 4 || pan2_len > pan_len)) ||
+           ((msgtype == 4) && (pan2_len != pan_len))) {
+               printf("ERROR: Invalid PAN lengths\n");
+               free(data);
+
+               return NULL;
+       }
+
+       unsigned i;
+       for (i = 0; i < pan2_len; i++)
+               if (emv_cn_get(pan_tlv, i) != emv_cn_get(&pan2_tlv, i)) {
+                       printf("ERROR: PAN data mismatch\n");
+                       printf("tlv  pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len));
+                       printf("cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len));
+                       free(data);
+
+                       return NULL;
+               }
+
+       pk_len = data[9 + pan_length];
+       if (pk_len > data_len - 11 - pan_length + rem_tlv->len) {
+               printf("ERROR: Invalid pk length\n");
+               free(data);
+               return NULL;
+       }
+
+       if (exp_tlv->len != data[10 + pan_length]) {
+               free(data);
+               return NULL;
+       }
+
+       struct emv_pk *pk = emv_pk_new(pk_len, exp_tlv->len);
+
+       memcpy(pk->rid, enc_pk->rid, 5);
+       pk->index = enc_pk->index;
+
+       pk->hash_algo = data[7 + pan_length];
+       pk->pk_algo = data[8 + pan_length];
+       pk->expire = (data[3 + pan_length] << 16) | (data[2 + pan_length] << 8) | 0x31;
+       memcpy(pk->serial, data + 4 + pan_length, 3);
+       memcpy(pk->pan, data + 2, pan_length);
+       memset(pk->pan + pan_length, 0xff, 10 - pan_length);
+
+       memcpy(pk->modulus, data + 11 + pan_length,
+                       pk_len < data_len - (11 + pan_length) ?
+                       pk_len :
+                       data_len - (11 + pan_length));
+       memcpy(pk->modulus + data_len - (11 + pan_length), rem_tlv->value, rem_tlv->len);
+       memcpy(pk->exp, exp_tlv->value, exp_tlv->len);
+
+       free(data);
+
+       return pk;
+}
+
+static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk,
+               unsigned char msgtype,
+               const struct tlv *pan_tlv,
+               const struct tlv *cert_tlv,
+               const struct tlv *exp_tlv,
+               const struct tlv *rem_tlv,
+               const struct tlv *add_tlv
+               ) {
+       return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, false);
+}
+
+struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db)
+{
+       return emv_pki_decode_key(pk, 2,
+                       tlvdb_get(db, 0x5a, NULL),
+                       tlvdb_get(db, 0x90, NULL),
+                       tlvdb_get(db, 0x9f32, NULL),
+                       tlvdb_get(db, 0x92, NULL),
+                       NULL);
+}
+
+struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv)
+{
+       return emv_pki_decode_key(pk, 4,
+                       tlvdb_get(db, 0x5a, NULL),
+                       tlvdb_get(db, 0x9f46, NULL),
+                       tlvdb_get(db, 0x9f47, NULL),
+                       tlvdb_get(db, 0x9f48, NULL),
+                       sda_tlv);
+}
+
+struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db)
+{
+       return emv_pki_decode_key(pk, 4,
+                       tlvdb_get(db, 0x5a, NULL),
+                       tlvdb_get(db, 0x9f2d, NULL),
+                       tlvdb_get(db, 0x9f2e, NULL),
+                       tlvdb_get(db, 0x9f2f, NULL),
+                       NULL);
+}
+
+struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData)
+{
+       size_t data_len;
+       unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
+                       tlvdb_get(db, 0x93, NULL),
+                       sda_tlv,
+                       NULL);
+
+       if (!data || data_len < 5)
+               return NULL;
+
+       if (showData){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       struct tlvdb *dac_db = tlvdb_fixed(0x9f45, 2, data+3);
+
+       free(data);
+
+       return dac_db;
+}
+struct tlvdb *emv_pki_recover_dac(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv) {
+       return emv_pki_recover_dac_ex(enc_pk, db, sda_tlv, false);
+}
+
+struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv) {
+       return emv_pki_recover_idn_ex(enc_pk, db, dyn_tlv, false);
+}
+
+struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData)
+{
+       size_t data_len;
+       unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
+                       tlvdb_get(db, 0x9f4b, NULL),
+                       dyn_tlv,
+                       NULL);
+
+       if (!data || data_len < 3)
+               return NULL;
+
+       if (data[3] < 2 || data[3] > data_len - 3) {
+               free(data);
+               return NULL;
+       }
+
+       if (showData){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       size_t idn_len = data[4];
+       if (idn_len > data[3] - 1) {
+               free(data);
+               return NULL;
+       }
+
+       // 9f4c ICC Dynamic Number
+       struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
+       
+       free(data);
+
+       return idn_db;
+}
+
+struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData)
+{
+       size_t data_len;
+       unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
+                       tlvdb_get(db, 0x9f4b, NULL),
+                       tlvdb_get(db, 0x9f37, NULL),
+                       tlvdb_get(db, 0x9f02, NULL),
+                       tlvdb_get(db, 0x5f2a, NULL),
+                       tlvdb_get(db, 0x9f69, NULL),
+                       NULL);
+
+       if (!data || data_len < 3)
+               return NULL;
+
+       if (data[3] < 2 || data[3] > data_len - 3) {
+               free(data);
+               return NULL;
+       }
+
+       if (showData){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       size_t idn_len = data[4];
+       if (idn_len > data[3] - 1) {
+               free(data);
+               return NULL;
+       }
+
+       // 9f36 Application Transaction Counter (ATC)
+       struct tlvdb *atc_db = tlvdb_fixed(0x9f36, idn_len, data + 5);
+       
+       free(data);
+
+       return atc_db;
+}
+
+static bool tlv_hash(void *data, const struct tlv *tlv, int level, bool is_leaf)
+{
+       struct crypto_hash *ch = data;
+       size_t tag_len;
+       unsigned char *tag;
+
+       if (tlv_is_constructed(tlv))
+               return true;
+
+       if (tlv->tag == 0x9f4b)
+               return true;
+
+       tag = tlv_encode(tlv, &tag_len);
+       crypto_hash_write(ch, tag, tag_len);
+       free(tag);
+
+       return true;
+}
+
+struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
+               const struct tlvdb *this_db,
+               const struct tlv *pdol_data_tlv,
+               const struct tlv *crm1_tlv,
+               const struct tlv *crm2_tlv)
+{
+       return emv_pki_perform_cda_ex(enc_pk, db, this_db, pdol_data_tlv, crm1_tlv, crm2_tlv, false);
+}
+struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
+               const struct tlvdb *this_db,     // AC TLV result
+               const struct tlv *pdol_data_tlv, // PDOL
+               const struct tlv *crm1_tlv,      // CDOL1
+               const struct tlv *crm2_tlv,      // CDOL2
+               bool showData)
+{
+       const struct tlv *un_tlv = tlvdb_get(db, 0x9f37, NULL);
+       const struct tlv *cid_tlv = tlvdb_get(this_db, 0x9f27, NULL);
+
+       if (!un_tlv || !cid_tlv)
+               return NULL;
+
+       size_t data_len = 0;
+       unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
+                       tlvdb_get(this_db, 0x9f4b, NULL),
+                       un_tlv,
+                       NULL);
+       if (!data || data_len < 3) {
+               printf("ERROR: can't decode message. len %d\n", data_len);
+               return NULL;
+       }
+
+       if (showData){
+               printf("Recovered data:\n");
+               dump_buffer(data, data_len, stdout, 0);
+       }
+
+       if (data[3] < 30 || data[3] > data_len - 4) {
+               printf("ERROR: Invalid data length\n");
+               free(data);
+               return NULL;
+       }
+
+       if (!cid_tlv || cid_tlv->len != 1 || cid_tlv->value[0] != data[5 + data[4]]) {
+               printf("ERROR: CID mismatch\n");
+               free(data);
+               return NULL;
+       }
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(enc_pk->hash_algo);
+       if (!ch) {
+               printf("ERROR: can't create hash\n");
+               free(data);
+               return NULL;
+       }
+
+       if (pdol_data_tlv)
+               crypto_hash_write(ch, pdol_data_tlv->value, pdol_data_tlv->len);
+       if (crm1_tlv)
+               crypto_hash_write(ch, crm1_tlv->value, crm1_tlv->len);
+       if (crm2_tlv)
+               crypto_hash_write(ch, crm2_tlv->value, crm2_tlv->len);
+
+       tlvdb_visit(this_db, tlv_hash, ch, 0);
+
+       if (memcmp(data + 5 + data[4] + 1 + 8, crypto_hash_read(ch), 20)) {
+               printf("ERROR: calculated hash error\n");
+               crypto_hash_close(ch);
+               free(data);
+               return NULL;
+       }
+       crypto_hash_close(ch);
+
+       size_t idn_len = data[4];
+       if (idn_len > data[3] - 1) {
+               printf("ERROR: Invalid IDN length\n");
+               free(data);
+               return NULL;
+       }
+
+       struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
+       free(data);
+
+       return idn_db;
+}
diff --git a/client/emv/emv_pki.h b/client/emv/emv_pki.h
new file mode 100644 (file)
index 0000000..e37e3c7
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef EMV_PKI_H
+#define EMV_PKI_H
+
+#include "emv_pk.h"
+#include "tlv.h"
+
+#include <stddef.h>
+
+struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db);
+struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv);
+struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db);
+
+struct tlvdb *emv_pki_recover_dac(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv);
+struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData);
+struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv);
+struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData);
+struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData);
+struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
+               const struct tlvdb *this_db,
+               const struct tlv *pdol_data_tlv,
+               const struct tlv *crm1_tlv,
+               const struct tlv *crm2_tlv);
+struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
+               const struct tlvdb *this_db,
+               const struct tlv *pdol_data_tlv,
+               const struct tlv *crm1_tlv,
+               const struct tlv *crm2_tlv,
+               bool showData);
+
+#endif
diff --git a/client/emv/emv_pki_priv.c b/client/emv/emv_pki_priv.c
new file mode 100644 (file)
index 0000000..d67a870
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "emv_pki_priv.h"
+#include "crypto.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
+               const unsigned char *rid, unsigned char index,
+               unsigned int expire, enum crypto_algo_hash hash_algo)
+{
+       size_t modlen, explen;
+       unsigned char *mod, *exp;
+
+       if (!rid)
+               return NULL;
+
+       mod = crypto_pk_get_parameter(cp, 0, &modlen);
+       exp = crypto_pk_get_parameter(cp, 1, &explen);
+
+       if (!mod || !modlen || !exp || !explen) {
+               free(mod);
+               free(exp);
+
+               return NULL;
+       }
+
+       struct emv_pk *pk = emv_pk_new(modlen, explen);
+       memcpy(pk->rid, rid, 5);
+       pk->index = index;
+       pk->expire = expire;
+       pk->pk_algo = crypto_pk_get_algo(cp);
+       pk->hash_algo = hash_algo;
+       memcpy(pk->modulus, mod, modlen);
+       memcpy(pk->exp, exp, explen);
+
+       free(mod);
+       free(exp);
+
+       struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
+       if (!ch) {
+               emv_pk_free(pk);
+               return false;
+       }
+
+       crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
+       crypto_hash_write(ch, &pk->index, 1);
+       crypto_hash_write(ch, pk->modulus, pk->mlen);
+       crypto_hash_write(ch, pk->exp, pk->elen);
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               emv_pk_free(pk);
+
+               return NULL;
+       }
+
+       memcpy(pk->hash, h, crypto_hash_get_size(ch));
+       crypto_hash_close(ch);
+
+       return pk;
+}
+
+static struct tlvdb *emv_pki_sign_message(const struct crypto_pk *cp,
+               tlv_tag_t cert_tag, tlv_tag_t rem_tag,
+               const unsigned char *msg, size_t msg_len,
+               ... /* A list of tlv pointers, end with NULL */
+               )
+{
+       size_t tmp_len = (crypto_pk_get_nbits(cp) + 7) / 8;
+       unsigned char *tmp = malloc(tmp_len);
+       if (!tmp)
+               return NULL;
+
+       // XXX
+       struct crypto_hash *ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(tmp);
+
+               return NULL;
+       }
+
+       tmp[0] = 0x6a;
+       tmp[tmp_len - 1] = 0xbc;
+
+       const unsigned char *rem;
+       size_t rem_len;
+       size_t hash_len = crypto_hash_get_size(ch);
+       size_t part_len = tmp_len - 2 - hash_len;
+       if (part_len < msg_len) {
+               memcpy(tmp + 1, msg, part_len);
+               rem = msg + part_len;
+               rem_len = msg_len - part_len;
+       } else {
+               memcpy(tmp + 1, msg, msg_len);
+               memset(tmp + 1 + msg_len, 0xbb, part_len - msg_len);
+               rem = NULL;
+               rem_len = 0;
+       }
+       crypto_hash_write(ch, tmp + 1, part_len);
+       crypto_hash_write(ch, rem, rem_len);
+
+       va_list vl;
+       va_start(vl, msg_len);
+       while (true) {
+               const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
+               if (!add_tlv)
+                       break;
+
+               crypto_hash_write(ch, add_tlv->value, add_tlv->len);
+       }
+       va_end(vl);
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(tmp);
+
+               return NULL;
+       }
+
+       memcpy(tmp + 1 + part_len, h, hash_len);
+       crypto_hash_close(ch);
+
+       size_t cert_len;
+       unsigned char *cert = crypto_pk_decrypt(cp, tmp, tmp_len, &cert_len);
+       free(tmp);
+
+       if (!cert)
+               return NULL;
+
+       struct tlvdb *db = tlvdb_fixed(cert_tag, cert_len, cert);
+       free(cert);
+       if (!db)
+               return NULL;
+
+       if (rem) {
+               struct tlvdb *rdb = tlvdb_fixed(rem_tag, rem_len, rem);
+               if (!rdb) {
+                       tlvdb_free(db);
+
+                       return NULL;
+               }
+               tlvdb_add(db, rdb);
+       }
+
+       return db;
+}
+
+static struct tlvdb *emv_pki_sign_key(const struct crypto_pk *cp,
+               struct emv_pk *ipk,
+               unsigned char msgtype,
+               size_t pan_len,
+               tlv_tag_t cert_tag,
+               tlv_tag_t exp_tag,
+               tlv_tag_t rem_tag,
+               const struct tlv *add_tlv
+               )
+{
+       unsigned pos = 0;
+       unsigned char *msg = malloc(1 + pan_len + 2 + 3 + 1 + 1 + 1 + 1 + ipk->mlen);
+
+       if (!msg)
+               return NULL;
+
+       msg[pos++] = msgtype;
+       memcpy(msg + pos, ipk->pan, pan_len); pos += pan_len;
+       msg[pos++] = (ipk->expire >> 8) & 0xff;
+       msg[pos++] = (ipk->expire >> 16) & 0xff;
+       memcpy(msg + pos, ipk->serial, 3); pos += 3;
+       msg[pos++] = ipk->hash_algo;
+       msg[pos++] = ipk->pk_algo;
+       msg[pos++] = ipk->mlen;
+       msg[pos++] = ipk->elen;
+       memcpy(msg + pos, ipk->modulus, ipk->mlen);
+       pos += ipk->mlen;
+
+       struct tlvdb *exp_db = tlvdb_fixed(exp_tag, ipk->elen, ipk->exp);
+       if (!exp_db) {
+               free(msg);
+
+               return NULL;
+       }
+
+       struct tlvdb *db = emv_pki_sign_message(cp,
+                       cert_tag, rem_tag,
+                       msg, pos,
+                       tlvdb_get(exp_db, exp_tag, NULL),
+                       add_tlv,
+                       NULL);
+       free(msg);
+       if (!db)
+               return NULL;
+
+       tlvdb_add(db, exp_db);
+
+       return db;
+}
+
+struct tlvdb *emv_pki_sign_issuer_cert(const struct crypto_pk *cp, struct emv_pk *issuer_pk)
+{
+       return emv_pki_sign_key(cp, issuer_pk, 2, 4, 0x90, 0x9f32, 0x92, NULL);
+}
+
+struct tlvdb *emv_pki_sign_icc_cert(const struct crypto_pk *cp, struct emv_pk *icc_pk, const struct tlv *sda_tlv)
+{
+       return emv_pki_sign_key(cp, icc_pk, 4, 10, 0x9f46, 0x9f47, 0x9f48, sda_tlv);
+}
+
+struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk *icc_pe_pk)
+{
+       return emv_pki_sign_key(cp, icc_pe_pk, 4, 10, 0x9f2d, 0x9f2e, 0x9f2f, NULL);
+}
+
+struct tlvdb *emv_pki_sign_dac(const struct crypto_pk *cp, const struct tlv *dac_tlv, const struct tlv *sda_tlv)
+{
+       unsigned pos = 0;
+       unsigned char *msg = malloc(1+1+dac_tlv->len);
+
+       if (!msg)
+               return NULL;
+
+       msg[pos++] = 3;
+       msg[pos++] = HASH_SHA_1;
+       memcpy(msg+pos, dac_tlv->value, dac_tlv->len);
+       pos += dac_tlv->len;
+
+       struct tlvdb *db = emv_pki_sign_message(cp,
+                       0x93, 0,
+                       msg, pos,
+                       sda_tlv,
+                       NULL);
+
+       free(msg);
+
+       return db;
+}
+
+struct tlvdb *emv_pki_sign_idn(const struct crypto_pk *cp, const struct tlv *idn_tlv, const struct tlv *dyn_tlv)
+{
+       unsigned pos = 0;
+       unsigned char *msg = malloc(1+1+1+1+idn_tlv->len);
+
+       if (!msg)
+               return NULL;
+
+       msg[pos++] = 5;
+       msg[pos++] = HASH_SHA_1;
+       msg[pos++] = idn_tlv->len + 1;
+       msg[pos++] = idn_tlv->len;
+       memcpy(msg+pos, idn_tlv->value, idn_tlv->len);
+       pos += idn_tlv->len;
+
+       struct tlvdb *db = emv_pki_sign_message(cp,
+                       0x9f4b, 0,
+                       msg, pos,
+                       dyn_tlv,
+                       NULL);
+
+       free(msg);
+
+       return db;
+}
diff --git a/client/emv/emv_pki_priv.h b/client/emv/emv_pki_priv.h
new file mode 100644 (file)
index 0000000..4f1639d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * libopenemv - a library to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef EMV_PKI_PRIV_H
+#define EMV_PKI_PRIV_H
+
+#include "crypto.h"
+#include "emv_pk.h"
+#include "tlv.h"
+
+#include <stddef.h>
+
+struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
+               const unsigned char *rid, unsigned char index,
+               unsigned int expire, enum crypto_algo_hash hash_algo);
+struct tlvdb *emv_pki_sign_issuer_cert(const struct crypto_pk *cp, struct emv_pk *issuer_pk);
+struct tlvdb *emv_pki_sign_icc_cert(const struct crypto_pk *cp, struct emv_pk *icc_pk, const struct tlv *sda_tlv);
+struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk *icc_pe_pk);
+
+struct tlvdb *emv_pki_sign_dac(const struct crypto_pk *cp, const struct tlv *dac_tlv, const struct tlv *sda_tlv);
+struct tlvdb *emv_pki_sign_idn(const struct crypto_pk *cp, const struct tlv *idn_tlv, const struct tlv *dyn_tlv);
+
+#endif
index 25ad9658509e855f61f1e33c195c8b4f684c4e74..cdd57cb519486a7fba431794dc449e9b9a298e28 100644 (file)
@@ -177,6 +177,7 @@ static const struct emv_tag emv_tags[] = {
        { 0x01  , "", EMV_TAG_STRING }, // string for headers
        { 0x02  , "Raw data", }, // data
        { 0x20  , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard!
+       { 0x21  , "Input list for Offline Data Authentication" }, // not standard! data for "Offline Data Authentication" come from "read records" command. (EMV book3 10.3)
 
        // EMV
        { 0x41  , "Country code and national data" },
@@ -266,6 +267,7 @@ static const struct emv_tag emv_tags[] = {
        { 0x9f65, "PCVC3(Track2)" },
        { 0x9f66, "PUNATC(Track2) / Terminal Transaction Qualifiers (TTQ)", EMV_TAG_BITMASK, &EMV_TTQ },
        { 0x9f67, "NATC(Track2) / MSD Offset" },
+       { 0x9f68, "Cardholder verification method list (PayPass)" },
        { 0x9f69, "Card Authentication Related Data" },
        { 0x9f6a, "Unpredictable Number", EMV_TAG_NUMERIC },
        { 0x9f6b, "Track 2 Data" },
index 36438413a25882f447e96a4c3aa55ed736253e04..08c6e3dbb53f5d57421897a35475ea9e0bb2a60f 100644 (file)
@@ -16,7 +16,7 @@ static const char *PSElist [] = {
        "325041592E5359532E4444463031", // 2PAY.SYS.DDF01 - Visa Proximity Payment System Environment - PPSE
        "315041592E5359532E4444463031"  // 1PAY.SYS.DDF01 - Visa Payment System Environment - PSE
 };
-static const size_t PSElistLen = sizeof(PSElist)/sizeof(char*);
+//static const size_t PSElistLen = sizeof(PSElist)/sizeof(char*);
 
 typedef struct {
        enum CardPSVendor vendor;
@@ -464,32 +464,378 @@ int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen
        return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
 }
 
+int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
+}
+
 int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
        return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
 }
 
 // Authentication 
-int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) {
-       if (AIDlen < 5) 
-               return 1;
-       
-       // Get public key index (0x8F)
-       //int PubKeyIndx = 0; 
-       
-       // Get public key from key storage
-       // GetPublicKey(AID(0..5), PubKeyIndx)
-       
-       // Processing of Issuer Public Key Certificate (0x90)
-       //Certificate = 
-       
-       // check issuer public key certificate
+static struct emv_pk *get_ca_pk(struct tlvdb *db) {
+       const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL);
+       const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL);
+
+       if (!df_tlv || !caidx_tlv || df_tlv->len < 6 || caidx_tlv->len != 1)
+               return NULL;
+
+       PrintAndLog("CA public key index 0x%0x", caidx_tlv->value[0]);
+       return emv_pk_get_ca_pk(df_tlv->value, caidx_tlv->value[0]);
+}
+
+int trSDA(struct tlvdb *tlv) {
+
+       struct emv_pk *pk = get_ca_pk(tlv);
+       if (!pk) {
+               PrintAndLog("ERROR: Key not found. Exit.");
+               return 2;
+       }
        
-       // Verification of Signed Static Application Data (SSAD) (0x93)
+       struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
+       if (!issuer_pk) {
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: Issuer certificate not found. Exit.");
+               return 2;
+       }
+
+       PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx",
+               issuer_pk->rid[0],
+               issuer_pk->rid[1],
+               issuer_pk->rid[2],
+               issuer_pk->rid[3],
+               issuer_pk->rid[4],
+               issuer_pk->index,
+               issuer_pk->serial[0],
+               issuer_pk->serial[1],
+               issuer_pk->serial[2]
+               );
+
+       const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
+       if (!sda_tlv || sda_tlv->len < 1) {
+               emv_pk_free(issuer_pk);
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit.");
+               return 3;
+       }
        
-       // get 9F4A Static Data Authentication Tag List
+       struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
+       if (dac_db) {
+               const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
+               PrintAndLog("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
+               tlvdb_add(tlv, dac_db);
+       } else {
+               emv_pk_free(issuer_pk);
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: SSAD verify error");
+               return 4;
+       }
        
-       // set Data Auth Code (9F45) from SSAD 
+       emv_pk_free(issuer_pk);
+       emv_pk_free(pk);
+       return 0;
+}
+
+static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
+static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
+
+int trDDA(bool decodeTLV, struct tlvdb *tlv) {
+       uint8_t buf[APDU_RES_LEN] = {0};
+       size_t len = 0;
+       uint16_t sw = 0;
+
+       struct emv_pk *pk = get_ca_pk(tlv);
+       if (!pk) {
+               PrintAndLog("ERROR: Key not found. Exit.");
+               return 2;
+       }
+
+       const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
+       if (!sda_tlv || sda_tlv->len < 1) {
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit.");
+               return 3;
+       }
+
+       struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
+       if (!issuer_pk) {
+               emv_pk_free(pk);
+               PrintAndLog("ERROR: Issuer certificate not found. Exit.");
+               return 2;
+       }
+       printf("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                       issuer_pk->rid[0],
+                       issuer_pk->rid[1],
+                       issuer_pk->rid[2],
+                       issuer_pk->rid[3],
+                       issuer_pk->rid[4],
+                       issuer_pk->index,
+                       issuer_pk->serial[0],
+                       issuer_pk->serial[1],
+                       issuer_pk->serial[2]
+                       );
+                               
+       struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
+       if (!icc_pk) {
+               emv_pk_free(pk);
+               emv_pk_free(issuer_pk);
+               PrintAndLog("ERROR: ICC setrificate not found. Exit.");
+               return 2;
+       }
+       printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                       icc_pk->rid[0],
+                       icc_pk->rid[1],
+                       icc_pk->rid[2],
+                       icc_pk->rid[3],
+                       icc_pk->rid[4],
+                       icc_pk->index,
+                       icc_pk->serial[0],
+                       icc_pk->serial[1],
+                       icc_pk->serial[2]
+                       );
+
+       struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv);
+       if (!icc_pe_pk) {
+               PrintAndLog("WARNING: ICC PE PK recover error. ");
+       } else {
+               printf("ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                               icc_pe_pk->rid[0],
+                               icc_pe_pk->rid[1],
+                               icc_pe_pk->rid[2],
+                               icc_pe_pk->rid[3],
+                               icc_pe_pk->rid[4],
+                               icc_pe_pk->index,
+                               icc_pe_pk->serial[0],
+                               icc_pe_pk->serial[1],
+                               icc_pe_pk->serial[2]
+                               );
+       }
+
+       // 9F4B: Signed Dynamic Application Data
+       const struct tlv *sdad_tlv = tlvdb_get(tlv, 0x9f4b, NULL);
+       // DDA with internal authenticate OR fDDA with filled 0x9F4B tag (GPO result)
+       // EMV kernel3 v2.4, contactless book C-3, C.1., page 147
+       if (sdad_tlv) {
+               PrintAndLog("\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
+
+               const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true);
+               if (!atc_db) {
+                       PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)");
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 8;
+               }
+
+               // 9f36 Application Transaction Counter (ATC)
+               const struct tlv *atc_tlv = tlvdb_get(atc_db, 0x9f36, NULL);
+               if(atc_tlv) {
+                       PrintAndLog("\nATC (Application Transaction Counter) [%zu] %s", atc_tlv->len, sprint_hex_inrow(atc_tlv->value, atc_tlv->len));
+                       
+                       const struct tlv *core_atc_tlv = tlvdb_get(tlv, 0x9f36, NULL);
+                       if(tlv_equal(core_atc_tlv, atc_tlv)) {
+                               PrintAndLog("ATC check OK.");
+                               PrintAndLog("fDDA (fast DDA) verified OK.");
+                       } else {
+                               PrintAndLog("ERROR: fDDA verified, but ATC in the certificate and ATC in the record not the same.");
+                       }
+               } else {
+                       PrintAndLog("\nERROR: fDDA (fast DDA) verify error");
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 9;
+               }
+       } else {
+               struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
+               if (dac_db) {
+                       const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
+                       printf("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
+                       tlvdb_add(tlv, dac_db);
+               } else {
+                       PrintAndLog("ERROR: SSAD verify error");
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 4;
+               }
+               
+               PrintAndLog("\n* Calc DDOL");
+               const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL);
+               if (!ddol_tlv) {
+                       ddol_tlv = &default_ddol_tlv;
+                       PrintAndLog("DDOL [9f49] not found. Using default DDOL");
+               }
+
+               struct tlv *ddol_data_tlv = dol_process(ddol_tlv, tlv, 0);
+               if (!ddol_data_tlv) {
+                       PrintAndLog("ERROR: Can't create DDOL TLV");
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 5;
+               }
+
+               PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
+
+               PrintAndLog("\n* Internal Authenticate");
+               int res = EMVInternalAuthenticate(true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL);
+               if (res) {      
+                       PrintAndLog("Internal Authenticate error(%d): %4x. Exit...", res, sw);
+                       free(ddol_data_tlv);
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 6;
+               }
+
+               struct tlvdb *dda_db = NULL;
+               if (buf[0] == 0x80) {
+                       if (len < 3 ) {
+                               PrintAndLog("ERROR: Internal Authenticate format1 parsing error. length=%d", len);
+                       } else {
+                               // 9f4b Signed Dynamic Application Data
+                               dda_db = tlvdb_fixed(0x9f4b, len - 2, buf + 2);
+                               tlvdb_add(tlv, dda_db);
+                               if (decodeTLV){
+                                       PrintAndLog("* * Decode response format 1:");
+                                       TLVPrintFromTLV(dda_db);
+                               }
+                       }
+               } else {
+                       dda_db = tlvdb_parse_multi(buf, len);
+                       if(!dda_db) {
+                               PrintAndLog("ERROR: Can't parse Internal Authenticate result as TLV");
+                               free(ddol_data_tlv);
+                               emv_pk_free(pk);
+                               emv_pk_free(issuer_pk);
+                               emv_pk_free(icc_pk);
+                               return 7;
+                       }
+                       tlvdb_add(tlv, dda_db);
+                       
+                       if (decodeTLV)
+                               TLVPrintFromTLV(dda_db);
+               }
+
+               struct tlvdb *idn_db = emv_pki_recover_idn_ex(icc_pk, dda_db, ddol_data_tlv, true);
+               free(ddol_data_tlv);
+               if (!idn_db) {
+                       PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)");
+                       tlvdb_free(dda_db);
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 8;
+               }
+               tlvdb_free(dda_db);
+
+               // 9f4c ICC Dynamic Number
+               const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
+               if(idn_tlv) {
+                       PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
+                       PrintAndLog("DDA verified OK.");
+                       tlvdb_add(tlv, idn_db);
+                       tlvdb_free(idn_db);
+               } else {
+                       PrintAndLog("\nERROR: DDA verify error");
+                       tlvdb_free(idn_db);
+
+                       emv_pk_free(pk);
+                       emv_pk_free(issuer_pk);
+                       emv_pk_free(icc_pk);
+                       return 9;
+               }
+       }
        
+       emv_pk_free(pk);
+       emv_pk_free(issuer_pk);
+       emv_pk_free(icc_pk);
        return 0;
 }
 
+int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv) {
+
+       struct emv_pk *pk = get_ca_pk(tlv);
+       if (!pk) {
+               PrintAndLog("ERROR: Key not found. Exit.");
+               return 2;
+       }
+
+       const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
+       if (!sda_tlv || sda_tlv->len < 1) {
+               PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit.");
+               emv_pk_free(pk);
+               return 3;
+       }
+
+       struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
+       if (!issuer_pk) {
+               PrintAndLog("ERROR: Issuer certificate not found. Exit.");
+               emv_pk_free(pk);
+               return 2;
+       }
+       printf("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                       issuer_pk->rid[0],
+                       issuer_pk->rid[1],
+                       issuer_pk->rid[2],
+                       issuer_pk->rid[3],
+                       issuer_pk->rid[4],
+                       issuer_pk->index,
+                       issuer_pk->serial[0],
+                       issuer_pk->serial[1],
+                       issuer_pk->serial[2]
+                       );
+                               
+       struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
+       if (!icc_pk) {
+               PrintAndLog("ERROR: ICC setrificate not found. Exit.");
+               emv_pk_free(pk);
+               emv_pk_free(issuer_pk);
+               return 2;
+       }
+       printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
+                       icc_pk->rid[0],
+                       icc_pk->rid[1],
+                       icc_pk->rid[2],
+                       icc_pk->rid[3],
+                       icc_pk->rid[4],
+                       icc_pk->index,
+                       icc_pk->serial[0],
+                       icc_pk->serial[1],
+                       icc_pk->serial[2]
+                       );
+
+       struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
+       if (dac_db) {
+               const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
+               PrintAndLog("SSAD verified OK. (%02hhx:%02hhx)", dac_tlv->value[0], dac_tlv->value[1]);
+               tlvdb_add(tlv, dac_db);
+       } else {
+               PrintAndLog("ERROR: SSAD verify error");
+               emv_pk_free(pk);
+               emv_pk_free(issuer_pk);
+               emv_pk_free(icc_pk);
+               return 4;
+       }
+       
+       PrintAndLog("\n* * Check Signed Dynamic Application Data (SDAD)");
+       struct tlvdb *idn_db = emv_pki_perform_cda_ex(icc_pk, tlv, ac_tlv,
+                       pdol_data_tlv, // pdol
+                       ac_data_tlv,   // cdol1
+                       NULL,          // cdol2 
+                       true);
+       if (idn_db) {
+               const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
+               PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
+               PrintAndLog("CDA verified OK.");
+               tlvdb_add(tlv, idn_db);
+       } else {
+               PrintAndLog("\nERROR: CDA verify error");
+       }
+
+       emv_pk_free(pk);
+       emv_pk_free(issuer_pk);
+       emv_pk_free(icc_pk);
+       return 0;
+}
index 7df5885025b8a3681ac9874a467ec06d75a19b28..94be4fcf36b8949fc1bd641448f4ff3e689594b8 100644 (file)
 #include "common.h"
 #include "ui.h"
 #include "cmdhf14a.h"
-#include "emv/apduinfo.h"
-#include "emv/tlv.h"
-#include "emv/dol.h"
-#include "emv/dump.h"
-#include "emv/emv_tags.h"
+#include "apduinfo.h"
+#include "tlv.h"
+#include "dol.h"
+#include "dump.h"
+#include "emv_tags.h"
+#include "emv_pk.h"
+#include "emv_pki.h"
 
 #define APDU_RES_LEN 260
 #define APDU_AID_LEN 50
@@ -79,10 +81,14 @@ extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t
 // AC
 extern int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
 extern int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
+// DDA
+extern int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
 // Mastercard
 int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
 // Auth
-extern int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv);
+extern int trSDA(struct tlvdb *tlv);
+extern int trDDA(bool decodeTLV, struct tlvdb *tlv);
+extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv);
 
 #endif
 
diff --git a/client/emv/test/cda_test.c b/client/emv/test/cda_test.c
new file mode 100644 (file)
index 0000000..536a586
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../emv_pk.h"
+#include "../crypto.h"
+#include "../dump.h"
+#include "../tlv.h"
+#include "../emv_pki.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct emv_pk c_mchip_05 = {
+       .rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
+       .index = 5,
+       .hash_algo = HASH_SHA_1,
+       .pk_algo = PK_RSA,
+       .hash = {
+               0xeb, 0xfa, 0x0d, 0x5d,
+               0x06, 0xd8, 0xce, 0x70,
+               0x2d, 0xa3, 0xea, 0xe8,
+               0x90, 0x70, 0x1d, 0x45,
+               0xe2, 0x74, 0xc8, 0x45, },
+       .exp = { 0x03, },
+       .elen = 1,
+       .mlen = 1408 / 8,
+       .modulus = (unsigned char[]){
+               0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
+               0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
+               0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
+               0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
+               0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
+               0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
+               0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
+               0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
+               0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
+               0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
+               0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
+       },
+};
+
+const unsigned char c_issuer_cert[] = {
+               0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
+               0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
+               0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
+               0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
+               0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
+               0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
+               0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
+               0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
+               0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
+               0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
+               0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
+};
+
+const unsigned char c_issuer_rem[] = {
+               0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
+               0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
+               0x6d, 0xbd, 0x64, 0x15,
+};
+
+const unsigned char c_issuer_exp[] = {
+               0x03,
+};
+
+const unsigned char c_icc_cert[] = {
+               0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
+               0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
+               0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
+               0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
+               0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
+               0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
+               0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
+               0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
+               0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
+               0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
+               0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
+};
+
+const unsigned char c_icc_exp[] = {
+               0x03,
+};
+
+const unsigned char c_sdad_cr[] = {
+       0x1c, 0x00, 0x9f, 0xc4, 0x86, 0x79, 0x15, 0x7d, 0xbf, 0xf4, 0x5f, 0x65, 0xd3, 0x3f, 0xf7, 0x8d,
+       0x4f, 0xcb, 0xf0, 0xcf, 0x5e, 0xa4, 0x20, 0x8d, 0x10, 0x7a, 0xe9, 0x5a, 0xa3, 0x8c, 0x54, 0x6d,
+       0x0e, 0x5a, 0x18, 0xb8, 0x74, 0x03, 0xa1, 0x2b, 0xd4, 0x47, 0xa8, 0xbb, 0xfc, 0x1e, 0x49, 0xce,
+       0x0b, 0x2e, 0x25, 0x13, 0x89, 0x20, 0x57, 0x03, 0xc9, 0xbb, 0x1a, 0x88, 0xcc, 0x79, 0xf1, 0xdd,
+       0xc2, 0xf9, 0x84, 0x1e, 0xad, 0xf0, 0x7c, 0xe0, 0x7b, 0x62, 0x51, 0x1d, 0xdc, 0x93, 0xdf, 0x59,
+       0xf2, 0x8f, 0x0e, 0x91, 0xf9, 0x23, 0x32, 0xd2, 0x9c, 0xde, 0xf2, 0xbc, 0xcb, 0x10, 0x08, 0x85,
+       0x05, 0x00, 0xef, 0x3e, 0x47, 0x0a, 0x4c, 0xb1, 0x8c, 0xd9, 0x1a, 0xa5, 0xc1, 0xa1, 0x08, 0xf3,
+
+};
+
+const unsigned char c_ssd1[] = {
+       0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
+       0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
+       0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
+       0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
+       0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
+       0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
+       0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
+       0x39, 0x00,
+};
+static const struct tlv ssd1_tlv = {
+       .len = sizeof(c_ssd1),
+       .value = c_ssd1,
+};
+
+const unsigned char c_pan[] = {
+       0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
+};
+
+const unsigned char c_dd1[] = {
+       0x12, 0x34, 0x57, 0x79,
+};
+
+const unsigned char c_dd2[] = {
+       0x9f, 0x27, 0x01, 0x40, 0x9f, 0x36, 0x02, 0x00, 0x10, 0x9f, 0x10, 0x12, 0x00, 0x10, 0x90, 0x40,
+       0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+};
+
+const unsigned char c_crm1[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x06, 0x43, 0x14, 0x09, 0x25, 0x50, 0x12, 0x34, 0x57, 0x79, 0x23, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x00,
+};
+static const struct tlv crm1_tlv = {
+       .len = sizeof(c_crm1),
+       .value = c_crm1,
+};
+
+static int cda_test_raw(bool verbose)
+{
+       const struct emv_pk *pk = &c_mchip_05;
+
+       struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
+                       pk->modulus, pk->mlen,
+                       pk->exp, pk->elen);
+       if (!kcp)
+               return 1;
+
+       unsigned char *ipk_data;
+       size_t ipk_data_len;
+       ipk_data = crypto_pk_encrypt(kcp, c_issuer_cert, sizeof(c_issuer_cert), &ipk_data_len);
+       crypto_pk_close(kcp);
+
+       if (!ipk_data)
+               return 1;
+
+       if (verbose) {
+               printf("issuer cert:\n");
+               dump_buffer(ipk_data, ipk_data_len, stdout, 0);
+       }
+
+       size_t ipk_pk_len = ipk_data[13];
+       unsigned char *ipk_pk = malloc(ipk_pk_len);
+       memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
+       memcpy(ipk_pk + ipk_data_len - 36, c_issuer_rem, sizeof(c_issuer_rem));
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, ipk_data + 1, 14);
+       crypto_hash_write(ch, ipk_pk, ipk_pk_len);
+       crypto_hash_write(ch, c_issuer_exp, sizeof(c_issuer_exp));
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(ipk_data);
+
+       struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
+                       c_issuer_exp, (int) sizeof(c_issuer_exp));
+       free(ipk_pk);
+       if (!ikcp)
+               return 1;
+
+       unsigned char *iccpk_data;
+       size_t iccpk_data_len;
+       iccpk_data = crypto_pk_encrypt(ikcp, c_icc_cert, sizeof(c_icc_cert), &iccpk_data_len);
+       crypto_pk_close(ikcp);
+
+       if (!iccpk_data)
+               return 1;
+
+       if (verbose) {
+               printf("icc cert:\n");
+               dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
+       }
+
+       size_t iccpk_pk_len = iccpk_data[19];
+       unsigned char *iccpk_pk = malloc(iccpk_pk_len);
+       memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
+       /*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
+       crypto_hash_write(ch, c_icc_exp, sizeof(c_icc_exp));
+       crypto_hash_write(ch, c_ssd1, sizeof(c_ssd1));
+
+       h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash1.1:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(iccpk_data);
+
+       struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
+                       c_issuer_exp, (int) sizeof(c_issuer_exp));
+       free(iccpk_pk);
+       if (!icckcp)
+               return 1;
+
+       size_t sdad_len;
+       unsigned char *sdad = crypto_pk_encrypt(icckcp, c_sdad_cr, sizeof(c_sdad_cr), &sdad_len);
+       crypto_pk_close(icckcp);
+       if (!sdad)
+               return 1;
+
+       if (verbose) {
+               printf("SDAD:\n");
+               dump_buffer(sdad, sdad_len, stdout, 0);
+       }
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(sdad);
+               return 1;
+       }
+
+       crypto_hash_write(ch, sdad + 1, sdad_len - 22);
+       crypto_hash_write(ch, c_dd1, sizeof(c_dd1));
+
+       unsigned char *h2 = crypto_hash_read(ch);
+       if (!h2) {
+               crypto_hash_close(ch);
+               free(sdad);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash2:\n");
+               dump_buffer(h2, 20, stdout, 0);
+       }
+
+       crypto_hash_close(ch);
+
+       ch =  crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(sdad);
+               return 1;
+       }
+
+       crypto_hash_write(ch, c_crm1, sizeof(c_crm1));
+       crypto_hash_write(ch, c_dd2, sizeof(c_dd2));
+
+       h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(sdad);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash2.1:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(sdad + 5 + 8 + 1 + 8, h, 20)) {
+               crypto_hash_close(ch);
+               free(sdad);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+
+       free(sdad);
+
+       return 0;
+}
+
+static int cda_test_pk(bool verbose)
+{
+       const struct emv_pk *pk = &c_mchip_05;
+       struct tlvdb *db;
+
+       db = tlvdb_external(0x90, sizeof(c_issuer_cert), c_issuer_cert);
+       tlvdb_add(db, tlvdb_external(0x9f32, sizeof(c_issuer_exp), c_issuer_exp));
+       tlvdb_add(db, tlvdb_external(0x92, sizeof(c_issuer_rem), c_issuer_rem));
+       tlvdb_add(db, tlvdb_external(0x5a, sizeof(c_pan), c_pan));
+
+       struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
+       if (!ipk) {
+               fprintf(stderr, "Could not recover Issuer certificate!\n");
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_external(0x9f46, sizeof(c_icc_cert), c_icc_cert));
+       tlvdb_add(db, tlvdb_external(0x9f47, sizeof(c_icc_exp), c_icc_exp));
+       /*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(issuer_rem), issuer_rem));*/
+
+       struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
+       if (!iccpk) {
+               fprintf(stderr, "Could not recover ICC certificate!\n");
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_fixed(0x9f37, sizeof(c_dd1), c_dd1));
+
+       struct tlvdb *cda_db;
+       cda_db = tlvdb_fixed(0x9f27, 1, (unsigned char[]){ 0x40 });
+       tlvdb_add(cda_db, tlvdb_fixed(0x9f36, 2, (unsigned char[]) { 0x00, 0x10 }));
+       tlvdb_add(cda_db, tlvdb_external(0x9f4b, sizeof(c_sdad_cr), c_sdad_cr));
+       tlvdb_add(cda_db, tlvdb_fixed(0x9f10, 0x12,
+                       (unsigned char[]) { 0x00, 0x10, 0x90, 0x40, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}));
+
+       struct tlvdb *idndb = emv_pki_perform_cda(iccpk, db, cda_db,
+                       NULL,
+                       &crm1_tlv,
+                       NULL);
+       if (!idndb) {
+               fprintf(stderr, "Could not recover IDN!\n");
+               tlvdb_free(cda_db);
+               emv_pk_free(iccpk);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
+       if (!idn) {
+               fprintf(stderr, "IDN not found!\n");
+               tlvdb_free(idndb);
+               tlvdb_free(cda_db);
+               emv_pk_free(iccpk);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       if (verbose) {
+               printf("IDN:\n");
+               dump_buffer(idn->value, idn->len, stdout, 0);
+       }
+
+       tlvdb_free(idndb);
+       tlvdb_free(cda_db);
+       emv_pk_free(iccpk);
+       emv_pk_free(ipk);
+       tlvdb_free(db);
+
+       return 0;
+}
+
+int exec_cda_test(bool verbose)
+{
+       int ret;
+       fprintf(stdout, "\n");
+       
+       ret = cda_test_raw(verbose);
+       if (ret) {
+               fprintf(stderr, "CDA raw test: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "CDA raw test: passed\n");
+
+       ret = cda_test_pk(verbose);
+       if (ret) {
+               fprintf(stderr, "CDA test pk: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "CDA test pk: passed\n");
+
+       return 0;
+}
diff --git a/client/emv/test/cda_test.h b/client/emv/test/cda_test.h
new file mode 100644 (file)
index 0000000..1d321a2
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include <stdbool.h> 
+extern int exec_cda_test(bool verbose);
diff --git a/client/emv/test/crypto_test.c b/client/emv/test/crypto_test.c
new file mode 100644 (file)
index 0000000..ff18b9d
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../crypto.h"
+#include "../dump.h"
+#include "util_posix.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+static int test_genkey(unsigned int keylength, unsigned char *msg, size_t msg_len, bool verbose)
+{
+       int ret = 1;
+       size_t tmp_len, tmp2_len;
+       unsigned char *tmp, *tmp2;
+       struct crypto_pk *pk;
+
+       printf("Testing key length %u ", keylength);
+       uint64_t ms = msclock();
+
+       pk = crypto_pk_genkey(PK_RSA, 1, keylength, 3);
+       if (!pk) {
+               fprintf(stderr, "ERROR: key generation error.\n");
+               goto out;
+       }
+
+       tmp_len = crypto_pk_get_nbits(pk);
+       if (tmp_len != keylength) {
+               fprintf(stderr, "ERROR: crypto_pk_get_nbits.\n");
+               goto close;
+       }
+
+       tmp = crypto_pk_decrypt(pk, msg, msg_len, &tmp_len);
+       if (!tmp) {
+               fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
+               goto close;
+       }
+
+       tmp2 = crypto_pk_encrypt(pk, tmp, tmp_len, &tmp2_len);
+       if (!tmp2) {
+               fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
+               goto free_tmp;
+       }
+
+       if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
+               ret = 0;
+       } else {
+               fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
+       }
+
+       free(tmp2);
+       printf("passed. (%"PRIu64" ms) \n", msclock() - ms);
+free_tmp:
+       free(tmp);
+close:
+       crypto_pk_close(pk);
+
+out:
+       return ret;
+}
+
+static unsigned char message[4096 / 8] =
+       "aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
+       "ccccccccccccccccdddddddddddddddd"
+       "eeeeeeeeeeeeeeeeffffffffffffffff"
+       "gggggggggggggggghhhhhhhhhhhhhhhh"
+       "iiiiiiiiiiiiiiiijjjjjjjjjjjjjjjj"
+       "kkkkkkkkkkkkkkkkllllllllllllllll"
+       "mmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnn"
+       "oooooooooooooooopppppppppppppppp"
+       "qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr"
+       "sssssssssssssssstttttttttttttttt"
+       "uuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvv"
+       "wwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxx"
+       "yyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzz"
+       "aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
+       "ccccccccccccccccdddddddddddddddd"
+       "eeeeeeeeeeeeeeeeffffffffffffffff"
+       ;
+
+static unsigned char pk_N[] = {
+       0xdb, 0x12, 0xe4, 0xf1, 0x8d, 0x43, 0x74, 0xf0, 0xec, 0x38, 0xdc, 0xfb, 0xf9, 0x20, 0x75, 0x6d,
+       0x05, 0xf4, 0x36, 0xc2, 0x21, 0xac, 0x34, 0x0d, 0x16, 0xc5, 0x23, 0xcb, 0xfc, 0x9a, 0x8a, 0xd1,
+       0xe0, 0xbd, 0xda, 0xe5, 0x77, 0xd5, 0xaf, 0x65, 0x8d, 0x6b, 0x62, 0x5c, 0xcd, 0x89, 0x06, 0x8d,
+       0x11, 0x19, 0x6b, 0x0e, 0x3e, 0xe2, 0x80, 0x45, 0xf6, 0x44, 0x55, 0x21, 0x9c, 0x86, 0x90, 0x00,
+       0xa8, 0xaf, 0x8c, 0x94, 0xde, 0x3f, 0xe8, 0x56, 0x52, 0xfe, 0xee, 0xa5, 0x36, 0x72, 0x07, 0xf2,
+       0xcf, 0x8e, 0xf0, 0xbd, 0xff, 0x36, 0xd5, 0xf2, 0xad, 0x74, 0x1d, 0x17, 0xd0, 0xb7, 0x93, 0xe2,
+       0x2c, 0x8d, 0x3f, 0xb6, 0x7c, 0x65, 0x19, 0x9f, 0xa7, 0x80, 0x1f, 0x9f, 0xe5, 0x2f, 0x2d, 0x75,
+       0xc9, 0xc2, 0xe9, 0x70, 0xfa, 0x1e, 0x5a, 0xc6, 0xa3, 0x82, 0xd1, 0x29, 0x5a, 0x60, 0xce, 0x1f,
+       0x40, 0x2e, 0xfc, 0x2a, 0x5e, 0xde, 0xc9, 0x67, 0xfc, 0x45, 0x18, 0xce, 0xf2, 0x83, 0x94, 0x53,
+       0xd6, 0x4f, 0x2e, 0xc5, 0x2d, 0xa1, 0xa5, 0x7a, 0x63, 0x26, 0x70, 0xcb, 0x76, 0xfc, 0xb5, 0x8d,
+       0x0f, 0x88, 0x4c, 0x07, 0xba, 0xfa, 0x8b, 0xbc, 0xa0, 0xea, 0xea, 0x0a, 0xe6, 0xa5, 0x44, 0xa5,
+       0x0d, 0x12, 0x66, 0x2b, 0xf7, 0xc4, 0x76, 0xa3, 0x82, 0xa6, 0x2b, 0xb2, 0x5a, 0x27, 0xcd, 0x11,
+       0xd2, 0x9d, 0x42, 0x86, 0x8c, 0x82, 0xc8, 0xe1, 0xff, 0x7d, 0xf1, 0xd9, 0xd9, 0xa1, 0xf3, 0x3d,
+       0xc3, 0x12, 0x4e, 0x47, 0xc8, 0xa2, 0xcd, 0x72, 0x5a, 0x18, 0xea, 0x89, 0x5c, 0x73, 0x28, 0x52,
+       0xf8, 0xdb, 0x70, 0xdc, 0x92, 0xc9, 0xb7, 0x98, 0x10, 0x94, 0x79, 0xdc, 0x9e, 0x12, 0x6c, 0x14,
+       0x78, 0xf9, 0x5a, 0xad, 0x00, 0x98, 0xc8, 0x17, 0x79, 0x8a, 0xed, 0xe7, 0xc3, 0xd3, 0xa7, 0x8b,
+};
+
+static unsigned char pk_E[] = {
+       0x01, 0x00, 0x01,
+};
+
+static unsigned char pk_D[] = {
+       0x01, 0x17, 0xd4, 0x0a, 0x9c, 0x80, 0xd4, 0xa9, 0x8b, 0x14, 0x31, 0x8e, 0x14, 0x4d, 0x24, 0x28,
+       0xda, 0x19, 0xc0, 0xd8, 0x31, 0x20, 0xd1, 0xd5, 0xaa, 0xe2, 0x6a, 0xee, 0x4e, 0xa1, 0x5a, 0xc5,
+       0xf7, 0x50, 0x1b, 0x32, 0x7f, 0xe9, 0x92, 0x09, 0x78, 0xae, 0x2b, 0x7c, 0x79, 0x0e, 0x10, 0xf9,
+       0x4d, 0x37, 0x8a, 0x40, 0x34, 0xf2, 0x1e, 0x5f, 0xba, 0xfd, 0xd6, 0x4a, 0xe7, 0xa4, 0x08, 0x3d,
+       0xe8, 0x99, 0x8f, 0xa3, 0x02, 0x84, 0xe1, 0x1c, 0xe5, 0x27, 0x1e, 0x7b, 0xb6, 0x8c, 0xd5, 0x1b,
+       0x52, 0x0b, 0xcd, 0x89, 0xb5, 0x27, 0x49, 0xe3, 0xff, 0x17, 0x90, 0x39, 0x99, 0x32, 0x01, 0x4b,
+       0xe4, 0x9b, 0x03, 0xd1, 0x5e, 0x47, 0x86, 0xdc, 0x34, 0x12, 0xc0, 0x95, 0xa4, 0xa8, 0x1a, 0x9a,
+       0xf6, 0xd9, 0xc1, 0x1e, 0x6e, 0x31, 0x0e, 0x94, 0xe5, 0x25, 0xf6, 0xf3, 0x34, 0xdf, 0x3c, 0xc8,
+       0x0a, 0xc5, 0x8c, 0x00, 0x5c, 0x59, 0x55, 0x06, 0xd1, 0x39, 0x84, 0x35, 0x96, 0x40, 0xe8, 0xb2,
+       0xf7, 0x13, 0x83, 0x37, 0xe1, 0xe2, 0x79, 0x41, 0x90, 0x2a, 0xc3, 0x71, 0xc5, 0xcf, 0xf0, 0xaa,
+       0x01, 0x2f, 0x48, 0x9c, 0x3f, 0x29, 0x7b, 0xb7, 0x5c, 0xef, 0x25, 0xde, 0x34, 0x23, 0x81, 0x7a,
+       0x4c, 0x3a, 0x9b, 0xe4, 0xa7, 0x44, 0x73, 0xbf, 0xf7, 0x39, 0x43, 0xa4, 0x39, 0xa0, 0x1b, 0xf7,
+       0x4f, 0x5f, 0x14, 0x49, 0x32, 0x0e, 0x66, 0xd0, 0x29, 0xb5, 0x80, 0xe0, 0xba, 0x3b, 0x88, 0x2b,
+       0x14, 0xa4, 0x26, 0x00, 0x2f, 0x50, 0x20, 0x4e, 0xfa, 0xc2, 0x44, 0x72, 0x72, 0x6c, 0x2a, 0x77,
+       0x85, 0x20, 0xe0, 0x1d, 0x95, 0x6a, 0x66, 0xe7, 0xb8, 0xca, 0x5b, 0xc9, 0xc3, 0xf3, 0x39, 0xef,
+       0xd7, 0xd5, 0x45, 0xb6, 0x3e, 0x19, 0xea, 0x7c, 0x56, 0x20, 0x1b, 0x95, 0x86, 0x2e, 0xc7, 0x51,
+};
+
+static unsigned char pk_P[] = {
+       0xf5, 0x93, 0x0f, 0x76, 0x00, 0xab, 0x37, 0x01, 0xb9, 0x52, 0xb6, 0x82, 0xf9, 0xf5, 0xae, 0x29,
+       0x8f, 0xd5, 0x08, 0xbc, 0xf7, 0x9f, 0x84, 0xb6, 0x4c, 0x94, 0xb5, 0xfc, 0xfe, 0xe1, 0xcd, 0x6a,
+       0xf4, 0x9c, 0xa7, 0x33, 0xdb, 0xd8, 0xc8, 0xc1, 0xc0, 0x8d, 0x65, 0xed, 0x29, 0x99, 0x6c, 0x5c,
+       0xbe, 0x08, 0xac, 0x04, 0xe4, 0x3a, 0x18, 0xe2, 0x0f, 0x70, 0x26, 0x70, 0x9b, 0x71, 0xfc, 0x9f,
+       0x22, 0xea, 0x90, 0x3b, 0xc2, 0xa5, 0x16, 0x7a, 0xcd, 0x04, 0x3e, 0xa6, 0x37, 0x49, 0xa7, 0xee,
+       0xaa, 0xe4, 0x9d, 0xaa, 0x9b, 0xb0, 0xe2, 0x6a, 0x9d, 0x1e, 0xcd, 0x83, 0x4e, 0xd8, 0x59, 0x6d,
+       0x03, 0xd5, 0x4c, 0x5e, 0xc5, 0x22, 0x10, 0xb7, 0xcc, 0x0c, 0x90, 0x76, 0x05, 0x21, 0xe7, 0x77,
+       0x5c, 0x88, 0x5f, 0xd0, 0x5f, 0x9e, 0x2e, 0x49, 0x56, 0xf4, 0x2b, 0xa9, 0x99, 0x57, 0x74, 0x19,
+};
+
+static unsigned char pk_Q[] = {
+       0xe4, 0x5f, 0xd2, 0x28, 0xbd, 0xf3, 0xdd, 0x70, 0x3d, 0xfd, 0x01, 0x23, 0xae, 0x93, 0x6a, 0x91,
+       0xca, 0x68, 0xb1, 0xdb, 0x81, 0xab, 0x1e, 0x63, 0x76, 0x9b, 0x6d, 0xaa, 0x41, 0x87, 0x5a, 0x79,
+       0xe7, 0xce, 0xd6, 0x84, 0x32, 0x53, 0xf5, 0xfc, 0xb7, 0x41, 0x7c, 0xcb, 0x88, 0x09, 0xcb, 0xe9,
+       0x07, 0x16, 0x28, 0x55, 0x23, 0xe5, 0xf2, 0xf5, 0x23, 0xf5, 0xee, 0x2b, 0x9d, 0x91, 0x56, 0xc6,
+       0x30, 0x91, 0x4d, 0x16, 0x11, 0x6c, 0x48, 0x45, 0xe8, 0x5d, 0x0e, 0x9e, 0x04, 0xc8, 0xb6, 0xdd,
+       0xba, 0x0d, 0xdf, 0x53, 0x56, 0xfa, 0x0b, 0x0b, 0x99, 0x8d, 0xea, 0x5c, 0x45, 0x7d, 0xed, 0xad,
+       0x1f, 0xc5, 0xc1, 0x7d, 0x63, 0x31, 0xf8, 0x32, 0xb5, 0x33, 0xb0, 0xef, 0xce, 0x2e, 0x74, 0x1e,
+       0x77, 0x2a, 0x18, 0x35, 0x3d, 0x6e, 0x01, 0xba, 0xde, 0x21, 0x8e, 0x14, 0x12, 0xc3, 0x0d, 0x43,
+};
+
+static unsigned char pk_dP[] = {
+       0x5a, 0xc8, 0xf7, 0x1a, 0x44, 0xbd, 0x07, 0x24, 0xd8, 0x02, 0x3f, 0xfe, 0xc3, 0xb1, 0x93, 0xa5,
+       0x41, 0xcb, 0x1b, 0xe3, 0xe0, 0x17, 0x54, 0xd4, 0xa0, 0x13, 0x0a, 0x04, 0x71, 0xa5, 0xc0, 0x6f,
+       0x1d, 0xe7, 0x1b, 0xd9, 0x0c, 0x19, 0x64, 0x7e, 0x5c, 0x54, 0xe9, 0xad, 0x77, 0x87, 0x84, 0x8b,
+       0xf4, 0xa4, 0xf8, 0x13, 0x06, 0xdc, 0x83, 0x7e, 0x6e, 0xfe, 0xa2, 0xf7, 0x56, 0x40, 0x19, 0x88,
+       0x2b, 0x3c, 0x53, 0xfe, 0x03, 0xc3, 0x4c, 0x40, 0x31, 0xb2, 0xb4, 0x06, 0x76, 0xc2, 0x00, 0x17,
+       0x37, 0x8e, 0x34, 0xcb, 0x71, 0xab, 0x3e, 0xc8, 0xf3, 0x35, 0x03, 0xfc, 0xdb, 0x15, 0x18, 0x5a,
+       0x38, 0xe4, 0x8d, 0xcb, 0x2b, 0x4d, 0xa0, 0xa8, 0x92, 0x02, 0xc3, 0x15, 0x1e, 0x68, 0x9e, 0x4d,
+       0x7e, 0x23, 0xdc, 0x68, 0x08, 0x31, 0x4e, 0x23, 0x46, 0xc6, 0x15, 0xae, 0x29, 0x46, 0x2f, 0x61,
+};
+
+static unsigned char pk_dQ[] = {
+       0x33, 0x61, 0x9f, 0xae, 0x0c, 0xf6, 0xc6, 0x16, 0x8f, 0xcb, 0xd1, 0xaa, 0xce, 0x87, 0x5a, 0x4d,
+       0xcc, 0xe5, 0x7b, 0x46, 0xb0, 0xc8, 0xe8, 0x40, 0x66, 0x9a, 0x17, 0xb5, 0x5b, 0xa2, 0xf1, 0x67,
+       0x46, 0x11, 0x52, 0x50, 0x51, 0xe6, 0x74, 0x0c, 0xd4, 0xca, 0x46, 0x22, 0xa0, 0xcb, 0xdb, 0x75,
+       0xe5, 0x63, 0x45, 0xd5, 0xca, 0x0a, 0xdd, 0x7b, 0xec, 0x08, 0x53, 0xfa, 0xba, 0x2b, 0xce, 0x03,
+       0x2f, 0x40, 0x31, 0xc0, 0xca, 0x50, 0xbb, 0x7e, 0x07, 0x06, 0x90, 0xd8, 0x5a, 0xa9, 0x32, 0x03,
+       0x76, 0xed, 0xd2, 0x16, 0x35, 0x16, 0x72, 0xcf, 0xbc, 0x4f, 0xa2, 0xaf, 0xf9, 0xee, 0x98, 0x40,
+       0x00, 0x4b, 0x04, 0xfa, 0x8a, 0x0b, 0xdf, 0x14, 0xc1, 0x92, 0x0c, 0xb8, 0x17, 0x82, 0x7a, 0x1b,
+       0xb4, 0xa1, 0xe2, 0xea, 0x6f, 0x94, 0xc5, 0x8c, 0xde, 0x97, 0x5c, 0x19, 0x06, 0x13, 0x9e, 0x73,
+};
+
+static unsigned char pk_I[] = {
+       0x75, 0x40, 0xc6, 0x02, 0x7e, 0x4f, 0xad, 0xdb, 0x95, 0xac, 0x07, 0x8d, 0x80, 0xb6, 0x80, 0x02,
+       0x06, 0xdd, 0xb8, 0x5d, 0x92, 0x65, 0x69, 0x26, 0x86, 0x61, 0x6c, 0x87, 0x4e, 0xe5, 0x03, 0x68,
+       0xc6, 0x10, 0x15, 0x8c, 0x43, 0x3a, 0x45, 0x63, 0x48, 0xb7, 0x8a, 0x8c, 0xa2, 0x2b, 0x34, 0xb6,
+       0x83, 0xfe, 0xa8, 0x10, 0xa5, 0x74, 0xa5, 0xa9, 0x52, 0x42, 0x1f, 0xa0, 0x80, 0x6a, 0xc5, 0x35,
+       0xe8, 0xb8, 0xc2, 0xa0, 0x3f, 0x49, 0x18, 0xcf, 0x0e, 0x54, 0x3c, 0x70, 0x11, 0x11, 0xd3, 0x85,
+       0x8c, 0xb2, 0xe5, 0x74, 0xdf, 0x98, 0xea, 0x6c, 0xc0, 0x5f, 0x7f, 0xff, 0x69, 0xbf, 0x08, 0x8d,
+       0x1b, 0xc4, 0x90, 0xcc, 0xa4, 0xcd, 0xcc, 0x34, 0x58, 0xe5, 0x91, 0x53, 0x3a, 0xd5, 0x39, 0xf4,
+       0xd4, 0x42, 0xc9, 0x17, 0xb2, 0x2c, 0x92, 0x12, 0x37, 0x1b, 0xd3, 0xc5, 0x79, 0xd2, 0x65, 0x61,
+};
+
+static int test_pk(bool verbose)
+{
+       int ret = 1;
+       size_t tmp_len, tmp2_len;
+       unsigned char *tmp, *tmp2;
+       struct crypto_pk *pubk, *privk;
+       unsigned char *msg = message;
+       size_t msg_len = sizeof(pk_N);
+
+       printf("Testing public keys interfaces\n");
+
+       pubk = crypto_pk_open(PK_RSA,
+                       pk_N, sizeof(pk_N),
+                       pk_E, sizeof(pk_E));
+       if (!pubk) {
+               fprintf(stderr, "ERROR: open public key.\n");
+               return 1;
+       }
+
+       tmp_len = crypto_pk_get_nbits(pubk);
+       if (tmp_len != sizeof(pk_N) * 8) {
+               fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
+               goto close_pub;
+       }
+
+       tmp = crypto_pk_get_parameter(pubk, 0, &tmp_len);
+       if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
+               fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %d len %d\n", tmp_len, sizeof(pk_N));
+               free(tmp);
+               goto close_pub;
+       }
+       free(tmp);
+
+       tmp = crypto_pk_get_parameter(pubk, 1, &tmp_len);
+       if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
+               fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
+               free(tmp);
+               goto close_pub;
+       }
+       free(tmp);
+
+       privk = crypto_pk_open_priv(PK_RSA,
+                       pk_N, sizeof(pk_N),
+                       pk_E, sizeof(pk_E),
+                       pk_D, sizeof(pk_D),
+                       pk_P, sizeof(pk_P),
+                       pk_Q, sizeof(pk_Q),
+                       pk_dP, sizeof(pk_dP),
+                       pk_dQ, sizeof(pk_dQ),
+                       pk_I, sizeof(pk_I));
+       if (!privk) {
+               fprintf(stderr, "ERROR: open private key.\n");
+               goto close_pub;
+       }
+
+
+       tmp_len = crypto_pk_get_nbits(privk);
+       if (tmp_len != sizeof(pk_N) * 8) {
+               fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
+               goto close_pub;
+       }
+
+       tmp = crypto_pk_get_parameter(privk, 0, &tmp_len);
+       if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
+               fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %d len %d\n", tmp_len, sizeof(pk_N));
+               free(tmp);
+               goto close;
+       }
+       free(tmp);
+
+       tmp = crypto_pk_get_parameter(privk, 1, &tmp_len);
+       if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
+               fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
+               free(tmp);
+               goto close;
+       }
+       free(tmp);
+
+       tmp = crypto_pk_decrypt(privk, msg, msg_len, &tmp_len);
+       if (!tmp) {
+               fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
+               goto close;
+       }
+
+       tmp2 = crypto_pk_encrypt(pubk, tmp, tmp_len, &tmp2_len);
+       if (!tmp2) {
+               fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
+               goto free_tmp;
+       }
+
+       if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
+               ret = 0;
+       } else {
+               fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
+       }
+
+       free(tmp2);
+free_tmp:
+       free(tmp);
+
+close:
+       crypto_pk_close(privk);
+close_pub:
+       crypto_pk_close(pubk);
+
+       return ret;
+}
+
+int exec_crypto_test(bool verbose)
+{
+       unsigned int keylengths[] = {1024, 1152, 1408, 1984, 2048, 3072, 4096};
+       int i;
+       int ret;
+       fprintf(stdout, "\n");
+
+       ret = test_pk(verbose);
+       if (ret) {
+               fprintf(stderr, "Crypto raw test: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "Crypto raw test: passed\n\n");
+
+       for (i = 0; i < sizeof(keylengths) / sizeof(keylengths[0]); i++) {
+               unsigned int kl = keylengths[i];
+               ret = test_genkey(kl, message, kl / 8, verbose);
+               if (ret) {
+                       fprintf(stderr, "Crypto generate key[%d] test: failed\n", kl);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
diff --git a/client/emv/test/crypto_test.h b/client/emv/test/crypto_test.h
new file mode 100644 (file)
index 0000000..084bc99
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+ #include <stdbool.h>
+
+extern int exec_crypto_test(bool verbose);
diff --git a/client/emv/test/cryptotest.c b/client/emv/test/cryptotest.c
new file mode 100644 (file)
index 0000000..a6d06e6
--- /dev/null
@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2017 Merlok
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Crypto algorithms testing
+//-----------------------------------------------------------------------------
+
+#include "cryptotest.h"
+#include "util.h"
+#include "ui.h"
+
+#include "bignum.h"
+#include "aes.h"
+#include "des.h"
+#include "rsa.h"
+#include "sha1.h"
+
+#include "crypto_test.h"
+#include "sda_test.h"
+#include "dda_test.h"
+#include "cda_test.h"
+
+int ExecuteCryptoTests(bool verbose) {
+       int res;
+       bool TestFail = false;
+       
+       res = mpi_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = aes_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = des_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = sha1_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = rsa_self_test(verbose);
+       if (res) TestFail = true;
+       
+       res = exec_sda_test(verbose);
+       if (res) TestFail = true;
+
+       res = exec_dda_test(verbose);
+       if (res) TestFail = true;
+       
+       res = exec_cda_test(verbose);
+       if (res) TestFail = true;
+
+       res = exec_crypto_test(verbose);
+       if (res) TestFail = true;
+
+       PrintAndLog("\n--------------------------");
+       if (TestFail)
+               PrintAndLog("Test(s) [ERROR].");
+       else
+               PrintAndLog("Tests [OK].");
+       
+       return TestFail;
+}
+
diff --git a/client/emv/test/cryptotest.h b/client/emv/test/cryptotest.h
new file mode 100644 (file)
index 0000000..5c6aaae
--- /dev/null
@@ -0,0 +1,13 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2017 Merlok
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Crypto algorithms testing
+//-----------------------------------------------------------------------------
+
+#include <stdbool.h>
+
+extern int ExecuteCryptoTests(bool verbose);
diff --git a/client/emv/test/dda_test.c b/client/emv/test/dda_test.c
new file mode 100644 (file)
index 0000000..afdd4e2
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "dda_test.h"
+
+#include "../emv_pk.h"
+#include "../crypto.h"
+#include "../dump.h"
+#include "../tlv.h"
+#include "../emv_pki.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct emv_pk mchip_05 = {
+       .rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
+       .index = 5,
+       .hash_algo = HASH_SHA_1,
+       .pk_algo = PK_RSA,
+       .hash = {
+               0xeb, 0xfa, 0x0d, 0x5d,
+               0x06, 0xd8, 0xce, 0x70,
+               0x2d, 0xa3, 0xea, 0xe8,
+               0x90, 0x70, 0x1d, 0x45,
+               0xe2, 0x74, 0xc8, 0x45, },
+       .exp = { 0x03, },
+       .elen = 1,
+       .mlen = 1408 / 8,
+       .modulus = (unsigned char[]){
+               0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
+               0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
+               0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
+               0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
+               0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
+               0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
+               0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
+               0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
+               0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
+               0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
+               0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
+       },
+};
+
+const unsigned char d_issuer_cert[] = {
+               0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
+               0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
+               0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
+               0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
+               0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
+               0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
+               0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
+               0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
+               0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
+               0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
+               0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
+};
+
+const unsigned char d_issuer_rem[] = {
+               0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
+               0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
+               0x6d, 0xbd, 0x64, 0x15,
+};
+
+const unsigned char d_issuer_exp[] = {
+               0x03,
+};
+
+const unsigned char d_icc_cert[] = {
+               0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
+               0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
+               0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
+               0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
+               0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
+               0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
+               0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
+               0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
+               0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
+               0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
+               0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
+};
+
+const unsigned char d_icc_exp[] = {
+               0x03,
+};
+
+const unsigned char d_sdad_cr[] = {
+       0x3d, 0x87, 0xf3, 0x10, 0x56, 0x10, 0x2d, 0x25, 0x12, 0xcf, 0xde, 0x30, 0x90, 0x06, 0x27, 0xc1,
+       0x26, 0x3a, 0x76, 0xd1, 0xda, 0xa8, 0x21, 0xf5, 0x08, 0x31, 0xe6, 0x06, 0xc5, 0x45, 0x44, 0xc2,
+       0x58, 0x13, 0x1e, 0xae, 0xbe, 0x87, 0x4d, 0xcb, 0x1a, 0x28, 0xcf, 0x82, 0xd3, 0xff, 0x91, 0x11,
+       0x82, 0x60, 0xbc, 0x91, 0x11, 0x37, 0x11, 0xd3, 0xb2, 0x89, 0xfa, 0x41, 0xbe, 0x69, 0xc7, 0xa7,
+       0xb5, 0xc7, 0x83, 0xe6, 0xf8, 0xf9, 0x7f, 0xce, 0x13, 0xf0, 0x8b, 0x13, 0xfa, 0x44, 0x18, 0x3e,
+       0x37, 0x18, 0xce, 0xbf, 0x0c, 0x41, 0x47, 0x3d, 0x2b, 0x0f, 0xf4, 0xde, 0x44, 0xb6, 0xa0, 0x2d,
+       0x75, 0xad, 0xb6, 0xd4, 0x96, 0x23, 0x93, 0xff, 0xdf, 0x4e, 0x69, 0x02, 0x6c, 0xdf, 0x38, 0xff,
+};
+
+const unsigned char d_ssd1[] = {
+       0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
+       0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
+       0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
+       0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
+       0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
+       0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
+       0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
+       0x39, 0x00,
+};
+static const struct tlv ssd1_tlv = {
+       .len = sizeof(d_ssd1),
+       .value = d_ssd1,
+};
+
+const unsigned char d_pan[] = {
+       0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
+};
+
+const unsigned char d_dd1[] = {
+       0x00, 0x00, 0x00, 0x00,
+};
+static const struct tlv dd1_tlv = {
+       .len = sizeof(d_dd1),
+       .value = d_dd1,
+};
+
+static int dda_test_raw(bool verbose)
+{
+       const struct emv_pk *pk = &mchip_05;
+
+       struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
+                       pk->modulus, pk->mlen,
+                       pk->exp, pk->elen);
+       if (!kcp)
+               return 1;
+
+       unsigned char *ipk_data;
+       size_t ipk_data_len;
+       ipk_data = crypto_pk_encrypt(kcp, d_issuer_cert, sizeof(d_issuer_cert), &ipk_data_len);
+       crypto_pk_close(kcp);
+
+       if (!ipk_data)
+               return 1;
+
+       if (verbose) {
+               printf("issuer cert:\n");
+               dump_buffer(ipk_data, ipk_data_len, stdout, 0);
+       }
+
+       size_t ipk_pk_len = ipk_data[13];
+       unsigned char *ipk_pk = malloc(ipk_pk_len);
+       memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
+       memcpy(ipk_pk + ipk_data_len - 36, d_issuer_rem, sizeof(d_issuer_rem));
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, ipk_data + 1, 14);
+       crypto_hash_write(ch, ipk_pk, ipk_pk_len);
+       crypto_hash_write(ch, d_issuer_exp, sizeof(d_issuer_exp));
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(ipk_data);
+
+       struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
+                       d_issuer_exp, (int) sizeof(d_issuer_exp));
+       free(ipk_pk);
+       if (!ikcp)
+               return 1;
+
+       unsigned char *iccpk_data;
+       size_t iccpk_data_len;
+       iccpk_data = crypto_pk_encrypt(ikcp, d_icc_cert, sizeof(d_icc_cert), &iccpk_data_len);
+       crypto_pk_close(ikcp);
+
+       if (!iccpk_data)
+               return 1;
+
+       if (verbose) {
+               printf("icc cert:\n");
+               dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
+       }
+
+       size_t iccpk_pk_len = iccpk_data[19];
+       unsigned char *iccpk_pk = malloc(iccpk_pk_len);
+       memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
+       /*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
+       crypto_hash_write(ch, d_icc_exp, sizeof(d_icc_exp));
+       crypto_hash_write(ch, d_ssd1, sizeof(d_ssd1));
+
+       h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash1.1:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(iccpk_pk);
+               free(iccpk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(iccpk_data);
+
+       struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
+                       d_issuer_exp, (int) sizeof(d_issuer_exp));
+       free(iccpk_pk);
+       if (!icckcp)
+               return 1;
+
+       size_t sdad_len;
+       unsigned char *sdad = crypto_pk_encrypt(icckcp, d_sdad_cr, sizeof(d_sdad_cr), &sdad_len);
+       crypto_pk_close(icckcp);
+       if (!sdad)
+               return 1;
+
+       if (verbose) {
+               printf("sdad:\n");
+               dump_buffer(sdad, sdad_len, stdout, 0);
+       }
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(sdad);
+               return 1;
+       }
+
+       crypto_hash_write(ch, sdad + 1, sdad_len - 22);
+       crypto_hash_write(ch, d_dd1, sizeof(d_dd1));
+
+       unsigned char *h2 = crypto_hash_read(ch);
+       if (!h2) {
+               crypto_hash_close(ch);
+               free(sdad);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash2:\n");
+               dump_buffer(h2, 20, stdout, 0);
+       }
+
+       crypto_hash_close(ch);
+
+       free(sdad);
+
+       return 0;
+}
+
+static int dda_test_pk(bool verbose)
+{
+       const struct emv_pk *pk = &mchip_05;
+       struct tlvdb *db;
+
+       db = tlvdb_external(0x90, sizeof(d_issuer_cert), d_issuer_cert);
+       tlvdb_add(db, tlvdb_external(0x9f32, sizeof(d_issuer_exp), d_issuer_exp));
+       tlvdb_add(db, tlvdb_external(0x92, sizeof(d_issuer_rem), d_issuer_rem));
+       tlvdb_add(db, tlvdb_external(0x5a, sizeof(d_pan), d_pan));
+
+       struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
+       if (!ipk) {
+               fprintf(stderr, "Could not recover Issuer certificate!\n");
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_external(0x9f46, sizeof(d_icc_cert), d_icc_cert));
+       tlvdb_add(db, tlvdb_external(0x9f47, sizeof(d_icc_exp), d_icc_exp));
+       /*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(d_issuer_rem), d_issuer_rem));*/
+
+       struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
+       if (!iccpk) {
+               fprintf(stderr, "Could not recover ICC certificate!\n");
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_external(0x9f4b, sizeof(d_sdad_cr), d_sdad_cr));
+
+       struct tlvdb *idndb = emv_pki_recover_idn(iccpk, db, &dd1_tlv);
+       if (!idndb) {
+               fprintf(stderr, "Could not recover IDN!\n");
+               emv_pk_free(iccpk);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
+       if (!idn) {
+               fprintf(stderr, "IDN not found!\n");
+               tlvdb_free(idndb);
+               emv_pk_free(iccpk);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       if (verbose) {
+               printf("IDN:\n");
+               dump_buffer(idn->value, idn->len, stdout, 0);
+       }
+
+       tlvdb_free(idndb);
+       emv_pk_free(iccpk);
+       emv_pk_free(ipk);
+       tlvdb_free(db);
+
+       return 0;
+}
+
+int exec_dda_test(bool verbose)
+{
+       int ret;
+       fprintf(stdout, "\n");
+
+       ret = dda_test_raw(verbose);
+       if (ret) {
+               fprintf(stderr, "DDA raw test: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "DDA raw test: passed\n");
+
+       ret = dda_test_pk(verbose);
+       if (ret) {
+               fprintf(stderr, "DDA test pk: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "DDA test pk: passed\n");
+
+       return 0;
+}
diff --git a/client/emv/test/dda_test.h b/client/emv/test/dda_test.h
new file mode 100644 (file)
index 0000000..354cd7e
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include <stdbool.h> 
+extern int exec_dda_test(bool verbose);
diff --git a/client/emv/test/sda_test.c b/client/emv/test/sda_test.c
new file mode 100644 (file)
index 0000000..2aafcf1
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../emv_pk.h"
+#include "../crypto.h"
+#include "../dump.h"
+#include "../tlv.h"
+#include "../emv_pki.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct emv_pk vsdc_01 = {
+       .rid = { 0xa0, 0x00, 0x00, 0x00, 0x03, },
+       .index = 1,
+       .hash_algo = HASH_SHA_1,
+       .pk_algo = PK_RSA,
+       .hash = {
+               0xd3, 0x4a, 0x6a, 0x77,
+               0x60, 0x11, 0xc7, 0xe7,
+               0xce, 0x3a, 0xec, 0x5f,
+               0x03, 0xad, 0x2f, 0x8c,
+               0xfc, 0x55, 0x03, 0xcc, },
+       .exp = { 0x03, },
+       .elen = 1,
+       .mlen = 1024 / 8,
+       .modulus = (unsigned char[]){
+               0xc6, 0x96, 0x03, 0x42, 0x13, 0xd7, 0xd8, 0x54, 0x69, 0x84, 0x57, 0x9d, 0x1d, 0x0f, 0x0e, 0xa5,
+               0x19, 0xcf, 0xf8, 0xde, 0xff, 0xc4, 0x29, 0x35, 0x4c, 0xf3, 0xa8, 0x71, 0xa6, 0xf7, 0x18, 0x3f,
+               0x12, 0x28, 0xda, 0x5c, 0x74, 0x70, 0xc0, 0x55, 0x38, 0x71, 0x00, 0xcb, 0x93, 0x5a, 0x71, 0x2c,
+               0x4e, 0x28, 0x64, 0xdf, 0x5d, 0x64, 0xba, 0x93, 0xfe, 0x7e, 0x63, 0xe7, 0x1f, 0x25, 0xb1, 0xe5,
+               0xf5, 0x29, 0x85, 0x75, 0xeb, 0xe1, 0xc6, 0x3a, 0xa6, 0x17, 0x70, 0x69, 0x17, 0x91, 0x1d, 0xc2,
+               0xa7, 0x5a, 0xc2, 0x8b, 0x25, 0x1c, 0x7e, 0xf4, 0x0f, 0x23, 0x65, 0x91, 0x24, 0x90, 0xb9, 0x39,
+               0xbc, 0xa2, 0x12, 0x4a, 0x30, 0xa2, 0x8f, 0x54, 0x40, 0x2c, 0x34, 0xae, 0xca, 0x33, 0x1a, 0xb6,
+               0x7e, 0x1e, 0x79, 0xb2, 0x85, 0xdd, 0x57, 0x71, 0xb5, 0xd9, 0xff, 0x79, 0xea, 0x63, 0x0b, 0x75,
+       },
+};
+
+const unsigned char issuer_cert[] = {
+               0x3c, 0x5f, 0xea, 0xd4, 0xdd, 0x7b, 0xca, 0x44, 0xf9, 0x3e, 0x90, 0xc4, 0x4f, 0x76, 0xed, 0xe5,
+               0x4a, 0x32, 0x88, 0xec, 0xdc, 0x78, 0x46, 0x9f, 0xcb, 0x12, 0x25, 0xc0, 0x3b, 0x2c, 0x04, 0xf2,
+               0xc2, 0xf4, 0x12, 0x28, 0x1a, 0x08, 0x22, 0xdf, 0x14, 0x64, 0x92, 0x30, 0x98, 0x9f, 0xb1, 0x49,
+               0x40, 0x70, 0xda, 0xf8, 0xc9, 0x53, 0x4a, 0x78, 0x81, 0x96, 0x01, 0x48, 0x61, 0x6a, 0xce, 0x58,
+               0x17, 0x88, 0x12, 0x0d, 0x35, 0x06, 0xac, 0xe4, 0xce, 0xe5, 0x64, 0xfb, 0x27, 0xee, 0x53, 0x34,
+               0x1c, 0x22, 0xf0, 0xb4, 0x5b, 0x31, 0x87, 0x3d, 0x05, 0xde, 0x54, 0x5e, 0xfe, 0x33, 0xbc, 0xd2,
+               0x9b, 0x21, 0x85, 0xd0, 0x35, 0xa8, 0x06, 0xad, 0x08, 0xc6, 0x97, 0x6f, 0x35, 0x05, 0xa1, 0x99,
+               0x99, 0x93, 0x0c, 0xa8, 0xa0, 0x3e, 0xfa, 0x32, 0x1c, 0x48, 0x60, 0x61, 0xf7, 0xdc, 0xec, 0x9f,
+};
+
+const unsigned char issuer_rem[] = {
+               0x1e, 0xbc, 0xa3, 0x0f, 0x00, 0xce, 0x59, 0x62, 0xa8, 0xc6, 0xe1, 0x30, 0x54, 0x4b, 0x82, 0x89,
+               0x1b, 0x23, 0x6c, 0x65, 0xde, 0x29, 0x31, 0x7f, 0x36, 0x47, 0x35, 0xde, 0xe6, 0x3f, 0x65, 0x98,
+               0x97, 0x58, 0x35, 0xd5
+};
+
+const unsigned char issuer_exp[] = {
+               0x03,
+};
+
+const unsigned char ssad_cr[] = {
+               0x99, 0xa5, 0x58, 0xb6, 0x2b, 0x67, 0x4a, 0xa5, 0xe7, 0xd2, 0xa5, 0x7e, 0x5e, 0xf6, 0xa6, 0xf2,
+               0x25, 0x8e, 0x5d, 0xa0, 0x52, 0xd0, 0x5b, 0x54, 0xe5, 0xc1, 0x15, 0xff, 0x1c, 0xec, 0xf9, 0x4a,
+               0xa2, 0xdf, 0x8f, 0x39, 0xa0, 0x1d, 0x71, 0xc6, 0x19, 0xeb, 0x81, 0x9d, 0xa5, 0x2e, 0xf3, 0x81,
+               0xe8, 0x49, 0x79, 0x58, 0x6a, 0xea, 0x78, 0x55, 0xff, 0xbe, 0xf4, 0x0a, 0xa3, 0xa7, 0x1c, 0xd3,
+               0xb0, 0x4c, 0xfd, 0xf2, 0x70, 0xae, 0xc8, 0x15, 0x8a, 0x27, 0x97, 0xf2, 0x4f, 0xd6, 0x13, 0xb7,
+               0x48, 0x13, 0x46, 0x61, 0x13, 0x5c, 0xd2, 0x90, 0xe4, 0x5b, 0x04, 0xa8, 0xe0, 0xcc, 0xc7, 0x11,
+               0xae, 0x04, 0x2f, 0x15, 0x9e, 0x73, 0xc8, 0x9c, 0x2a, 0x7e, 0x65, 0xa4, 0xc2, 0xfd, 0x1d, 0x61,
+               0x06, 0x02, 0x4a, 0xa2, 0x71, 0x30, 0xb0, 0xec, 0xec, 0x02, 0x38, 0xf9, 0x16, 0x59, 0xde, 0x96,
+};
+
+const unsigned char ssd1[] = {
+       0x5f, 0x24, 0x03, 0x08, 0x12, 0x31, 0x5a, 0x08, 0x42, 0x76, 0x55, 0x00, 0x13, 0x23, 0x45, 0x99, 0x5f, 0x34, 0x01, 0x01, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05, 0xd0, 0x40, 0xac, 0xa8, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05, 0xd0, 0x68, 0xbc, 0xf8, 0x00,
+       0x5c, 0x00,
+};
+static const struct tlv ssd1_tlv = {
+       .len = sizeof(ssd1),
+       .value = ssd1,
+};
+
+const unsigned char pan[] = {
+       0x42, 0x76, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static int sda_test_raw(bool verbose)
+{
+       const struct emv_pk *pk = &vsdc_01;
+
+       struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
+                       pk->modulus, pk->mlen,
+                       pk->exp, pk->elen);
+       if (!kcp)
+               return 1;
+
+       unsigned char *ipk_data;
+       size_t ipk_data_len;
+       ipk_data = crypto_pk_encrypt(kcp, issuer_cert, sizeof(issuer_cert), &ipk_data_len);
+       crypto_pk_close(kcp);
+
+       if (!ipk_data)
+               return 1;
+
+       if (verbose) {
+               printf("issuer cert:\n");
+               dump_buffer(ipk_data, ipk_data_len, stdout, 0);
+       }
+
+       size_t ipk_pk_len = ipk_data[13];
+       unsigned char *ipk_pk = malloc(ipk_pk_len);
+       memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
+       memcpy(ipk_pk + ipk_data_len - 36, issuer_rem, sizeof(issuer_rem));
+
+       struct crypto_hash *ch;
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_write(ch, ipk_data + 1, 14);
+       crypto_hash_write(ch, ipk_pk, ipk_pk_len);
+       crypto_hash_write(ch, issuer_exp, sizeof(issuer_exp));
+
+       unsigned char *h = crypto_hash_read(ch);
+       if (!h) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash:\n");
+               dump_buffer(h, 20, stdout, 0);
+       }
+
+       if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
+               crypto_hash_close(ch);
+               free(ipk_pk);
+               free(ipk_data);
+               return 1;
+       }
+
+       crypto_hash_close(ch);
+       free(ipk_data);
+
+       struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
+                       issuer_exp, (int) sizeof(issuer_exp));
+       free(ipk_pk);
+       if (!ikcp)
+               return 1;
+
+       size_t ssad_len;
+       unsigned char *ssad = crypto_pk_encrypt(ikcp, ssad_cr, sizeof(ssad_cr), &ssad_len);
+       crypto_pk_close(ikcp);
+       if (!ssad)
+               return 1;
+
+       if (verbose) {
+               printf("ssad:\n");
+               dump_buffer(ssad, ssad_len, stdout, 0);
+       }
+
+       ch = crypto_hash_open(HASH_SHA_1);
+       if (!ch) {
+               free(ssad);
+               return 1;
+       }
+
+       crypto_hash_write(ch, ssad + 1, ssad_len - 22);
+       crypto_hash_write(ch, ssd1, sizeof(ssd1));
+
+       unsigned char *h2 = crypto_hash_read(ch);
+       if (!h2) {
+               crypto_hash_close(ch);
+               free(ssad);
+               return 1;
+       }
+
+       if (verbose) {
+               printf("crypto hash2:\n");
+               dump_buffer(h2, 20, stdout, 0);
+       }
+
+       crypto_hash_close(ch);
+
+       free(ssad);
+
+       return 0;
+}
+
+static int sda_test_pk(bool verbose)
+{
+       const struct emv_pk *pk = &vsdc_01;
+       struct tlvdb *db;
+
+       db = tlvdb_external(0x90, sizeof(issuer_cert), issuer_cert);
+       tlvdb_add(db, tlvdb_external(0x9f32, sizeof(issuer_exp), issuer_exp));
+       tlvdb_add(db, tlvdb_external(0x92, sizeof(issuer_rem), issuer_rem));
+       tlvdb_add(db, tlvdb_external(0x5a, sizeof(pan), pan));
+
+       struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
+       if (!ipk) {
+               fprintf(stderr, "Could not recover Issuer certificate!\n");
+               tlvdb_free(db);
+               return 2;
+       }
+
+       tlvdb_add(db, tlvdb_external(0x93, sizeof(ssad_cr), ssad_cr));
+
+       struct tlvdb *dacdb = emv_pki_recover_dac(ipk, db, &ssd1_tlv);
+       if (!dacdb) {
+               fprintf(stderr, "Could not recover DAC!\n");
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       const struct tlv *dac = tlvdb_get(dacdb, 0x9f45, NULL);
+       if (!dac) {
+               fprintf(stderr, "DAC not found!\n");
+               tlvdb_free(dacdb);
+               emv_pk_free(ipk);
+               tlvdb_free(db);
+               return 2;
+       }
+
+       if (verbose) {
+               printf("dac:\n");
+               dump_buffer(dac->value, dac->len, stdout, 0);
+       }
+
+       tlvdb_free(dacdb);
+       emv_pk_free(ipk);
+       tlvdb_free(db);
+
+       return 0;
+}
+
+int exec_sda_test(bool verbose)
+{
+       int ret;
+       fprintf(stdout, "\n");
+
+       ret = sda_test_raw(verbose);
+       if (ret) {
+               fprintf(stderr, "SDA raw test: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "SDA raw test: passed\n");
+
+       ret = sda_test_pk(verbose);
+       if (ret) {
+               fprintf(stderr, "SDA test pk: failed\n");
+               return ret;
+       }
+       fprintf(stdout, "SDA test pk: passed\n");
+
+       return 0;
+}
diff --git a/client/emv/test/sda_test.h b/client/emv/test/sda_test.h
new file mode 100644 (file)
index 0000000..43a4c94
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * emv-tools - a set of tools to work with EMV family of smart cards
+ * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+extern int exec_sda_test(bool verbose);
diff --git a/client/obj/emv/test/.dummy b/client/obj/emv/test/.dummy
new file mode 100644 (file)
index 0000000..e69de29
index 13cb8cdfcb1c998fdb09a773c8904a8262e4f74a..3859fd4863ce35fbc4942c5e326568a651ce403c 100644 (file)
@@ -23,8 +23,8 @@
 #include "iso14443crc.h"
 #include "../common/crc16.h"
 #include "../common/crc64.h"
-#include "../common/sha1.h"
-#include "polarssl/aes.h"
+#include "../common/polarssl/sha1.h"
+#include "../common/polarssl/aes.h"
 #include "cmdcrc.h"
 /**
  * The following params expected:
index 946bd87d92c0fb43e0290540892a5354c79fcaea..299cb4cdfe3d02b89641eceea2404e78e22e8585 100644 (file)
@@ -125,7 +125,6 @@ int aes_crypt_ecb( aes_context *ctx,
                     int mode,
                     const unsigned char input[16],
                     unsigned char output[16] );
-
 #if defined(POLARSSL_CIPHER_MODE_CBC)
 /**
  * \brief          AES-CBC buffer encryption/decryption
diff --git a/common/polarssl/bignum.c b/common/polarssl/bignum.c
new file mode 100644 (file)
index 0000000..d22dd5c
--- /dev/null
@@ -0,0 +1,2143 @@
+/*
+ *  Multi-precision integer library
+ *
+ *  Copyright (C) 2006-2010, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  This MPI implementation is based on:
+ *
+ *  http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
+ *  http://www.stillhq.com/extracted/gnupg-api/mpi/
+ *  http://math.libtomcrypt.com/files/tommath.pdf
+ */
+
+#include "polarssl_config.h"
+
+#if defined(POLARSSL_BIGNUM_C)
+
+#include "bignum.h"
+#include "bn_mul.h"
+
+#include <stdlib.h>
+
+#define ciL    (sizeof(t_uint))         /* chars in limb  */
+#define biL    (ciL << 3)               /* bits  in limb  */
+#define biH    (ciL << 2)               /* half limb size */
+
+/*
+ * Convert between bits/chars and number of limbs
+ */
+#define BITS_TO_LIMBS(i)  (((i) + biL - 1) / biL)
+#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL)
+
+/*
+ * Initialize one MPI
+ */
+void mpi_init( mpi *X )
+{
+    if( X == NULL )
+        return;
+
+    X->s = 1;
+    X->n = 0;
+    X->p = NULL;
+}
+
+/*
+ * Unallocate one MPI
+ */
+void mpi_free( mpi *X )
+{
+    if( X == NULL )
+        return;
+
+    if( X->p != NULL )
+    {
+        memset( X->p, 0, X->n * ciL );
+        free( X->p );
+    }
+
+    X->s = 1;
+    X->n = 0;
+    X->p = NULL;
+}
+
+/*
+ * Enlarge to the specified number of limbs
+ */
+int mpi_grow( mpi *X, size_t nblimbs )
+{
+    t_uint *p;
+
+    if( nblimbs > POLARSSL_MPI_MAX_LIMBS )
+        return( POLARSSL_ERR_MPI_MALLOC_FAILED );
+
+    if( X->n < nblimbs )
+    {
+        if( ( p = (t_uint *) malloc( nblimbs * ciL ) ) == NULL )
+            return( POLARSSL_ERR_MPI_MALLOC_FAILED );
+
+        memset( p, 0, nblimbs * ciL );
+
+        if( X->p != NULL )
+        {
+            memcpy( p, X->p, X->n * ciL );
+            memset( X->p, 0, X->n * ciL );
+            free( X->p );
+        }
+
+        X->n = nblimbs;
+        X->p = p;
+    }
+
+    return( 0 );
+}
+
+/*
+ * Copy the contents of Y into X
+ */
+int mpi_copy( mpi *X, const mpi *Y )
+{
+    int ret;
+    size_t i;
+
+    if( X == Y )
+        return( 0 );
+
+    for( i = Y->n - 1; i > 0; i-- )
+        if( Y->p[i] != 0 )
+            break;
+    i++;
+
+    X->s = Y->s;
+
+    MPI_CHK( mpi_grow( X, i ) );
+
+    memset( X->p, 0, X->n * ciL );
+    memcpy( X->p, Y->p, i * ciL );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Swap the contents of X and Y
+ */
+void mpi_swap( mpi *X, mpi *Y )
+{
+    mpi T;
+
+    memcpy( &T,  X, sizeof( mpi ) );
+    memcpy(  X,  Y, sizeof( mpi ) );
+    memcpy(  Y, &T, sizeof( mpi ) );
+}
+
+/*
+ * Set value from integer
+ */
+int mpi_lset( mpi *X, t_sint z )
+{
+    int ret;
+
+    MPI_CHK( mpi_grow( X, 1 ) );
+    memset( X->p, 0, X->n * ciL );
+
+    X->p[0] = ( z < 0 ) ? -z : z;
+    X->s    = ( z < 0 ) ? -1 : 1;
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Get a specific bit
+ */
+int mpi_get_bit( const mpi *X, size_t pos )
+{
+    if( X->n * biL <= pos )
+        return( 0 );
+
+    return ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01;
+}
+
+/*
+ * Set a bit to a specific value of 0 or 1
+ */
+int mpi_set_bit( mpi *X, size_t pos, unsigned char val )
+{
+    int ret = 0;
+    size_t off = pos / biL;
+    size_t idx = pos % biL;
+
+    if( val != 0 && val != 1 )
+        return POLARSSL_ERR_MPI_BAD_INPUT_DATA;
+        
+    if( X->n * biL <= pos )
+    {
+        if( val == 0 )
+            return ( 0 );
+
+        MPI_CHK( mpi_grow( X, off + 1 ) );
+    }
+
+    X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx );
+
+cleanup:
+    
+    return( ret );
+}
+
+/*
+ * Return the number of least significant bits
+ */
+size_t mpi_lsb( const mpi *X )
+{
+    size_t i, j, count = 0;
+
+    for( i = 0; i < X->n; i++ )
+        for( j = 0; j < biL; j++, count++ )
+            if( ( ( X->p[i] >> j ) & 1 ) != 0 )
+                return( count );
+
+    return( 0 );
+}
+
+/*
+ * Return the number of most significant bits
+ */
+size_t mpi_msb( const mpi *X )
+{
+    size_t i, j;
+
+    for( i = X->n - 1; i > 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = biL; j > 0; j-- )
+        if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 )
+            break;
+
+    return( ( i * biL ) + j );
+}
+
+/*
+ * Return the total size in bytes
+ */
+size_t mpi_size( const mpi *X )
+{
+    return( ( mpi_msb( X ) + 7 ) >> 3 );
+}
+
+/*
+ * Convert an ASCII character to digit value
+ */
+static int mpi_get_digit( t_uint *d, int radix, char c )
+{
+    *d = 255;
+
+    if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
+    if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
+    if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
+
+    if( *d >= (t_uint) radix )
+        return( POLARSSL_ERR_MPI_INVALID_CHARACTER );
+
+    return( 0 );
+}
+
+/*
+ * Import from an ASCII string
+ */
+int mpi_read_string( mpi *X, int radix, const char *s )
+{
+    int ret;
+    size_t i, j, slen, n;
+    t_uint d;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &T );
+
+    slen = strlen( s );
+
+    if( radix == 16 )
+    {
+        n = BITS_TO_LIMBS( slen << 2 );
+
+        MPI_CHK( mpi_grow( X, n ) );
+        MPI_CHK( mpi_lset( X, 0 ) );
+
+        for( i = slen, j = 0; i > 0; i--, j++ )
+        {
+            if( i == 1 && s[i - 1] == '-' )
+            {
+                X->s = -1;
+                break;
+            }
+
+            MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
+            X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 );
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_lset( X, 0 ) );
+
+        for( i = 0; i < slen; i++ )
+        {
+            if( i == 0 && s[i] == '-' )
+            {
+                X->s = -1;
+                continue;
+            }
+
+            MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
+            MPI_CHK( mpi_mul_int( &T, X, radix ) );
+
+            if( X->s == 1 )
+            {
+                MPI_CHK( mpi_add_int( X, &T, d ) );
+            }
+            else
+            {
+                MPI_CHK( mpi_sub_int( X, &T, d ) );
+            }
+        }
+    }
+
+cleanup:
+
+    mpi_free( &T );
+
+    return( ret );
+}
+
+/*
+ * Helper to write the digits high-order first
+ */
+static int mpi_write_hlp( mpi *X, int radix, char **p )
+{
+    int ret;
+    t_uint r;
+
+    if( radix < 2 || radix > 16 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    MPI_CHK( mpi_mod_int( &r, X, radix ) );
+    MPI_CHK( mpi_div_int( X, NULL, X, radix ) );
+
+    if( mpi_cmp_int( X, 0 ) != 0 )
+        MPI_CHK( mpi_write_hlp( X, radix, p ) );
+
+    if( r < 10 )
+        *(*p)++ = (char)( r + 0x30 );
+    else
+        *(*p)++ = (char)( r + 0x37 );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Export into an ASCII string
+ */
+int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen )
+{
+    int ret = 0;
+    size_t n;
+    char *p;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    n = mpi_msb( X );
+    if( radix >=  4 ) n >>= 1;
+    if( radix >= 16 ) n >>= 1;
+    n += 3;
+
+    if( *slen < n )
+    {
+        *slen = n;
+        return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
+    }
+
+    p = s;
+    mpi_init( &T );
+
+    if( X->s == -1 )
+        *p++ = '-';
+
+    if( radix == 16 )
+    {
+        int c;
+        size_t i, j, k;
+
+        for( i = X->n, k = 0; i > 0; i-- )
+        {
+            for( j = ciL; j > 0; j-- )
+            {
+                c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
+
+                if( c == 0 && k == 0 && ( i + j + 3 ) != 0 )
+                    continue;
+
+                *(p++) = "0123456789ABCDEF" [c / 16];
+                *(p++) = "0123456789ABCDEF" [c % 16];
+                k = 1;
+            }
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_copy( &T, X ) );
+
+        if( T.s == -1 )
+            T.s = 1;
+
+        MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
+    }
+
+    *p++ = '\0';
+    *slen = p - s;
+
+cleanup:
+
+    mpi_free( &T );
+
+    return( ret );
+}
+
+#if defined(POLARSSL_FS_IO)
+/*
+ * Read X from an opened file
+ */
+int mpi_read_file( mpi *X, int radix, FILE *fin )
+{
+    t_uint d;
+    size_t slen;
+    char *p;
+    /*
+     * Buffer should have space for (short) label and decimal formatted MPI,
+     * newline characters and '\0'
+     */
+    char s[ POLARSSL_MPI_RW_BUFFER_SIZE ];
+
+    memset( s, 0, sizeof( s ) );
+    if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
+        return( POLARSSL_ERR_MPI_FILE_IO_ERROR );
+
+    slen = strlen( s );
+    if( slen == sizeof( s ) - 2 )
+        return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
+
+    if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
+    if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
+
+    p = s + slen;
+    while( --p >= s )
+        if( mpi_get_digit( &d, radix, *p ) != 0 )
+            break;
+
+    return( mpi_read_string( X, radix, p + 1 ) );
+}
+
+/*
+ * Write X into an opened file (or stdout if fout == NULL)
+ */
+int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout )
+{
+    int ret;
+    size_t n, slen, plen;
+    /*
+     * Buffer should have space for (short) label and decimal formatted MPI,
+     * newline characters and '\0'
+     */
+    char s[ POLARSSL_MPI_RW_BUFFER_SIZE ];
+
+    n = sizeof( s );
+    memset( s, 0, n );
+    n -= 2;
+
+    MPI_CHK( mpi_write_string( X, radix, s, (size_t *) &n ) );
+
+    if( p == NULL ) p = "";
+
+    plen = strlen( p );
+    slen = strlen( s );
+    s[slen++] = '\r';
+    s[slen++] = '\n';
+
+    if( fout != NULL )
+    {
+        if( fwrite( p, 1, plen, fout ) != plen ||
+            fwrite( s, 1, slen, fout ) != slen )
+            return( POLARSSL_ERR_MPI_FILE_IO_ERROR );
+    }
+    else
+        printf( "%s%s", p, s );
+
+cleanup:
+
+    return( ret );
+}
+#endif /* POLARSSL_FS_IO */
+
+/*
+ * Import X from unsigned binary data, big endian
+ */
+int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen )
+{
+    int ret;
+    size_t i, j, n;
+
+    for( n = 0; n < buflen; n++ )
+        if( buf[n] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    for( i = buflen, j = 0; i > n; i--, j++ )
+        X->p[j / ciL] |= ((t_uint) buf[i - 1]) << ((j % ciL) << 3);
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Export X into unsigned binary data, big endian
+ */
+int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen )
+{
+    size_t i, j, n;
+
+    n = mpi_size( X );
+
+    if( buflen < n )
+        return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
+
+    memset( buf, 0, buflen );
+
+    for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
+        buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
+
+    return( 0 );
+}
+
+/*
+ * Left-shift: X <<= count
+ */
+int mpi_shift_l( mpi *X, size_t count )
+{
+    int ret;
+    size_t i, v0, t1;
+    t_uint r0 = 0, r1;
+
+    v0 = count / (biL    );
+    t1 = count & (biL - 1);
+
+    i = mpi_msb( X ) + count;
+
+    if( X->n * biL < i )
+        MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) );
+
+    ret = 0;
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = X->n; i > v0; i-- )
+            X->p[i - 1] = X->p[i - v0 - 1];
+
+        for( ; i > 0; i-- )
+            X->p[i - 1] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( t1 > 0 )
+    {
+        for( i = v0; i < X->n; i++ )
+        {
+            r1 = X->p[i] >> (biL - t1);
+            X->p[i] <<= t1;
+            X->p[i] |= r0;
+            r0 = r1;
+        }
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Right-shift: X >>= count
+ */
+int mpi_shift_r( mpi *X, size_t count )
+{
+    size_t i, v0, v1;
+    t_uint r0 = 0, r1;
+
+    v0 = count /  biL;
+    v1 = count & (biL - 1);
+
+    if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
+        return mpi_lset( X, 0 );
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = 0; i < X->n - v0; i++ )
+            X->p[i] = X->p[i + v0];
+
+        for( ; i < X->n; i++ )
+            X->p[i] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( v1 > 0 )
+    {
+        for( i = X->n; i > 0; i-- )
+        {
+            r1 = X->p[i - 1] << (biL - v1);
+            X->p[i - 1] >>= v1;
+            X->p[i - 1] |= r0;
+            r0 = r1;
+        }
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare unsigned values
+ */
+int mpi_cmp_abs( const mpi *X, const mpi *Y )
+{
+    size_t i, j;
+
+    for( i = X->n; i > 0; i-- )
+        if( X->p[i - 1] != 0 )
+            break;
+
+    for( j = Y->n; j > 0; j-- )
+        if( Y->p[j - 1] != 0 )
+            break;
+
+    if( i == 0 && j == 0 )
+        return( 0 );
+
+    if( i > j ) return(  1 );
+    if( j > i ) return( -1 );
+
+    for( ; i > 0; i-- )
+    {
+        if( X->p[i - 1] > Y->p[i - 1] ) return(  1 );
+        if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_mpi( const mpi *X, const mpi *Y )
+{
+    size_t i, j;
+
+    for( i = X->n; i > 0; i-- )
+        if( X->p[i - 1] != 0 )
+            break;
+
+    for( j = Y->n; j > 0; j-- )
+        if( Y->p[j - 1] != 0 )
+            break;
+
+    if( i == 0 && j == 0 )
+        return( 0 );
+
+    if( i > j ) return(  X->s );
+    if( j > i ) return( -Y->s );
+
+    if( X->s > 0 && Y->s < 0 ) return(  1 );
+    if( Y->s > 0 && X->s < 0 ) return( -1 );
+
+    for( ; i > 0; i-- )
+    {
+        if( X->p[i - 1] > Y->p[i - 1] ) return(  X->s );
+        if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_int( const mpi *X, t_sint z )
+{
+    mpi Y;
+    t_uint p[1];
+
+    *p  = ( z < 0 ) ? -z : z;
+    Y.s = ( z < 0 ) ? -1 : 1;
+    Y.n = 1;
+    Y.p = p;
+
+    return( mpi_cmp_mpi( X, &Y ) );
+}
+
+/*
+ * Unsigned addition: X = |A| + |B|  (HAC 14.7)
+ */
+int mpi_add_abs( mpi *X, const mpi *A, const mpi *B )
+{
+    int ret;
+    size_t i, j;
+    t_uint *o, *p, c;
+
+    if( X == B )
+    {
+        const mpi *T = A; A = X; B = T;
+    }
+
+    if( X != A )
+        MPI_CHK( mpi_copy( X, A ) );
+   
+    /*
+     * X should always be positive as a result of unsigned additions.
+     */
+    X->s = 1;
+
+    for( j = B->n; j > 0; j-- )
+        if( B->p[j - 1] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, j ) );
+
+    o = B->p; p = X->p; c = 0;
+
+    for( i = 0; i < j; i++, o++, p++ )
+    {
+        *p +=  c; c  = ( *p <  c );
+        *p += *o; c += ( *p < *o );
+    }
+
+    while( c != 0 )
+    {
+        if( i >= X->n )
+        {
+            MPI_CHK( mpi_grow( X, i + 1 ) );
+            p = X->p + i;
+        }
+
+        *p += c; c = ( *p < c ); i++; p++;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Helper for mpi substraction
+ */
+static void mpi_sub_hlp( size_t n, t_uint *s, t_uint *d )
+{
+    size_t i;
+    t_uint c, z;
+
+    for( i = c = 0; i < n; i++, s++, d++ )
+    {
+        z = ( *d <  c );     *d -=  c;
+        c = ( *d < *s ) + z; *d -= *s;
+    }
+
+    while( c != 0 )
+    {
+        z = ( *d < c ); *d -= c;
+        c = z; i++; d++;
+    }
+}
+
+/*
+ * Unsigned substraction: X = |A| - |B|  (HAC 14.9)
+ */
+int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B )
+{
+    mpi TB;
+    int ret;
+    size_t n;
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+        return( POLARSSL_ERR_MPI_NEGATIVE_VALUE );
+
+    mpi_init( &TB );
+
+    if( X == B )
+    {
+        MPI_CHK( mpi_copy( &TB, B ) );
+        B = &TB;
+    }
+
+    if( X != A )
+        MPI_CHK( mpi_copy( X, A ) );
+
+    /*
+     * X should always be positive as a result of unsigned substractions.
+     */
+    X->s = 1;
+
+    ret = 0;
+
+    for( n = B->n; n > 0; n-- )
+        if( B->p[n - 1] != 0 )
+            break;
+
+    mpi_sub_hlp( n, B->p, X->p );
+
+cleanup:
+
+    mpi_free( &TB );
+
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + B
+ */
+int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s < 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed substraction: X = A - B
+ */
+int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s > 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + b
+ */
+int mpi_add_int( mpi *X, const mpi *A, t_sint b )
+{
+    mpi _B;
+    t_uint p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_add_mpi( X, A, &_B ) );
+}
+
+/*
+ * Signed substraction: X = A - b
+ */
+int mpi_sub_int( mpi *X, const mpi *A, t_sint b )
+{
+    mpi _B;
+    t_uint p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_sub_mpi( X, A, &_B ) );
+}
+
+/*
+ * Helper for mpi multiplication
+ */
+static
+#if defined(__APPLE__) && defined(__arm__)
+/*
+ * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
+ * appears to need this to prevent bad ARM code generation at -O3.
+ */
+__attribute__ ((noinline))
+#endif
+void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b )
+{
+    t_uint c = 0, t = 0;
+
+#if defined(MULADDC_HUIT)
+    for( ; i >= 8; i -= 8 )
+    {
+        MULADDC_INIT
+        MULADDC_HUIT
+        MULADDC_STOP
+    }
+
+    for( ; i > 0; i-- )
+    {
+        MULADDC_INIT
+        MULADDC_CORE
+        MULADDC_STOP
+    }
+#else
+    for( ; i >= 16; i -= 16 )
+    {
+        MULADDC_INIT
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_STOP
+    }
+
+    for( ; i >= 8; i -= 8 )
+    {
+        MULADDC_INIT
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_STOP
+    }
+
+    for( ; i > 0; i-- )
+    {
+        MULADDC_INIT
+        MULADDC_CORE
+        MULADDC_STOP
+    }
+#endif
+
+    t++;
+
+    do {
+        *d += c; c = ( *d < c ); d++;
+    }
+    while( c != 0 );
+}
+
+/*
+ * Baseline multiplication: X = A * B  (HAC 14.12)
+ */
+int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B )
+{
+    int ret;
+    size_t i, j;
+    mpi TA, TB;
+
+    mpi_init( &TA ); mpi_init( &TB );
+
+    if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; }
+    if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; }
+
+    for( i = A->n; i > 0; i-- )
+        if( A->p[i - 1] != 0 )
+            break;
+
+    for( j = B->n; j > 0; j-- )
+        if( B->p[j - 1] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, i + j ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    for( i++; j > 0; j-- )
+        mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] );
+
+    X->s = A->s * B->s;
+
+cleanup:
+
+    mpi_free( &TB ); mpi_free( &TA );
+
+    return( ret );
+}
+
+/*
+ * Baseline multiplication: X = A * b
+ */
+int mpi_mul_int( mpi *X, const mpi *A, t_sint b )
+{
+    mpi _B;
+    t_uint p[1];
+
+    _B.s = 1;
+    _B.n = 1;
+    _B.p = p;
+    p[0] = b;
+
+    return( mpi_mul_mpi( X, A, &_B ) );
+}
+
+/*
+ * Division by mpi: A = Q * B + R  (HAC 14.20)
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B )
+{
+    int ret;
+    size_t i, n, t, k;
+    mpi X, Y, Z, T1, T2;
+
+    if( mpi_cmp_int( B, 0 ) == 0 )
+        return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO );
+
+    mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
+    mpi_init( &T1 ); mpi_init( &T2 );
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+    {
+        if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) );
+        if( R != NULL ) MPI_CHK( mpi_copy( R, A ) );
+        return( 0 );
+    }
+
+    MPI_CHK( mpi_copy( &X, A ) );
+    MPI_CHK( mpi_copy( &Y, B ) );
+    X.s = Y.s = 1;
+
+    MPI_CHK( mpi_grow( &Z, A->n + 2 ) );
+    MPI_CHK( mpi_lset( &Z,  0 ) );
+    MPI_CHK( mpi_grow( &T1, 2 ) );
+    MPI_CHK( mpi_grow( &T2, 3 ) );
+
+    k = mpi_msb( &Y ) % biL;
+    if( k < biL - 1 )
+    {
+        k = biL - 1 - k;
+        MPI_CHK( mpi_shift_l( &X, k ) );
+        MPI_CHK( mpi_shift_l( &Y, k ) );
+    }
+    else k = 0;
+
+    n = X.n - 1;
+    t = Y.n - 1;
+    MPI_CHK( mpi_shift_l( &Y, biL * (n - t) ) );
+
+    while( mpi_cmp_mpi( &X, &Y ) >= 0 )
+    {
+        Z.p[n - t]++;
+        mpi_sub_mpi( &X, &X, &Y );
+    }
+    mpi_shift_r( &Y, biL * (n - t) );
+
+    for( i = n; i > t ; i-- )
+    {
+        if( X.p[i] >= Y.p[t] )
+            Z.p[i - t - 1] = ~0;
+        else
+        {
+#if defined(POLARSSL_HAVE_UDBL)
+            t_udbl r;
+
+            r  = (t_udbl) X.p[i] << biL;
+            r |= (t_udbl) X.p[i - 1];
+            r /= Y.p[t];
+            if( r > ((t_udbl) 1 << biL) - 1)
+                r = ((t_udbl) 1 << biL) - 1;
+
+            Z.p[i - t - 1] = (t_uint) r;
+#else
+            /*
+             * __udiv_qrnnd_c, from gmp/longlong.h
+             */
+            t_uint q0, q1, r0, r1;
+            t_uint d0, d1, d, m;
+
+            d  = Y.p[t];
+            d0 = ( d << biH ) >> biH;
+            d1 = ( d >> biH );
+
+            q1 = X.p[i] / d1;
+            r1 = X.p[i] - d1 * q1;
+            r1 <<= biH;
+            r1 |= ( X.p[i - 1] >> biH );
+
+            m = q1 * d0;
+            if( r1 < m )
+            {
+                q1--, r1 += d;
+                while( r1 >= d && r1 < m )
+                    q1--, r1 += d;
+            }
+            r1 -= m;
+
+            q0 = r1 / d1;
+            r0 = r1 - d1 * q0;
+            r0 <<= biH;
+            r0 |= ( X.p[i - 1] << biH ) >> biH;
+
+            m = q0 * d0;
+            if( r0 < m )
+            {
+                q0--, r0 += d;
+                while( r0 >= d && r0 < m )
+                    q0--, r0 += d;
+            }
+            r0 -= m;
+
+            Z.p[i - t - 1] = ( q1 << biH ) | q0;
+#endif
+        }
+
+        Z.p[i - t - 1]++;
+        do
+        {
+            Z.p[i - t - 1]--;
+
+            MPI_CHK( mpi_lset( &T1, 0 ) );
+            T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
+            T1.p[1] = Y.p[t];
+            MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
+
+            MPI_CHK( mpi_lset( &T2, 0 ) );
+            T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
+            T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
+            T2.p[2] = X.p[i];
+        }
+        while( mpi_cmp_mpi( &T1, &T2 ) > 0 );
+
+        MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
+        MPI_CHK( mpi_shift_l( &T1,  biL * (i - t - 1) ) );
+        MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) );
+
+        if( mpi_cmp_int( &X, 0 ) < 0 )
+        {
+            MPI_CHK( mpi_copy( &T1, &Y ) );
+            MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
+            MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) );
+            Z.p[i - t - 1]--;
+        }
+    }
+
+    if( Q != NULL )
+    {
+        mpi_copy( Q, &Z );
+        Q->s = A->s * B->s;
+    }
+
+    if( R != NULL )
+    {
+        mpi_shift_r( &X, k );
+        X.s = A->s;
+        mpi_copy( R, &X );
+
+        if( mpi_cmp_int( R, 0 ) == 0 )
+            R->s = 1;
+    }
+
+cleanup:
+
+    mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
+    mpi_free( &T1 ); mpi_free( &T2 );
+
+    return( ret );
+}
+
+/*
+ * Division by int: A = Q * b + R
+ */
+int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b )
+{
+    mpi _B;
+    t_uint p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_div_mpi( Q, R, A, &_B ) );
+}
+
+/*
+ * Modulo: R = A mod B
+ */
+int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B )
+{
+    int ret;
+
+    if( mpi_cmp_int( B, 0 ) < 0 )
+        return POLARSSL_ERR_MPI_NEGATIVE_VALUE;
+
+    MPI_CHK( mpi_div_mpi( NULL, R, A, B ) );
+
+    while( mpi_cmp_int( R, 0 ) < 0 )
+      MPI_CHK( mpi_add_mpi( R, R, B ) );
+
+    while( mpi_cmp_mpi( R, B ) >= 0 )
+      MPI_CHK( mpi_sub_mpi( R, R, B ) );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Modulo: r = A mod b
+ */
+int mpi_mod_int( t_uint *r, const mpi *A, t_sint b )
+{
+    size_t i;
+    t_uint x, y, z;
+
+    if( b == 0 )
+        return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO );
+
+    if( b < 0 )
+        return POLARSSL_ERR_MPI_NEGATIVE_VALUE;
+
+    /*
+     * handle trivial cases
+     */
+    if( b == 1 )
+    {
+        *r = 0;
+        return( 0 );
+    }
+
+    if( b == 2 )
+    {
+        *r = A->p[0] & 1;
+        return( 0 );
+    }
+
+    /*
+     * general case
+     */
+    for( i = A->n, y = 0; i > 0; i-- )
+    {
+        x  = A->p[i - 1];
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+
+        x <<= biH;
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+    }
+
+    /*
+     * If A is negative, then the current y represents a negative value.
+     * Flipping it to the positive side.
+     */
+    if( A->s < 0 && y != 0 )
+        y = b - y;
+
+    *r = y;
+
+    return( 0 );
+}
+
+/*
+ * Fast Montgomery initialization (thanks to Tom St Denis)
+ */
+static void mpi_montg_init( t_uint *mm, const mpi *N )
+{
+    t_uint x, m0 = N->p[0];
+
+    x  = m0;
+    x += ( ( m0 + 2 ) & 4 ) << 1;
+    x *= ( 2 - ( m0 * x ) );
+
+    if( biL >= 16 ) x *= ( 2 - ( m0 * x ) );
+    if( biL >= 32 ) x *= ( 2 - ( m0 * x ) );
+    if( biL >= 64 ) x *= ( 2 - ( m0 * x ) );
+
+    *mm = ~x + 1;
+}
+
+/*
+ * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
+ */
+static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_uint mm, const mpi *T )
+{
+    size_t i, n, m;
+    t_uint u0, u1, *d;
+
+    memset( T->p, 0, T->n * ciL );
+
+    d = T->p;
+    n = N->n;
+    m = ( B->n < n ) ? B->n : n;
+
+    for( i = 0; i < n; i++ )
+    {
+        /*
+         * T = (T + u0*B + u1*N) / 2^biL
+         */
+        u0 = A->p[i];
+        u1 = ( d[0] + u0 * B->p[0] ) * mm;
+
+        mpi_mul_hlp( m, B->p, d, u0 );
+        mpi_mul_hlp( n, N->p, d, u1 );
+
+        *d++ = u0; d[n + 1] = 0;
+    }
+
+    memcpy( A->p, d, (n + 1) * ciL );
+
+    if( mpi_cmp_abs( A, N ) >= 0 )
+        mpi_sub_hlp( n, N->p, A->p );
+    else
+        /* prevent timing attacks */
+        mpi_sub_hlp( n, A->p, T->p );
+}
+
+/*
+ * Montgomery reduction: A = A * R^-1 mod N
+ */
+static void mpi_montred( mpi *A, const mpi *N, t_uint mm, const mpi *T )
+{
+    t_uint z = 1;
+    mpi U;
+
+    U.n = U.s = (int) z;
+    U.p = &z;
+
+    mpi_montmul( A, &U, N, mm, T );
+}
+
+/*
+ * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
+ */
+int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
+{
+    int ret;
+    size_t wbits, wsize, one = 1;
+    size_t i, j, nblimbs;
+    size_t bufsize, nbits;
+    t_uint ei, mm, state;
+    mpi RR, T, W[ 2 << POLARSSL_MPI_WINDOW_SIZE ], Apos;
+    int neg;
+
+    if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    if( mpi_cmp_int( E, 0 ) < 0 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    /*
+     * Init temps and window size
+     */
+    mpi_montg_init( &mm, N );
+    mpi_init( &RR ); mpi_init( &T );
+    memset( W, 0, sizeof( W ) );
+
+    i = mpi_msb( E );
+
+    wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
+            ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
+
+    if( wsize > POLARSSL_MPI_WINDOW_SIZE )
+        wsize = POLARSSL_MPI_WINDOW_SIZE;
+
+    j = N->n + 1;
+    MPI_CHK( mpi_grow( X, j ) );
+    MPI_CHK( mpi_grow( &W[1],  j ) );
+    MPI_CHK( mpi_grow( &T, j * 2 ) );
+
+    /*
+     * Compensate for negative A (and correct at the end)
+     */
+    neg = ( A->s == -1 );
+
+    mpi_init( &Apos );
+    if( neg )
+    {
+        MPI_CHK( mpi_copy( &Apos, A ) );
+        Apos.s = 1;
+        A = &Apos;
+    }
+
+    /*
+     * If 1st call, pre-compute R^2 mod N
+     */
+    if( _RR == NULL || _RR->p == NULL )
+    {
+        MPI_CHK( mpi_lset( &RR, 1 ) );
+        MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) );
+        MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) );
+
+        if( _RR != NULL )
+            memcpy( _RR, &RR, sizeof( mpi ) );
+    }
+    else
+        memcpy( &RR, _RR, sizeof( mpi ) );
+
+    /*
+     * W[1] = A * R^2 * R^-1 mod N = A * R mod N
+     */
+    if( mpi_cmp_mpi( A, N ) >= 0 )
+        mpi_mod_mpi( &W[1], A, N );
+    else   mpi_copy( &W[1], A );
+
+    mpi_montmul( &W[1], &RR, N, mm, &T );
+
+    /*
+     * X = R^2 * R^-1 mod N = R mod N
+     */
+    MPI_CHK( mpi_copy( X, &RR ) );
+    mpi_montred( X, N, mm, &T );
+
+    if( wsize > 1 )
+    {
+        /*
+         * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
+         */
+        j =  one << (wsize - 1);
+
+        MPI_CHK( mpi_grow( &W[j], N->n + 1 ) );
+        MPI_CHK( mpi_copy( &W[j], &W[1]    ) );
+
+        for( i = 0; i < wsize - 1; i++ )
+            mpi_montmul( &W[j], &W[j], N, mm, &T );
+    
+        /*
+         * W[i] = W[i - 1] * W[1]
+         */
+        for( i = j + 1; i < (one << wsize); i++ )
+        {
+            MPI_CHK( mpi_grow( &W[i], N->n + 1 ) );
+            MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) );
+
+            mpi_montmul( &W[i], &W[1], N, mm, &T );
+        }
+    }
+
+    nblimbs = E->n;
+    bufsize = 0;
+    nbits   = 0;
+    wbits   = 0;
+    state   = 0;
+
+    while( 1 )
+    {
+        if( bufsize == 0 )
+        {
+            if( nblimbs-- == 0 )
+                break;
+
+            bufsize = sizeof( t_uint ) << 3;
+        }
+
+        bufsize--;
+
+        ei = (E->p[nblimbs] >> bufsize) & 1;
+
+        /*
+         * skip leading 0s
+         */
+        if( ei == 0 && state == 0 )
+            continue;
+
+        if( ei == 0 && state == 1 )
+        {
+            /*
+             * out of window, square X
+             */
+            mpi_montmul( X, X, N, mm, &T );
+            continue;
+        }
+
+        /*
+         * add ei to current window
+         */
+        state = 2;
+
+        nbits++;
+        wbits |= (ei << (wsize - nbits));
+
+        if( nbits == wsize )
+        {
+            /*
+             * X = X^wsize R^-1 mod N
+             */
+            for( i = 0; i < wsize; i++ )
+                mpi_montmul( X, X, N, mm, &T );
+
+            /*
+             * X = X * W[wbits] R^-1 mod N
+             */
+            mpi_montmul( X, &W[wbits], N, mm, &T );
+
+            state--;
+            nbits = 0;
+            wbits = 0;
+        }
+    }
+
+    /*
+     * process the remaining bits
+     */
+    for( i = 0; i < nbits; i++ )
+    {
+        mpi_montmul( X, X, N, mm, &T );
+
+        wbits <<= 1;
+
+        if( (wbits & (one << wsize)) != 0 )
+            mpi_montmul( X, &W[1], N, mm, &T );
+    }
+
+    /*
+     * X = A^E * R * R^-1 mod N = A^E mod N
+     */
+    mpi_montred( X, N, mm, &T );
+
+    if( neg )
+    {
+        X->s = -1;
+        mpi_add_mpi( X, N, X );
+    }
+
+cleanup:
+
+    for( i = (one << (wsize - 1)); i < (one << wsize); i++ )
+        mpi_free( &W[i] );
+
+    mpi_free( &W[1] ); mpi_free( &T ); mpi_free( &Apos );
+
+    if( _RR == NULL )
+        mpi_free( &RR );
+
+    return( ret );
+}
+
+/*
+ * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
+ */
+int mpi_gcd( mpi *G, const mpi *A, const mpi *B )
+{
+    int ret;
+    size_t lz, lzt;
+    mpi TG, TA, TB;
+
+    mpi_init( &TG ); mpi_init( &TA ); mpi_init( &TB );
+
+    MPI_CHK( mpi_copy( &TA, A ) );
+    MPI_CHK( mpi_copy( &TB, B ) );
+
+    lz = mpi_lsb( &TA );
+    lzt = mpi_lsb( &TB );
+
+    if ( lzt < lz )
+        lz = lzt;
+
+    MPI_CHK( mpi_shift_r( &TA, lz ) );
+    MPI_CHK( mpi_shift_r( &TB, lz ) );
+
+    TA.s = TB.s = 1;
+
+    while( mpi_cmp_int( &TA, 0 ) != 0 )
+    {
+        MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) );
+        MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) );
+
+        if( mpi_cmp_mpi( &TA, &TB ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) );
+            MPI_CHK( mpi_shift_r( &TA, 1 ) );
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) );
+            MPI_CHK( mpi_shift_r( &TB, 1 ) );
+        }
+    }
+
+    MPI_CHK( mpi_shift_l( &TB, lz ) );
+    MPI_CHK( mpi_copy( G, &TB ) );
+
+cleanup:
+
+    mpi_free( &TG ); mpi_free( &TA ); mpi_free( &TB );
+
+    return( ret );
+}
+
+int mpi_fill_random( mpi *X, size_t size,
+                     int (*f_rng)(void *, unsigned char *, size_t),
+                     void *p_rng )
+{
+    int ret;
+
+    MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    MPI_CHK( f_rng( p_rng, (unsigned char *) X->p, size ) );
+
+cleanup:
+    return( ret );
+}
+
+/*
+ * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
+ */
+int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N )
+{
+    int ret;
+    mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
+
+    if( mpi_cmp_int( N, 0 ) <= 0 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 );
+    mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV );
+    mpi_init( &V1 ); mpi_init( &V2 );
+
+    MPI_CHK( mpi_gcd( &G, A, N ) );
+
+    if( mpi_cmp_int( &G, 1 ) != 0 )
+    {
+        ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE;
+        goto cleanup;
+    }
+
+    MPI_CHK( mpi_mod_mpi( &TA, A, N ) );
+    MPI_CHK( mpi_copy( &TU, &TA ) );
+    MPI_CHK( mpi_copy( &TB, N ) );
+    MPI_CHK( mpi_copy( &TV, N ) );
+
+    MPI_CHK( mpi_lset( &U1, 1 ) );
+    MPI_CHK( mpi_lset( &U2, 0 ) );
+    MPI_CHK( mpi_lset( &V1, 0 ) );
+    MPI_CHK( mpi_lset( &V2, 1 ) );
+
+    do
+    {
+        while( ( TU.p[0] & 1 ) == 0 )
+        {
+            MPI_CHK( mpi_shift_r( &TU, 1 ) );
+
+            if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
+            {
+                MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) );
+                MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) );
+            }
+
+            MPI_CHK( mpi_shift_r( &U1, 1 ) );
+            MPI_CHK( mpi_shift_r( &U2, 1 ) );
+        }
+
+        while( ( TV.p[0] & 1 ) == 0 )
+        {
+            MPI_CHK( mpi_shift_r( &TV, 1 ) );
+
+            if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
+            {
+                MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) );
+                MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) );
+            }
+
+            MPI_CHK( mpi_shift_r( &V1, 1 ) );
+            MPI_CHK( mpi_shift_r( &V2, 1 ) );
+        }
+
+        if( mpi_cmp_mpi( &TU, &TV ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) );
+            MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) );
+            MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) );
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) );
+            MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) );
+            MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) );
+        }
+    }
+    while( mpi_cmp_int( &TU, 0 ) != 0 );
+
+    while( mpi_cmp_int( &V1, 0 ) < 0 )
+        MPI_CHK( mpi_add_mpi( &V1, &V1, N ) );
+
+    while( mpi_cmp_mpi( &V1, N ) >= 0 )
+        MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) );
+
+    MPI_CHK( mpi_copy( X, &V1 ) );
+
+cleanup:
+
+    mpi_free( &TA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 );
+    mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV );
+    mpi_free( &V1 ); mpi_free( &V2 );
+
+    return( ret );
+}
+
+#if defined(POLARSSL_GENPRIME)
+
+static const int small_prime[] =
+{
+        3,    5,    7,   11,   13,   17,   19,   23,
+       29,   31,   37,   41,   43,   47,   53,   59,
+       61,   67,   71,   73,   79,   83,   89,   97,
+      101,  103,  107,  109,  113,  127,  131,  137,
+      139,  149,  151,  157,  163,  167,  173,  179,
+      181,  191,  193,  197,  199,  211,  223,  227,
+      229,  233,  239,  241,  251,  257,  263,  269,
+      271,  277,  281,  283,  293,  307,  311,  313,
+      317,  331,  337,  347,  349,  353,  359,  367,
+      373,  379,  383,  389,  397,  401,  409,  419,
+      421,  431,  433,  439,  443,  449,  457,  461,
+      463,  467,  479,  487,  491,  499,  503,  509,
+      521,  523,  541,  547,  557,  563,  569,  571,
+      577,  587,  593,  599,  601,  607,  613,  617,
+      619,  631,  641,  643,  647,  653,  659,  661,
+      673,  677,  683,  691,  701,  709,  719,  727,
+      733,  739,  743,  751,  757,  761,  769,  773,
+      787,  797,  809,  811,  821,  823,  827,  829,
+      839,  853,  857,  859,  863,  877,  881,  883,
+      887,  907,  911,  919,  929,  937,  941,  947,
+      953,  967,  971,  977,  983,  991,  997, -103
+};
+
+/*
+ * Miller-Rabin primality test  (HAC 4.24)
+ */
+int mpi_is_prime( mpi *X,
+                  int (*f_rng)(void *, unsigned char *, size_t),
+                  void *p_rng )
+{
+    int ret, xs;
+    size_t i, j, n, s;
+    mpi W, R, T, A, RR;
+
+    if( mpi_cmp_int( X, 0 ) == 0 ||
+        mpi_cmp_int( X, 1 ) == 0 )
+        return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
+
+    if( mpi_cmp_int( X, 2 ) == 0 )
+        return( 0 );
+
+    mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A );
+    mpi_init( &RR );
+
+    xs = X->s; X->s = 1;
+
+    /*
+     * test trivial factors first
+     */
+    if( ( X->p[0] & 1 ) == 0 )
+        return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
+
+    for( i = 0; small_prime[i] > 0; i++ )
+    {
+        t_uint r;
+
+        if( mpi_cmp_int( X, small_prime[i] ) <= 0 )
+            return( 0 );
+
+        MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) );
+
+        if( r == 0 )
+            return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
+    }
+
+    /*
+     * W = |X| - 1
+     * R = W >> lsb( W )
+     */
+    MPI_CHK( mpi_sub_int( &W, X, 1 ) );
+    s = mpi_lsb( &W );
+    MPI_CHK( mpi_copy( &R, &W ) );
+    MPI_CHK( mpi_shift_r( &R, s ) );
+
+    i = mpi_msb( X );
+    /*
+     * HAC, table 4.4
+     */
+    n = ( ( i >= 1300 ) ?  2 : ( i >=  850 ) ?  3 :
+          ( i >=  650 ) ?  4 : ( i >=  350 ) ?  8 :
+          ( i >=  250 ) ? 12 : ( i >=  150 ) ? 18 : 27 );
+
+    for( i = 0; i < n; i++ )
+    {
+        /*
+         * pick a random A, 1 < A < |X| - 1
+         */
+        MPI_CHK( mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
+
+        if( mpi_cmp_mpi( &A, &W ) >= 0 )
+        {
+            j = mpi_msb( &A ) - mpi_msb( &W );
+            MPI_CHK( mpi_shift_r( &A, j + 1 ) );
+        }
+        A.p[0] |= 3;
+
+        /*
+         * A = A^R mod |X|
+         */
+        MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) );
+
+        if( mpi_cmp_mpi( &A, &W ) == 0 ||
+            mpi_cmp_int( &A,  1 ) == 0 )
+            continue;
+
+        j = 1;
+        while( j < s && mpi_cmp_mpi( &A, &W ) != 0 )
+        {
+            /*
+             * A = A * A mod |X|
+             */
+            MPI_CHK( mpi_mul_mpi( &T, &A, &A ) );
+            MPI_CHK( mpi_mod_mpi( &A, &T, X  ) );
+
+            if( mpi_cmp_int( &A, 1 ) == 0 )
+                break;
+
+            j++;
+        }
+
+        /*
+         * not prime if A != |X| - 1 or A == 1
+         */
+        if( mpi_cmp_mpi( &A, &W ) != 0 ||
+            mpi_cmp_int( &A,  1 ) == 0 )
+        {
+            ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE;
+            break;
+        }
+    }
+
+cleanup:
+
+    X->s = xs;
+
+    mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A );
+    mpi_free( &RR );
+
+    return( ret );
+}
+
+/*
+ * Prime number generation
+ */
+int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag,
+                   int (*f_rng)(void *, unsigned char *, size_t),
+                   void *p_rng )
+{
+    int ret;
+    size_t k, n;
+    mpi Y;
+
+    if( nbits < 3 || nbits > POLARSSL_MPI_MAX_BITS )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &Y );
+
+    n = BITS_TO_LIMBS( nbits );
+
+    MPI_CHK( mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
+
+    k = mpi_msb( X );
+    if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) );
+    if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) );
+
+    X->p[0] |= 3;
+
+    if( dh_flag == 0 )
+    {
+        while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
+        {
+            if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
+                goto cleanup;
+
+            MPI_CHK( mpi_add_int( X, X, 2 ) );
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_sub_int( &Y, X, 1 ) );
+        MPI_CHK( mpi_shift_r( &Y, 1 ) );
+
+        while( 1 )
+        {
+            if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 )
+            {
+                if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 )
+                    break;
+
+                if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
+                    goto cleanup;
+            }
+
+            if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
+                goto cleanup;
+
+            MPI_CHK( mpi_add_int( &Y, X, 1 ) );
+            MPI_CHK( mpi_add_int(  X, X, 2 ) );
+            MPI_CHK( mpi_shift_r( &Y, 1 ) );
+        }
+    }
+
+cleanup:
+
+    mpi_free( &Y );
+
+    return( ret );
+}
+
+#endif
+
+#if defined(POLARSSL_SELF_TEST)
+
+#define GCD_PAIR_COUNT  3
+
+static const int gcd_pairs[GCD_PAIR_COUNT][3] =
+{
+    { 693, 609, 21 },
+    { 1764, 868, 28 },
+    { 768454923, 542167814, 1 }
+};
+
+/*
+ * Checkup routine
+ */
+int mpi_self_test( int verbose )
+{
+    int ret, i;
+    mpi A, E, N, X, Y, U, V;
+
+    mpi_init( &A ); mpi_init( &E ); mpi_init( &N ); mpi_init( &X );
+    mpi_init( &Y ); mpi_init( &U ); mpi_init( &V );
+
+    MPI_CHK( mpi_read_string( &A, 16,
+        "EFE021C2645FD1DC586E69184AF4A31E" \
+        "D5F53E93B5F123FA41680867BA110131" \
+        "944FE7952E2517337780CB0DB80E61AA" \
+        "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
+
+    MPI_CHK( mpi_read_string( &E, 16,
+        "B2E7EFD37075B9F03FF989C7C5051C20" \
+        "34D2A323810251127E7BF8625A4F49A5" \
+        "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
+        "5B5C25763222FEFCCFC38B832366C29E" ) );
+
+    MPI_CHK( mpi_read_string( &N, 16,
+        "0066A198186C18C10B2F5ED9B522752A" \
+        "9830B69916E535C8F047518A889A43A5" \
+        "94B6BED27A168D31D4A52F88925AA8F5" ) );
+
+    MPI_CHK( mpi_mul_mpi( &X, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "602AB7ECA597A3D6B56FF9829A5E8B85" \
+        "9E857EA95A03512E2BAE7391688D264A" \
+        "A5663B0341DB9CCFD2C4C5F421FEC814" \
+        "8001B72E848A38CAE1C65F78E56ABDEF" \
+        "E12D3C039B8A02D6BE593F0BBBDA56F1" \
+        "ECF677152EF804370C1A305CAF3B5BF1" \
+        "30879B56C61DE584A0F53A2447A51E" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #1 (mul_mpi): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "256567336059E52CAE22925474705F39A94" ) );
+
+    MPI_CHK( mpi_read_string( &V, 16,
+        "6613F26162223DF488E9CD48CC132C7A" \
+        "0AC93C701B001B092E4E5B9F73BCD27B" \
+        "9EE50D0657C77F374E903CDFA4C642" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #2 (div_mpi): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 ||
+        mpi_cmp_mpi( &Y, &V ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "36E139AEA55215609D2816998ED020BB" \
+        "BD96C37890F65171D948E9BC7CBAA4D9" \
+        "325D24D6A3C12710F10A09FA08AB87" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #3 (exp_mod): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+#if defined(POLARSSL_GENPRIME)
+    MPI_CHK( mpi_inv_mod( &X, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
+        "C3DBA76456363A10869622EAC2DD84EC" \
+        "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #4 (inv_mod): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+#endif
+
+    if( verbose != 0 )
+        printf( "  MPI test #5 (simple gcd): " );
+
+    for ( i = 0; i < GCD_PAIR_COUNT; i++)
+    {
+        MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) );
+        MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) );
+
+           MPI_CHK( mpi_gcd( &A, &X, &Y ) );
+
+           if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
+           {
+                   if( verbose != 0 )
+                           printf( "failed at %d\n", i );
+
+                   return( 1 );
+           }
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+cleanup:
+
+    if( ret != 0 && verbose != 0 )
+        printf( "Unexpected error, return code = %08X\n", ret );
+
+    mpi_free( &A ); mpi_free( &E ); mpi_free( &N ); mpi_free( &X );
+    mpi_free( &Y ); mpi_free( &U ); mpi_free( &V );
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( ret );
+}
+
+#endif
+
+#endif
diff --git a/common/polarssl/bignum.h b/common/polarssl/bignum.h
new file mode 100644 (file)
index 0000000..5eaf1a5
--- /dev/null
@@ -0,0 +1,685 @@
+/**
+ * \file bignum.h
+ *
+ * \brief  Multi-precision integer library
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_BIGNUM_H
+#define POLARSSL_BIGNUM_H
+
+#include <stdio.h>
+#include <string.h>
+
+#include "polarssl_config.h"
+
+#ifdef _MSC_VER
+#include <basetsd.h>
+#if (_MSC_VER <= 1200)
+typedef   signed short  int16_t;
+typedef unsigned short uint16_t;
+#else
+typedef  INT16  int16_t;
+typedef UINT16 uint16_t;
+#endif
+typedef  INT32  int32_t;
+typedef  INT64  int64_t;
+typedef UINT32 uint32_t;
+typedef UINT64 uint64_t;
+#else
+#include <inttypes.h>
+#endif
+
+#define POLARSSL_ERR_MPI_FILE_IO_ERROR                     -0x0002  /**< An error occurred while reading from or writing to a file. */
+#define POLARSSL_ERR_MPI_BAD_INPUT_DATA                    -0x0004  /**< Bad input parameters to function. */
+#define POLARSSL_ERR_MPI_INVALID_CHARACTER                 -0x0006  /**< There is an invalid character in the digit string. */
+#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL                  -0x0008  /**< The buffer is too small to write to. */
+#define POLARSSL_ERR_MPI_NEGATIVE_VALUE                    -0x000A  /**< The input arguments are negative or result in illegal output. */
+#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO                  -0x000C  /**< The input argument for division is zero, which is not allowed. */
+#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE                    -0x000E  /**< The input arguments are not acceptable. */
+#define POLARSSL_ERR_MPI_MALLOC_FAILED                     -0x0010  /**< Memory allocation failed. */
+
+#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup
+
+/*
+ * Maximum size MPIs are allowed to grow to in number of limbs.
+ */
+#define POLARSSL_MPI_MAX_LIMBS                             10000
+
+#if !defined(POLARSSL_CONFIG_OPTIONS)
+/*
+ * Maximum window size used for modular exponentiation. Default: 6
+ * Minimum value: 1. Maximum value: 6.
+ *
+ * Result is an array of ( 2 << POLARSSL_MPI_WINDOW_SIZE ) MPIs used
+ * for the sliding window calculation. (So 64 by default)
+ *
+ * Reduction in size, reduces speed.
+ */
+#define POLARSSL_MPI_WINDOW_SIZE                           6        /**< Maximum windows size used. */
+
+/*
+ * Maximum size of MPIs allowed in bits and bytes for user-MPIs.
+ * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits )
+ *
+ * Note: Calculations can results temporarily in larger MPIs. So the number
+ * of limbs required (POLARSSL_MPI_MAX_LIMBS) is higher.
+ */
+#define POLARSSL_MPI_MAX_SIZE                              512      /**< Maximum number of bytes for usable MPIs. */
+
+#endif /* !POLARSSL_CONFIG_OPTIONS */
+
+#define POLARSSL_MPI_MAX_BITS                              ( 8 * POLARSSL_MPI_MAX_SIZE )    /**< Maximum number of bits for usable MPIs. */
+
+/*
+ * When reading from files with mpi_read_file() and writing to files with
+ * mpi_write_file() the buffer should have space
+ * for a (short) label, the MPI (in the provided radix), the newline
+ * characters and the '\0'.
+ *
+ * By default we assume at least a 10 char label, a minimum radix of 10
+ * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars).
+ * Autosized at compile time for at least a 10 char label, a minimum radix
+ * of 10 (decimal) for a number of POLARSSL_MPI_MAX_BITS size.
+ *
+ * This used to be statically sized to 1250 for a maximum of 4096 bit
+ * numbers (1234 decimal chars).
+ *
+ * Calculate using the formula:
+ *  POLARSSL_MPI_RW_BUFFER_SIZE = ceil(POLARSSL_MPI_MAX_BITS / ln(10) * ln(2)) +
+ *                                LabelSize + 6
+ */
+#define POLARSSL_MPI_MAX_BITS_SCALE100          ( 100 * POLARSSL_MPI_MAX_BITS )
+#define LN_2_DIV_LN_10_SCALE100                 332
+#define POLARSSL_MPI_RW_BUFFER_SIZE             ( ((POLARSSL_MPI_MAX_BITS_SCALE100 + LN_2_DIV_LN_10_SCALE100 - 1) / LN_2_DIV_LN_10_SCALE100) + 10 + 6 )
+
+/*
+ * Define the base integer type, architecture-wise
+ */
+#if defined(POLARSSL_HAVE_INT8)
+typedef   signed char  t_sint;
+typedef unsigned char  t_uint;
+typedef uint16_t       t_udbl;
+#define POLARSSL_HAVE_UDBL
+#else
+#if defined(POLARSSL_HAVE_INT16)
+typedef  int16_t t_sint;
+typedef uint16_t t_uint;
+typedef uint32_t t_udbl;
+#define POLARSSL_HAVE_UDBL
+#else
+  #if ( defined(_MSC_VER) && defined(_M_AMD64) )
+    typedef  int64_t t_sint;
+    typedef uint64_t t_uint;
+  #else
+    #if ( defined(__GNUC__) && (                          \
+          defined(__amd64__) || defined(__x86_64__)    || \
+          defined(__ppc64__) || defined(__powerpc64__) || \
+          defined(__ia64__)  || defined(__alpha__)     || \
+          (defined(__sparc__) && defined(__arch64__))  || \
+          defined(__s390x__) ) )
+       typedef  int64_t t_sint;
+       typedef uint64_t t_uint;
+       typedef unsigned int t_udbl __attribute__((mode(TI)));
+       #define POLARSSL_HAVE_UDBL
+    #else
+       typedef  int32_t t_sint;
+       typedef uint32_t t_uint;
+       #if ( defined(_MSC_VER) && defined(_M_IX86) )
+         typedef uint64_t t_udbl;
+         #define POLARSSL_HAVE_UDBL
+       #else
+         #if defined( POLARSSL_HAVE_LONGLONG )
+           typedef unsigned long long t_udbl;
+           #define POLARSSL_HAVE_UDBL
+         #endif
+       #endif
+    #endif
+  #endif
+#endif /* POLARSSL_HAVE_INT16 */
+#endif /* POLARSSL_HAVE_INT8  */
+
+/**
+ * \brief          MPI structure
+ */
+typedef struct
+{
+    int s;              /*!<  integer sign      */
+    size_t n;           /*!<  total # of limbs  */
+    t_uint *p;          /*!<  pointer to limbs  */
+}
+mpi;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief           Initialize one MPI
+ *
+ * \param X         One MPI to initialize.
+ */
+void mpi_init( mpi *X );
+
+/**
+ * \brief          Unallocate one MPI
+ *
+ * \param X        One MPI to unallocate.
+ */
+void mpi_free( mpi *X );
+
+/**
+ * \brief          Enlarge to the specified number of limbs
+ *
+ * \param X        MPI to grow
+ * \param nblimbs  The target number of limbs
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_grow( mpi *X, size_t nblimbs );
+
+/**
+ * \brief          Copy the contents of Y into X
+ *
+ * \param X        Destination MPI
+ * \param Y        Source MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_copy( mpi *X, const mpi *Y );
+
+/**
+ * \brief          Swap the contents of X and Y
+ *
+ * \param X        First MPI value
+ * \param Y        Second MPI value
+ */
+void mpi_swap( mpi *X, mpi *Y );
+
+/**
+ * \brief          Set value from integer
+ *
+ * \param X        MPI to set
+ * \param z        Value to use
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_lset( mpi *X, t_sint z );
+
+/**
+ * \brief          Get a specific bit from X
+ *
+ * \param X        MPI to use
+ * \param pos      Zero-based index of the bit in X
+ *
+ * \return         Either a 0 or a 1
+ */
+int mpi_get_bit( const mpi *X, size_t pos );
+
+/**
+ * \brief          Set a bit of X to a specific value of 0 or 1
+ *
+ * \note           Will grow X if necessary to set a bit to 1 in a not yet
+ *                 existing limb. Will not grow if bit should be set to 0
+ *
+ * \param X        MPI to use
+ * \param pos      Zero-based index of the bit in X
+ * \param val      The value to set the bit to (0 or 1)
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1
+ */
+int mpi_set_bit( mpi *X, size_t pos, unsigned char val );
+
+/**
+ * \brief          Return the number of zero-bits before the least significant
+ *                 '1' bit
+ *
+ * Note: Thus also the zero-based index of the least significant '1' bit
+ *
+ * \param X        MPI to use
+ */
+size_t mpi_lsb( const mpi *X );
+
+/**
+ * \brief          Return the number of bits up to and including the most
+ *                 significant '1' bit'
+ *
+ * Note: Thus also the one-based index of the most significant '1' bit
+ *
+ * \param X        MPI to use
+ */
+size_t mpi_msb( const mpi *X );
+
+/**
+ * \brief          Return the total size in bytes
+ *
+ * \param X        MPI to use
+ */
+size_t mpi_size( const mpi *X );
+
+/**
+ * \brief          Import from an ASCII string
+ *
+ * \param X        Destination MPI
+ * \param radix    Input numeric base
+ * \param s        Null-terminated string buffer
+ *
+ * \return         0 if successful, or a POLARSSL_ERR_MPI_XXX error code
+ */
+int mpi_read_string( mpi *X, int radix, const char *s );
+
+/**
+ * \brief          Export into an ASCII string
+ *
+ * \param X        Source MPI
+ * \param radix    Output numeric base
+ * \param s        String buffer
+ * \param slen     String buffer size
+ *
+ * \return         0 if successful, or a POLARSSL_ERR_MPI_XXX error code.
+ *                 *slen is always updated to reflect the amount
+ *                 of data that has (or would have) been written.
+ *
+ * \note           Call this function with *slen = 0 to obtain the
+ *                 minimum required buffer size in *slen.
+ */
+int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen );
+
+#if defined(POLARSSL_FS_IO)
+/**
+ * \brief          Read X from an opened file
+ *
+ * \param X        Destination MPI
+ * \param radix    Input numeric base
+ * \param fin      Input file handle
+ *
+ * \return         0 if successful, POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if
+ *                 the file read buffer is too small or a
+ *                 POLARSSL_ERR_MPI_XXX error code
+ */
+int mpi_read_file( mpi *X, int radix, FILE *fin );
+
+/**
+ * \brief          Write X into an opened file, or stdout if fout is NULL
+ *
+ * \param p        Prefix, can be NULL
+ * \param X        Source MPI
+ * \param radix    Output numeric base
+ * \param fout     Output file handle (can be NULL)
+ *
+ * \return         0 if successful, or a POLARSSL_ERR_MPI_XXX error code
+ *
+ * \note           Set fout == NULL to print X on the console.
+ */
+int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout );
+#endif /* POLARSSL_FS_IO */
+
+/**
+ * \brief          Import X from unsigned binary data, big endian
+ *
+ * \param X        Destination MPI
+ * \param buf      Input buffer
+ * \param buflen   Input buffer size
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen );
+
+/**
+ * \brief          Export X into unsigned binary data, big endian
+ *
+ * \param X        Source MPI
+ * \param buf      Output buffer
+ * \param buflen   Output buffer size
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
+ */
+int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen );
+
+/**
+ * \brief          Left-shift: X <<= count
+ *
+ * \param X        MPI to shift
+ * \param count    Amount to shift
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_shift_l( mpi *X, size_t count );
+
+/**
+ * \brief          Right-shift: X >>= count
+ *
+ * \param X        MPI to shift
+ * \param count    Amount to shift
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_shift_r( mpi *X, size_t count );
+
+/**
+ * \brief          Compare unsigned values
+ *
+ * \param X        Left-hand MPI
+ * \param Y        Right-hand MPI
+ *
+ * \return         1 if |X| is greater than |Y|,
+ *                -1 if |X| is lesser  than |Y| or
+ *                 0 if |X| is equal to |Y|
+ */
+int mpi_cmp_abs( const mpi *X, const mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \param X        Left-hand MPI
+ * \param Y        Right-hand MPI
+ *
+ * \return         1 if X is greater than Y,
+ *                -1 if X is lesser  than Y or
+ *                 0 if X is equal to Y
+ */
+int mpi_cmp_mpi( const mpi *X, const mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \param X        Left-hand MPI
+ * \param z        The integer value to compare to
+ *
+ * \return         1 if X is greater than z,
+ *                -1 if X is lesser  than z or
+ *                 0 if X is equal to z
+ */
+int mpi_cmp_int( const mpi *X, t_sint z );
+
+/**
+ * \brief          Unsigned addition: X = |A| + |B|
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_add_abs( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Unsigned substraction: X = |A| - |B|
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A
+ */
+int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + B
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Signed substraction: X = A - B
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + b
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param b        The integer value to add
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_add_int( mpi *X, const mpi *A, t_sint b );
+
+/**
+ * \brief          Signed substraction: X = A - b
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param b        The integer value to subtract
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_sub_int( mpi *X, const mpi *A, t_sint b );
+
+/**
+ * \brief          Baseline multiplication: X = A * B
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Baseline multiplication: X = A * b
+ *                 Note: b is an unsigned integer type, thus
+ *                 Negative values of b are ignored.
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param b        The integer value to multiply with
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_mul_int( mpi *X, const mpi *A, t_sint b );
+
+/**
+ * \brief          Division by mpi: A = Q * B + R
+ *
+ * \param Q        Destination MPI for the quotient
+ * \param R        Destination MPI for the rest value
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Division by int: A = Q * b + R
+ *
+ * \param Q        Destination MPI for the quotient
+ * \param R        Destination MPI for the rest value
+ * \param A        Left-hand MPI
+ * \param b        Integer to divide by
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b );
+
+/**
+ * \brief          Modulo: R = A mod B
+ *
+ * \param R        Destination MPI for the rest value
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0,
+ *                 POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0
+ */
+int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Modulo: r = A mod b
+ *
+ * \param r        Destination t_uint
+ * \param A        Left-hand MPI
+ * \param b        Integer to divide by
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0,
+ *                 POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0
+ */
+int mpi_mod_int( t_uint *r, const mpi *A, t_sint b );
+
+/**
+ * \brief          Sliding-window exponentiation: X = A^E mod N
+ *
+ * \param X        Destination MPI 
+ * \param A        Left-hand MPI
+ * \param E        Exponent MPI
+ * \param N        Modular MPI
+ * \param _RR      Speed-up MPI used for recalculations
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even or if
+ *                 E is negative
+ *
+ * \note           _RR is used to avoid re-computing R*R mod N across
+ *                 multiple calls, which speeds up things a bit. It can
+ *                 be set to NULL if the extra performance is unneeded.
+ */
+int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR );
+
+/**
+ * \brief          Fill an MPI X with size bytes of random
+ *
+ * \param X        Destination MPI
+ * \param size     Size in bytes
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_fill_random( mpi *X, size_t size,
+                     int (*f_rng)(void *, unsigned char *, size_t),
+                     void *p_rng );
+
+/**
+ * \brief          Greatest common divisor: G = gcd(A, B)
+ *
+ * \param G        Destination MPI
+ * \param A        Left-hand MPI
+ * \param B        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
+ */
+int mpi_gcd( mpi *G, const mpi *A, const mpi *B );
+
+/**
+ * \brief          Modular inverse: X = A^-1 mod N
+ *
+ * \param X        Destination MPI
+ * \param A        Left-hand MPI
+ * \param N        Right-hand MPI
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil
+                   POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N
+ */
+int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N );
+
+/**
+ * \brief          Miller-Rabin primality test
+ *
+ * \param X        MPI to check
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful (probably prime),
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
+ */
+int mpi_is_prime( mpi *X,
+                  int (*f_rng)(void *, unsigned char *, size_t),
+                  void *p_rng );
+
+/**
+ * \brief          Prime number generation
+ *
+ * \param X        Destination MPI
+ * \param nbits    Required size of X in bits ( 3 <= nbits <= POLARSSL_MPI_MAX_BITS )
+ * \param dh_flag  If 1, then (X-1)/2 will be prime too
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful (probably prime),
+ *                 POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
+ */
+int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag,
+                   int (*f_rng)(void *, unsigned char *, size_t),
+                   void *p_rng );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int mpi_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* bignum.h */
diff --git a/common/polarssl/bn_mul.h b/common/polarssl/bn_mul.h
new file mode 100644 (file)
index 0000000..1c2da13
--- /dev/null
@@ -0,0 +1,864 @@
+/**
+ * \file bn_mul.h
+ *
+ * \brief  Multi-precision integer library
+ *
+ *  Copyright (C) 2006-2010, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *      Multiply source vector [s] with b, add result
+ *       to destination vector [d] and set carry c.
+ *
+ *      Currently supports:
+ *
+ *         . IA-32 (386+)         . AMD64 / EM64T
+ *         . IA-32 (SSE2)         . Motorola 68000
+ *         . PowerPC, 32-bit      . MicroBlaze
+ *         . PowerPC, 64-bit      . TriCore
+ *         . SPARC v8             . ARM v3+
+ *         . Alpha                . MIPS32
+ *         . C, longlong          . C, generic
+ */
+#ifndef POLARSSL_BN_MUL_H
+#define POLARSSL_BN_MUL_H
+
+#include "bignum.h"
+
+#if defined(POLARSSL_HAVE_ASM)
+
+#if defined(__GNUC__)
+#if defined(__i386__)
+
+#define MULADDC_INIT                \
+    asm( "                          \
+        movl   %%ebx, %0;           \
+        movl   %5, %%esi;           \
+        movl   %6, %%edi;           \
+        movl   %7, %%ecx;           \
+        movl   %8, %%ebx;           \
+        "
+
+#define MULADDC_CORE                \
+        "                           \
+        lodsl;                      \
+        mull   %%ebx;               \
+        addl   %%ecx,   %%eax;      \
+        adcl   $0,      %%edx;      \
+        addl   (%%edi), %%eax;      \
+        adcl   $0,      %%edx;      \
+        movl   %%edx,   %%ecx;      \
+        stosl;                      \
+        "
+
+#if defined(POLARSSL_HAVE_SSE2)
+
+#define MULADDC_HUIT                    \
+        "                               \
+        movd     %%ecx,     %%mm1;      \
+        movd     %%ebx,     %%mm0;      \
+        movd     (%%edi),   %%mm3;      \
+        paddq    %%mm3,     %%mm1;      \
+        movd     (%%esi),   %%mm2;      \
+        pmuludq  %%mm0,     %%mm2;      \
+        movd     4(%%esi),  %%mm4;      \
+        pmuludq  %%mm0,     %%mm4;      \
+        movd     8(%%esi),  %%mm6;      \
+        pmuludq  %%mm0,     %%mm6;      \
+        movd     12(%%esi), %%mm7;      \
+        pmuludq  %%mm0,     %%mm7;      \
+        paddq    %%mm2,     %%mm1;      \
+        movd     4(%%edi),  %%mm3;      \
+        paddq    %%mm4,     %%mm3;      \
+        movd     8(%%edi),  %%mm5;      \
+        paddq    %%mm6,     %%mm5;      \
+        movd     12(%%edi), %%mm4;      \
+        paddq    %%mm4,     %%mm7;      \
+        movd     %%mm1,     (%%edi);    \
+        movd     16(%%esi), %%mm2;      \
+        pmuludq  %%mm0,     %%mm2;      \
+        psrlq    $32,       %%mm1;      \
+        movd     20(%%esi), %%mm4;      \
+        pmuludq  %%mm0,     %%mm4;      \
+        paddq    %%mm3,     %%mm1;      \
+        movd     24(%%esi), %%mm6;      \
+        pmuludq  %%mm0,     %%mm6;      \
+        movd     %%mm1,     4(%%edi);   \
+        psrlq    $32,       %%mm1;      \
+        movd     28(%%esi), %%mm3;      \
+        pmuludq  %%mm0,     %%mm3;      \
+        paddq    %%mm5,     %%mm1;      \
+        movd     16(%%edi), %%mm5;      \
+        paddq    %%mm5,     %%mm2;      \
+        movd     %%mm1,     8(%%edi);   \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm7,     %%mm1;      \
+        movd     20(%%edi), %%mm5;      \
+        paddq    %%mm5,     %%mm4;      \
+        movd     %%mm1,     12(%%edi);  \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm2,     %%mm1;      \
+        movd     24(%%edi), %%mm5;      \
+        paddq    %%mm5,     %%mm6;      \
+        movd     %%mm1,     16(%%edi);  \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm4,     %%mm1;      \
+        movd     28(%%edi), %%mm5;      \
+        paddq    %%mm5,     %%mm3;      \
+        movd     %%mm1,     20(%%edi);  \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm6,     %%mm1;      \
+        movd     %%mm1,     24(%%edi);  \
+        psrlq    $32,       %%mm1;      \
+        paddq    %%mm3,     %%mm1;      \
+        movd     %%mm1,     28(%%edi);  \
+        addl     $32,       %%edi;      \
+        addl     $32,       %%esi;      \
+        psrlq    $32,       %%mm1;      \
+        movd     %%mm1,     %%ecx;      \
+        "
+
+#define MULADDC_STOP            \
+        "                       \
+        emms;                   \
+        movl   %4, %%ebx;       \
+        movl   %%ecx, %1;       \
+        movl   %%edi, %2;       \
+        movl   %%esi, %3;       \
+        "                       \
+        : "=m" (t), "=m" (c), "=m" (d), "=m" (s)        \
+        : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b)   \
+        : "eax", "ecx", "edx", "esi", "edi"             \
+    );
+
+#else
+
+#define MULADDC_STOP            \
+        "                       \
+        movl   %4, %%ebx;       \
+        movl   %%ecx, %1;       \
+        movl   %%edi, %2;       \
+        movl   %%esi, %3;       \
+        "                       \
+        : "=m" (t), "=m" (c), "=m" (d), "=m" (s)        \
+        : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b)   \
+        : "eax", "ecx", "edx", "esi", "edi"             \
+    );
+#endif /* SSE2 */
+#endif /* i386 */
+
+#if defined(__amd64__) || defined (__x86_64__)
+
+#define MULADDC_INIT                            \
+    asm( "movq   %0, %%rsi      " :: "m" (s));  \
+    asm( "movq   %0, %%rdi      " :: "m" (d));  \
+    asm( "movq   %0, %%rcx      " :: "m" (c));  \
+    asm( "movq   %0, %%rbx      " :: "m" (b));  \
+    asm( "xorq   %r8, %r8       " );
+
+#define MULADDC_CORE                            \
+    asm( "movq  (%rsi),%rax     " );            \
+    asm( "mulq   %rbx           " );            \
+    asm( "addq   $8,   %rsi     " );            \
+    asm( "addq   %rcx, %rax     " );            \
+    asm( "movq   %r8,  %rcx     " );            \
+    asm( "adcq   $0,   %rdx     " );            \
+    asm( "nop                   " );            \
+    asm( "addq   %rax, (%rdi)   " );            \
+    asm( "adcq   %rdx, %rcx     " );            \
+    asm( "addq   $8,   %rdi     " );
+
+#define MULADDC_STOP                            \
+    asm( "movq   %%rcx, %0      " : "=m" (c));  \
+    asm( "movq   %%rdi, %0      " : "=m" (d));  \
+    asm( "movq   %%rsi, %0      " : "=m" (s) :: \
+    "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
+
+#endif /* AMD64 */
+
+#if defined(__mc68020__) || defined(__mcpu32__)
+
+#define MULADDC_INIT                            \
+    asm( "movl   %0, %%a2       " :: "m" (s));  \
+    asm( "movl   %0, %%a3       " :: "m" (d));  \
+    asm( "movl   %0, %%d3       " :: "m" (c));  \
+    asm( "movl   %0, %%d2       " :: "m" (b));  \
+    asm( "moveq  #0, %d0        " );
+
+#define MULADDC_CORE                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addl   %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "moveq  #0,  %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d4, %d3       " );
+
+#define MULADDC_STOP                            \
+    asm( "movl   %%d3, %0       " : "=m" (c));  \
+    asm( "movl   %%a3, %0       " : "=m" (d));  \
+    asm( "movl   %%a2, %0       " : "=m" (s) :: \
+    "d0", "d1", "d2", "d3", "d4", "a2", "a3" );
+
+#define MULADDC_HUIT                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d0, %d3       " );
+
+#endif /* MC68000 */
+
+#if defined(__powerpc__)   || defined(__ppc__)
+#if defined(__powerpc64__) || defined(__ppc64__)
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT                            \
+    asm( "ld     r3, %0         " :: "m" (s));  \
+    asm( "ld     r4, %0         " :: "m" (d));  \
+    asm( "ld     r5, %0         " :: "m" (c));  \
+    asm( "ld     r6, %0         " :: "m" (b));  \
+    asm( "addi   r3, r3, -8     " );            \
+    asm( "addi   r4, r4, -8     " );            \
+    asm( "addic  r5, r5,  0     " );
+
+#define MULADDC_CORE                            \
+    asm( "ldu    r7, 8(r3)      " );            \
+    asm( "mulld  r8, r7, r6     " );            \
+    asm( "mulhdu r9, r7, r6     " );            \
+    asm( "adde   r8, r8, r5     " );            \
+    asm( "ld     r7, 8(r4)      " );            \
+    asm( "addze  r5, r9         " );            \
+    asm( "addc   r8, r8, r7     " );            \
+    asm( "stdu   r8, 8(r4)      " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  r5, r5         " );            \
+    asm( "addi   r4, r4, 8      " );            \
+    asm( "addi   r3, r3, 8      " );            \
+    asm( "std    r5, %0         " : "=m" (c));  \
+    asm( "std    r4, %0         " : "=m" (d));  \
+    asm( "std    r3, %0         " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm( "ld     %%r3, %0       " :: "m" (s));  \
+    asm( "ld     %%r4, %0       " :: "m" (d));  \
+    asm( "ld     %%r5, %0       " :: "m" (c));  \
+    asm( "ld     %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -8   " );            \
+    asm( "addi   %r4, %r4, -8   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "ldu    %r7, 8(%r3)    " );            \
+    asm( "mulld  %r8, %r7, %r6  " );            \
+    asm( "mulhdu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "ld     %r7, 8(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stdu   %r8, 8(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 8    " );            \
+    asm( "addi   %r3, %r3, 8    " );            \
+    asm( "std    %%r5, %0       " : "=m" (c));  \
+    asm( "std    %%r4, %0       " : "=m" (d));  \
+    asm( "std    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#endif
+
+#else /* PPC32 */
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT                            \
+    asm( "lwz    r3, %0         " :: "m" (s));  \
+    asm( "lwz    r4, %0         " :: "m" (d));  \
+    asm( "lwz    r5, %0         " :: "m" (c));  \
+    asm( "lwz    r6, %0         " :: "m" (b));  \
+    asm( "addi   r3, r3, -4     " );            \
+    asm( "addi   r4, r4, -4     " );            \
+    asm( "addic  r5, r5,  0     " );
+
+#define MULADDC_CORE                            \
+    asm( "lwzu   r7, 4(r3)      " );            \
+    asm( "mullw  r8, r7, r6     " );            \
+    asm( "mulhwu r9, r7, r6     " );            \
+    asm( "adde   r8, r8, r5     " );            \
+    asm( "lwz    r7, 4(r4)      " );            \
+    asm( "addze  r5, r9         " );            \
+    asm( "addc   r8, r8, r7     " );            \
+    asm( "stwu   r8, 4(r4)      " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  r5, r5         " );            \
+    asm( "addi   r4, r4, 4      " );            \
+    asm( "addi   r3, r3, 4      " );            \
+    asm( "stw    r5, %0         " : "=m" (c));  \
+    asm( "stw    r4, %0         " : "=m" (d));  \
+    asm( "stw    r3, %0         " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm( "lwz    %%r3, %0       " :: "m" (s));  \
+    asm( "lwz    %%r4, %0       " :: "m" (d));  \
+    asm( "lwz    %%r5, %0       " :: "m" (c));  \
+    asm( "lwz    %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -4   " );            \
+    asm( "addi   %r4, %r4, -4   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "lwzu   %r7, 4(%r3)    " );            \
+    asm( "mullw  %r8, %r7, %r6  " );            \
+    asm( "mulhwu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "lwz    %r7, 4(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stwu   %r8, 4(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 4    " );            \
+    asm( "addi   %r3, %r3, 4    " );            \
+    asm( "stw    %%r5, %0       " : "=m" (c));  \
+    asm( "stw    %%r4, %0       " : "=m" (d));  \
+    asm( "stw    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#endif
+
+#endif /* PPC32 */
+#endif /* PPC64 */
+
+#if defined(__sparc__) && defined(__sparc64__)
+
+#define MULADDC_INIT                            \
+    asm(                                        \
+         "                                      \
+                ldx     %3, %%o0;               \
+                ldx     %4, %%o1;               \
+                ld      %5, %%o2;               \
+                ld      %6, %%o3;               \
+         "
+
+#define MULADDC_CORE                            \
+         "                                      \
+                ld      [%%o0], %%o4;           \
+                inc     4, %%o0;                \
+                ld      [%%o1], %%o5;           \
+                umul    %%o3, %%o4, %%o4;       \
+                addcc   %%o4, %%o2, %%o4;       \
+                rd      %%y, %%g1;              \
+                addx    %%g1, 0, %%g1;          \
+                addcc   %%o4, %%o5, %%o4;       \
+                st      %%o4, [%%o1];           \
+                addx    %%g1, 0, %%o2;          \
+                inc     4, %%o1;                \
+        "
+
+#define MULADDC_STOP                            \
+        "                                       \
+                st      %%o2, %0;               \
+                stx     %%o1, %1;               \
+                stx     %%o0, %2;               \
+        "                                       \
+        : "=m" (c), "=m" (d), "=m" (s)          \
+        : "m" (s), "m" (d), "m" (c), "m" (b)    \
+        : "g1", "o0", "o1", "o2", "o3", "o4",   \
+          "o5"                                  \
+        );
+#endif /* SPARCv9 */
+
+#if defined(__sparc__) && !defined(__sparc64__)
+
+#define MULADDC_INIT                            \
+    asm(                                        \
+         "                                      \
+                ld      %3, %%o0;               \
+                ld      %4, %%o1;               \
+                ld      %5, %%o2;               \
+                ld      %6, %%o3;               \
+         "
+
+#define MULADDC_CORE                            \
+         "                                      \
+                ld      [%%o0], %%o4;           \
+                inc     4, %%o0;                \
+                ld      [%%o1], %%o5;           \
+                umul    %%o3, %%o4, %%o4;       \
+                addcc   %%o4, %%o2, %%o4;       \
+                rd      %%y, %%g1;              \
+                addx    %%g1, 0, %%g1;          \
+                addcc   %%o4, %%o5, %%o4;       \
+                st      %%o4, [%%o1];           \
+                addx    %%g1, 0, %%o2;          \
+                inc     4, %%o1;                \
+        "
+
+#define MULADDC_STOP                            \
+        "                                       \
+                st      %%o2, %0;               \
+                st      %%o1, %1;               \
+                st      %%o0, %2;               \
+        "                                       \
+        : "=m" (c), "=m" (d), "=m" (s)          \
+        : "m" (s), "m" (d), "m" (c), "m" (b)    \
+        : "g1", "o0", "o1", "o2", "o3", "o4",   \
+          "o5"                                  \
+        );
+
+#endif /* SPARCv8 */
+
+#if defined(__microblaze__) || defined(microblaze)
+
+#define MULADDC_INIT                            \
+    asm( "lwi   r3,   %0        " :: "m" (s));  \
+    asm( "lwi   r4,   %0        " :: "m" (d));  \
+    asm( "lwi   r5,   %0        " :: "m" (c));  \
+    asm( "lwi   r6,   %0        " :: "m" (b));  \
+    asm( "andi  r7,   r6, 0xffff" );            \
+    asm( "bsrli r6,   r6, 16    " );
+
+#define MULADDC_CORE                            \
+    asm( "lhui  r8,   r3,   0   " );            \
+    asm( "addi  r3,   r3,   2   " );            \
+    asm( "lhui  r9,   r3,   0   " );            \
+    asm( "addi  r3,   r3,   2   " );            \
+    asm( "mul   r10,  r9,  r6   " );            \
+    asm( "mul   r11,  r8,  r7   " );            \
+    asm( "mul   r12,  r9,  r7   " );            \
+    asm( "mul   r13,  r8,  r6   " );            \
+    asm( "bsrli  r8, r10,  16   " );            \
+    asm( "bsrli  r9, r11,  16   " );            \
+    asm( "add   r13, r13,  r8   " );            \
+    asm( "add   r13, r13,  r9   " );            \
+    asm( "bslli r10, r10,  16   " );            \
+    asm( "bslli r11, r11,  16   " );            \
+    asm( "add   r12, r12, r10   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "add   r12, r12, r11   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "lwi   r10,  r4,   0   " );            \
+    asm( "add   r12, r12, r10   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "add   r12, r12,  r5   " );            \
+    asm( "addc   r5, r13,  r0   " );            \
+    asm( "swi   r12,  r4,   0   " );            \
+    asm( "addi   r4,  r4,   4   " );
+
+#define MULADDC_STOP                            \
+    asm( "swi   r5,   %0        " : "=m" (c));  \
+    asm( "swi   r4,   %0        " : "=m" (d));  \
+    asm( "swi   r3,   %0        " : "=m" (s) :: \
+     "r3", "r4" , "r5" , "r6" , "r7" , "r8" ,   \
+     "r9", "r10", "r11", "r12", "r13" );
+
+#endif /* MicroBlaze */
+
+#if defined(__tricore__)
+
+#define MULADDC_INIT                            \
+    asm( "ld.a   %%a2, %0       " :: "m" (s));  \
+    asm( "ld.a   %%a3, %0       " :: "m" (d));  \
+    asm( "ld.w   %%d4, %0       " :: "m" (c));  \
+    asm( "ld.w   %%d1, %0       " :: "m" (b));  \
+    asm( "xor    %d5, %d5       " );
+
+#define MULADDC_CORE                            \
+    asm( "ld.w   %d0,   [%a2+]      " );        \
+    asm( "madd.u %e2, %e4, %d0, %d1 " );        \
+    asm( "ld.w   %d0,   [%a3]       " );        \
+    asm( "addx   %d2,    %d2,  %d0  " );        \
+    asm( "addc   %d3,    %d3,    0  " );        \
+    asm( "mov    %d4,    %d3        " );        \
+    asm( "st.w  [%a3+],  %d2        " );
+
+#define MULADDC_STOP                            \
+    asm( "st.w   %0, %%d4       " : "=m" (c));  \
+    asm( "st.a   %0, %%a3       " : "=m" (d));  \
+    asm( "st.a   %0, %%a2       " : "=m" (s) :: \
+    "d0", "d1", "e2", "d4", "a2", "a3" );
+
+#endif /* TriCore */
+
+#if defined(__arm__)
+
+#if defined(__thumb__) && !defined(__thumb2__)
+
+#define MULADDC_INIT                            \
+    asm(                                        \
+         "                                      \
+            ldr    r0, %3;                      \
+            ldr    r1, %4;                      \
+            ldr    r2, %5;                      \
+            ldr    r3, %6;                      \
+            lsr    r7, r3, #16;                 \
+            mov    r9, r7;                      \
+            lsl    r7, r3, #16;                 \
+            lsr    r7, r7, #16;                 \
+            mov    r8, r7;                      \
+         "
+
+#define MULADDC_CORE                            \
+         "                                      \
+            ldmia  r0!, {r6};                   \
+            lsr    r7, r6, #16;                 \
+            lsl    r6, r6, #16;                 \
+            lsr    r6, r6, #16;                 \
+            mov    r4, r8;                      \
+            mul    r4, r6;                      \
+            mov    r3, r9;                      \
+            mul    r6, r3;                      \
+            mov    r5, r9;                      \
+            mul    r5, r7;                      \
+            mov    r3, r8;                      \
+            mul    r7, r3;                      \
+            lsr    r3, r6, #16;                 \
+            add    r5, r5, r3;                  \
+            lsr    r3, r7, #16;                 \
+            add    r5, r5, r3;                  \
+            add    r4, r4, r2;                  \
+            mov    r2, #0;                      \
+            adc    r5, r2;                      \
+            lsl    r3, r6, #16;                 \
+            add    r4, r4, r3;                  \
+            adc    r5, r2;                      \
+            lsl    r3, r7, #16;                 \
+            add    r4, r4, r3;                  \
+            adc    r5, r2;                      \
+            ldr    r3, [r1];                    \
+            add    r4, r4, r3;                  \
+            adc    r2, r5;                      \
+            stmia  r1!, {r4};                   \
+         "
+
+#define MULADDC_STOP                            \
+         "                                      \
+            str    r2, %0;                      \
+            str    r1, %1;                      \
+            str    r0, %2;                      \
+         "                                      \
+         : "=m" (c),  "=m" (d), "=m" (s)        \
+         : "m" (s), "m" (d), "m" (c), "m" (b)   \
+         : "r0", "r1", "r2", "r3", "r4", "r5",  \
+           "r6", "r7", "r8", "r9", "cc"         \
+         );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm(                                        \
+         "                                     \
+            ldr    r0, %3;                      \
+            ldr    r1, %4;                      \
+            ldr    r2, %5;                      \
+            ldr    r3, %6;                      \
+         "
+
+#define MULADDC_CORE                            \
+         "                                      \
+            ldr    r4, [r0], #4;                \
+            mov    r5, #0;                      \
+            ldr    r6, [r1];                    \
+            umlal  r2, r5, r3, r4;              \
+            adds   r7, r6, r2;                  \
+            adc    r2, r5, #0;                  \
+            str    r7, [r1], #4;                \
+         "
+
+#define MULADDC_STOP                            \
+         "                                      \
+            str    r2, %0;                      \
+            str    r1, %1;                      \
+            str    r0, %2;                      \
+         "                                      \
+         : "=m" (c),  "=m" (d), "=m" (s)        \
+         : "m" (s), "m" (d), "m" (c), "m" (b)   \
+         : "r0", "r1", "r2", "r3", "r4", "r5",  \
+           "r6", "r7", "cc"                     \
+         );
+
+#endif /* Thumb */
+
+#endif /* ARMv3 */
+
+#if defined(__alpha__)
+
+#define MULADDC_INIT                            \
+    asm( "ldq    $1, %0         " :: "m" (s));  \
+    asm( "ldq    $2, %0         " :: "m" (d));  \
+    asm( "ldq    $3, %0         " :: "m" (c));  \
+    asm( "ldq    $4, %0         " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ldq    $6,  0($1)     " );            \
+    asm( "addq   $1,  8, $1     " );            \
+    asm( "mulq   $6, $4, $7     " );            \
+    asm( "umulh  $6, $4, $6     " );            \
+    asm( "addq   $7, $3, $7     " );            \
+    asm( "cmpult $7, $3, $3     " );            \
+    asm( "ldq    $5,  0($2)     " );            \
+    asm( "addq   $7, $5, $7     " );            \
+    asm( "cmpult $7, $5, $5     " );            \
+    asm( "stq    $7,  0($2)     " );            \
+    asm( "addq   $2,  8, $2     " );            \
+    asm( "addq   $6, $3, $3     " );            \
+    asm( "addq   $5, $3, $3     " );
+
+#define MULADDC_STOP                            \
+    asm( "stq    $3, %0         " : "=m" (c));  \
+    asm( "stq    $2, %0         " : "=m" (d));  \
+    asm( "stq    $1, %0         " : "=m" (s) :: \
+    "$1", "$2", "$3", "$4", "$5", "$6", "$7" );
+
+#endif /* Alpha */
+
+#if defined(__mips__)
+
+#define MULADDC_INIT                            \
+    asm( "lw     $10, %0        " :: "m" (s));  \
+    asm( "lw     $11, %0        " :: "m" (d));  \
+    asm( "lw     $12, %0        " :: "m" (c));  \
+    asm( "lw     $13, %0        " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "lw     $14, 0($10)    " );            \
+    asm( "multu  $13, $14       " );            \
+    asm( "addi   $10, $10, 4    " );            \
+    asm( "mflo   $14            " );            \
+    asm( "mfhi   $9             " );            \
+    asm( "addu   $14, $12, $14  " );            \
+    asm( "lw     $15, 0($11)    " );            \
+    asm( "sltu   $12, $14, $12  " );            \
+    asm( "addu   $15, $14, $15  " );            \
+    asm( "sltu   $14, $15, $14  " );            \
+    asm( "addu   $12, $12, $9   " );            \
+    asm( "sw     $15, 0($11)    " );            \
+    asm( "addu   $12, $12, $14  " );            \
+    asm( "addi   $11, $11, 4    " );
+
+#define MULADDC_STOP                            \
+    asm( "sw     $12, %0        " : "=m" (c));  \
+    asm( "sw     $11, %0        " : "=m" (d));  \
+    asm( "sw     $10, %0        " : "=m" (s) :: \
+    "$9", "$10", "$11", "$12", "$13", "$14", "$15" );
+
+#endif /* MIPS */
+#endif /* GNUC */
+
+#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+
+#define MULADDC_INIT                            \
+    __asm   mov     esi, s                      \
+    __asm   mov     edi, d                      \
+    __asm   mov     ecx, c                      \
+    __asm   mov     ebx, b
+
+#define MULADDC_CORE                            \
+    __asm   lodsd                               \
+    __asm   mul     ebx                         \
+    __asm   add     eax, ecx                    \
+    __asm   adc     edx, 0                      \
+    __asm   add     eax, [edi]                  \
+    __asm   adc     edx, 0                      \
+    __asm   mov     ecx, edx                    \
+    __asm   stosd
+
+#if defined(POLARSSL_HAVE_SSE2)
+
+#define EMIT __asm _emit
+
+#define MULADDC_HUIT                            \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC9             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC3             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x1F             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x16             \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x7E  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xEE             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x67  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xFC             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x0F             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x56  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5E  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCD             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xD5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCF             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xE5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xF5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDD             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCE             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x1C  \
+    EMIT 0x83  EMIT 0xC7  EMIT 0x20             \
+    EMIT 0x83  EMIT 0xC6  EMIT 0x20             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0xC9
+
+#define MULADDC_STOP                            \
+