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.
31 #include "proxmark3.h"
32 #include "fileutils.h"
35 #define BCD(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : -1)
37 #define HEX(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
38 ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
39 ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
42 #define TOHEX(v) ((v) < 10 ? (v) + '0' : (v) - 10 + 'a')
44 static ssize_t
emv_pk_read_bin(char *buf
, size_t buflen
, unsigned char *bin
, size_t size
, size_t *read
) {
51 while ((*p
== ' ') && (p
< (buf
+ buflen
- 1)))
59 if (p
== (buf
+ buflen
- 1))
65 if (p
== (buf
+ buflen
- 1))
68 *bin
= (c1
* 16 + c2
);
71 if ((*p
== ':') && (p
< (buf
+ buflen
- 1)))
74 *read
= (size
- left
);
82 while ((*p
== ' ') && (p
< (buf
+ buflen
- 1)))
90 static ssize_t
emv_pk_read_ymv(char *buf
, size_t buflen
, unsigned *ymv
) {
95 unsigned char temp
[3];
100 while ((*p
== ' ') && (p
< (buf
+ buflen
- 1)))
103 for (int i
= 0; i
< 3; i
++) {
108 if (p
== (buf
+ buflen
- 1))
114 if (p
== (buf
+ buflen
- 1))
117 temp
[i
] = (c1
* 16 + c2
);
120 while ((*p
== ' ') && (p
< (buf
+ buflen
- 1)))
125 if (temp
[1] > 0x12 || temp
[2] > 0x31)
128 *ymv
= (temp
[0] * 0x10000 + temp
[1] * 0x100 + temp
[2]);
133 static ssize_t
emv_pk_read_string(char *buf
, size_t buflen
, char *str
, size_t size
) {
139 while ((*p
== ' ') && (p
< (buf
+ buflen
- 1)))
145 else if (*p
< 0x20 || *p
>= 0x7f)
148 if (p
== (buf
+ buflen
- 1))
157 while ((*p
== ' ') && (p
< (buf
+ buflen
- 1)))
165 struct emv_pk
*emv_pk_parse_pk(char *buf
, size_t buflen
) {
166 struct emv_pk
*r
= calloc(1, sizeof(*r
));
170 l
= emv_pk_read_bin(buf
, buflen
, r
->rid
, 5, NULL
);
175 l
= emv_pk_read_bin(buf
, buflen
, &r
->index
, 1, NULL
);
180 l
= emv_pk_read_ymv(buf
, buflen
, &r
->expire
);
185 l
= emv_pk_read_string(buf
, buflen
, temp
, sizeof(temp
));
190 if (!strcmp(temp
, "rsa"))
195 l
= emv_pk_read_bin(buf
, buflen
, r
->exp
, sizeof(r
->exp
), &r
->elen
);
200 r
->modulus
= malloc(2048 / 8);
201 l
= emv_pk_read_bin(buf
, buflen
, r
->modulus
, 2048 / 8, &r
->mlen
);
206 l
= emv_pk_read_string(buf
, buflen
, temp
, sizeof(temp
));
211 if (!strcmp(temp
, "sha1"))
212 r
->hash_algo
= HASH_SHA_1
;
216 l
= emv_pk_read_bin(buf
, buflen
, r
->hash
, 20, NULL
);
229 static size_t emv_pk_write_bin(char *out
, size_t outlen
, const unsigned char *buf
, size_t len
) {
235 if (outlen
< len
* 3)
238 out
[pos
++] = TOHEX(buf
[0] >> 4);
239 out
[pos
++] = TOHEX(buf
[0] & 0xf);
240 for (i
= 1; i
< len
; i
++) {
242 out
[pos
++] = TOHEX(buf
[i
] >> 4);
243 out
[pos
++] = TOHEX(buf
[i
] & 0xf);
250 static size_t emv_pk_write_str(char *out
, size_t outlen
, const char *str
) {
251 size_t len
= strlen(str
);
258 memcpy(out
, str
, len
);
263 char *emv_pk_dump_pk(const struct emv_pk
*pk
) {
265 size_t outsize
= 1024; /* should be enough */
266 char *out
= malloc(outsize
); /* should be enough */
270 size_t rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, pk
->rid
, 5);
276 rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, &pk
->index
, 1);
282 if (outpos
+ 7 > outsize
)
284 out
[outpos
++] = TOHEX((pk
->expire
>> 20) & 0xf);
285 out
[outpos
++] = TOHEX((pk
->expire
>> 16) & 0xf);
286 out
[outpos
++] = TOHEX((pk
->expire
>> 12) & 0xf);
287 out
[outpos
++] = TOHEX((pk
->expire
>> 8) & 0xf);
288 out
[outpos
++] = TOHEX((pk
->expire
>> 4) & 0xf);
289 out
[outpos
++] = TOHEX((pk
->expire
>> 0) & 0xf);
292 if (pk
->pk_algo
== PK_RSA
) {
293 rc
= emv_pk_write_str(out
+ outpos
, outsize
- outpos
, "rsa");
299 if (outpos
+ 4 > outsize
)
303 out
[outpos
++] = TOHEX(pk
->pk_algo
>> 4);
304 out
[outpos
++] = TOHEX(pk
->pk_algo
& 0xf);
307 rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, pk
->exp
, pk
->elen
);
312 rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, pk
->modulus
, pk
->mlen
);
317 if (pk
->hash_algo
== HASH_SHA_1
) {
318 rc
= emv_pk_write_str(out
+ outpos
, outsize
- outpos
, "sha1");
324 if (outpos
+ 4 > outsize
)
328 out
[outpos
++] = TOHEX(pk
->pk_algo
>> 4);
329 out
[outpos
++] = TOHEX(pk
->pk_algo
& 0xf);
333 rc
= emv_pk_write_bin(out
+ outpos
, outsize
- outpos
, pk
->hash
, 20);
338 out
[outpos
- 1] = '\0';
347 bool emv_pk_verify(const struct emv_pk
*pk
) {
348 struct crypto_hash
*ch
= crypto_hash_open(pk
->hash_algo
);
352 crypto_hash_write(ch
, pk
->rid
, sizeof(pk
->rid
));
353 crypto_hash_write(ch
, &pk
->index
, 1);
354 crypto_hash_write(ch
, pk
->modulus
, pk
->mlen
);
355 crypto_hash_write(ch
, pk
->exp
, pk
->elen
);
357 unsigned char *h
= crypto_hash_read(ch
);
359 crypto_hash_close(ch
);
363 size_t hsize
= crypto_hash_get_size(ch
);
364 bool r
= hsize
&& !memcmp(h
, pk
->hash
, hsize
) ? true : false;
366 crypto_hash_close(ch
);
371 struct emv_pk
*emv_pk_new(size_t modlen
, size_t explen
) {
374 /* Not supported ATM */
378 pk
= calloc(1, sizeof(*pk
));
385 pk
->modulus
= calloc(modlen
, 1);
394 void emv_pk_free(struct emv_pk
*pk
) {
402 static struct emv_pk
*emv_pk_get_ca_pk_from_file(const char *fname
,
403 const unsigned char *rid
,
408 FILE *f
= fopen(fname
, "r");
410 PrintAndLogEx(ERR
, "Error: can't open file %s.", fname
);
416 if (fgets(buf
, sizeof(buf
), f
) == NULL
)
419 struct emv_pk
*pk
= emv_pk_parse_pk(buf
, sizeof(buf
));
423 if (memcmp(pk
->rid
, rid
, 5) || pk
->index
!= idx
) {
436 char *emv_pk_get_ca_pk_file(const char *dirname
, const unsigned char *rid
, unsigned char idx
) {
438 dirname
= ".";//openemv_config_get_str("capk.dir", NULL);
441 int ret
= asprintf(&filename
, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0",
456 char *emv_pk_get_ca_pk_rid_file(const char *dirname
, const unsigned char *rid
) {
458 dirname
= "."; //openemv_config_get_str("capk.dir", NULL);
461 int ret
= asprintf(&filename
, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks",
475 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 if (searchFile(&path
, RESOURCES_SUBDIR
, "capk", ".txt", false) != PM3_SUCCESS
) {
498 pk
= emv_pk_get_ca_pk_from_file(path
, rid
, idx
);
504 bool isok
= emv_pk_verify(pk
);
506 PrintAndLogEx(INFO
, "Verifying CA PK for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zu bits. ( %s )",
514 (isok
) ? _GREEN_("ok") : _RED_("failed")