2 * libopenemv - a library to work with EMV family of smart cards
3 * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
26 #include "proxmark3.h"
31 #include <sys/types.h>
33 #define BCD(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
36 #define HEX(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
37 ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
38 ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
41 #define TOHEX(v) ((v) < 10 ? (v) + '0' : (v) - 10 + 'a')
43 static ssize_t
emv_pk_read_bin(char *buf
, unsigned char *bin
, size_t size
, size_t *read
)
47 while (*p
&& (*p
== ' ' || *p
== '\t'))
60 *bin
= (c1
* 16 + c2
);
66 *read
= (size
- left
);
74 while (*p
&& (*p
== ' ' || *p
== '\t'))
82 static ssize_t
emv_pk_read_ymv(char *buf
, unsigned *ymv
)
85 unsigned char temp
[3];
90 while (*p
&& (*p
== ' ' || *p
== '\t'))
93 for (i
= 0; i
< 3; i
++) {
103 temp
[i
] = (c1
* 16 + c2
);
106 while (*p
&& (*p
== ' ' || *p
== '\t'))
111 if (temp
[1] > 0x12 || temp
[2] > 0x31)
114 *ymv
= (temp
[0] * 0x10000 + temp
[1] * 0x100 + temp
[2]);
119 static ssize_t
emv_pk_read_string(char *buf
, char *str
, size_t size
)
122 while (*p
&& (*p
== ' ' || *p
== '\t'))
126 if (*p
== ' ' || *p
== '\t')
128 else if (*p
< 0x20 || *p
>= 0x7f)
138 while (*p
&& (*p
== ' ' || *p
== '\t'))
147 struct emv_pk
*emv_pk_parse_pk(char *buf
)
149 struct emv_pk
*r
= calloc(1, sizeof(*r
));
153 l
= emv_pk_read_bin(buf
, r
->rid
, 5, NULL
);
158 l
= emv_pk_read_bin(buf
, &r
->index
, 1, NULL
);
163 l
= emv_pk_read_ymv(buf
, &r
->expire
);
168 l
= emv_pk_read_string(buf
, temp
, sizeof(temp
));
173 if (!strcmp(temp
, "rsa"))
178 l
= emv_pk_read_bin(buf
, r
->exp
, sizeof(r
->exp
), &r
->elen
);
183 r
->modulus
= malloc(2048/8);
184 l
= emv_pk_read_bin(buf
, r
->modulus
, 2048/8, &r
->mlen
);
189 l
= emv_pk_read_string(buf
, temp
, sizeof(temp
));
194 if (!strcmp(temp
, "sha1"))
195 r
->hash_algo
= HASH_SHA_1
;
199 l
= emv_pk_read_bin(buf
, r
->hash
, 20, NULL
);
212 static size_t emv_pk_write_bin(char *out
, size_t outlen
, const unsigned char *buf
, size_t len
)
219 if (outlen
< len
* 3)
222 out
[pos
++] = TOHEX(buf
[0] >> 4);
223 out
[pos
++] = TOHEX(buf
[0] & 0xf);
224 for (i
= 1; i
< len
; i
++) {
226 out
[pos
++] = TOHEX(buf
[i
] >> 4);
227 out
[pos
++] = TOHEX(buf
[i
] & 0xf);
234 static size_t emv_pk_write_str(char *out
, size_t outlen
, const char *str
)
236 size_t len
= strlen(str
);
243 memcpy(out
, str
, len
);
248 char *emv_pk_dump_pk(const struct emv_pk
*pk
)
250 size_t outsize
= 1024; /* should be enough */
251 char *out
= malloc(outsize
); /* should be enough */
258 rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, pk
->rid
, 5);
263 rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, &pk
->index
, 1);
268 if (outpos
+ 7 > outsize
)
270 out
[outpos
++] = TOHEX((pk
->expire
>> 20) & 0xf);
271 out
[outpos
++] = TOHEX((pk
->expire
>> 16) & 0xf);
272 out
[outpos
++] = TOHEX((pk
->expire
>> 12) & 0xf);
273 out
[outpos
++] = TOHEX((pk
->expire
>> 8 ) & 0xf);
274 out
[outpos
++] = TOHEX((pk
->expire
>> 4 ) & 0xf);
275 out
[outpos
++] = TOHEX((pk
->expire
>> 0 ) & 0xf);
278 if (pk
->pk_algo
== PK_RSA
) {
279 rc
= emv_pk_write_str(out
+ outpos
, outsize
- outpos
, "rsa");
285 if (outpos
+ 4 > outsize
)
289 out
[outpos
++] = TOHEX(pk
->pk_algo
>> 4);
290 out
[outpos
++] = TOHEX(pk
->pk_algo
& 0xf);
293 rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, pk
->exp
, pk
->elen
);
298 rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, pk
->modulus
, pk
->mlen
);
303 if (pk
->hash_algo
== HASH_SHA_1
) {
304 rc
= emv_pk_write_str(out
+ outpos
, outsize
- outpos
, "sha1");
310 if (outpos
+ 4 > outsize
)
314 out
[outpos
++] = TOHEX(pk
->pk_algo
>> 4);
315 out
[outpos
++] = TOHEX(pk
->pk_algo
& 0xf);
319 rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, pk
->hash
, 20);
324 out
[outpos
-1] = '\0';
333 bool emv_pk_verify(const struct emv_pk
*pk
)
335 struct crypto_hash
*ch
= crypto_hash_open(pk
->hash_algo
);
339 crypto_hash_write(ch
, pk
->rid
, sizeof(pk
->rid
));
340 crypto_hash_write(ch
, &pk
->index
, 1);
341 crypto_hash_write(ch
, pk
->modulus
, pk
->mlen
);
342 crypto_hash_write(ch
, pk
->exp
, pk
->elen
);
344 unsigned char *h
= crypto_hash_read(ch
);
346 crypto_hash_close(ch
);
350 size_t hsize
= crypto_hash_get_size(ch
);
351 bool r
= hsize
&& !memcmp(h
, pk
->hash
, hsize
) ? true : false;
353 crypto_hash_close(ch
);
358 struct emv_pk
*emv_pk_new(size_t modlen
, size_t explen
)
362 /* Not supported ATM */
366 pk
= calloc(1, sizeof(*pk
));
373 pk
->modulus
= calloc(modlen
, 1);
382 void emv_pk_free(struct emv_pk
*pk
)
391 static struct emv_pk
*emv_pk_get_ca_pk_from_file(const char *fname
,
392 const unsigned char *rid
,
398 FILE *f
= fopen(fname
, "r");
406 if (fgets(buf
, sizeof(buf
), f
) == NULL
)
409 struct emv_pk
*pk
= emv_pk_parse_pk(buf
);
412 if (memcmp(pk
->rid
, rid
, 5) || pk
->index
!= idx
) {
427 char *emv_pk_get_ca_pk_file(const char *dirname
, const unsigned char *rid
, unsigned char idx
)
430 dirname
= ".";//openemv_config_get_str("capk.dir", NULL);
436 int ret
= asprintf(&filename
, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0",
451 char *emv_pk_get_ca_pk_rid_file(const char *dirname
, const unsigned char *rid
)
454 dirname
= "."; //openemv_config_get_str("capk.dir", NULL);
460 int ret
= asprintf(&filename
, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks",
474 struct emv_pk
*emv_pk_get_ca_pk(const unsigned char *rid
, unsigned char idx
)
476 struct emv_pk
*pk
= NULL
;
479 char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
481 pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
487 char *fname = emv_pk_get_ca_pk_rid_file(NULL, rid);
489 pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
495 const char *relfname
= "emv/capk.txt";
497 char fname
[strlen(get_my_executable_directory()) + strlen(relfname
) + 1];
498 strcpy(fname
, get_my_executable_directory());
499 strcat(fname
, relfname
);
501 pk
= emv_pk_get_ca_pk_from_file(fname
, rid
, idx
);
506 printf("Verifying CA Public Key for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...",
514 if (emv_pk_verify(pk
)) {