]> git.zerfleddert.de Git - proxmark3-svn/blob - client/emv/emv_pk.c
Code improved for less memory
[proxmark3-svn] / client / emv / emv_pk.c
1 /*
2 * libopenemv - a library to work with EMV family of smart cards
3 * Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
4 *
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.
9 *
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.
14 */
15
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 /* For asprintf */
21 #define _GNU_SOURCE
22 #include <stdio.h>
23
24 #include "emv_pk.h"
25 #include "crypto.h"
26 #include "proxmark3.h"
27
28 #include <stdbool.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <sys/types.h>
32
33 #define BCD(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
34 -1)
35
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) : \
39 -1)
40
41 #define TOHEX(v) ((v) < 10 ? (v) + '0' : (v) - 10 + 'a')
42
43 static ssize_t emv_pk_read_bin(char *buf, unsigned char *bin, size_t size, size_t *read)
44 {
45 size_t left = size;
46 char *p = buf;
47 while (*p && (*p == ' ' || *p == '\t'))
48 p++;
49
50 while (left > 0) {
51 int c1, c2;
52 c1 = HEX(*p);
53 if (c1 == -1)
54 return -(p - buf);
55 p++;
56 c2 = HEX(*p);
57 if (c2 == -1)
58 return -(p - buf);
59 p++;
60 *bin = (c1 * 16 + c2);
61 bin ++;
62 left --;
63 if (*p == ':')
64 p++;
65 else if (read) {
66 *read = (size - left);
67 break;
68 } else if (left == 0)
69 break;
70 else
71 return -(p - buf);
72 }
73
74 while (*p && (*p == ' ' || *p == '\t'))
75 p++;
76
77 p--;
78
79 return (p - buf);
80 }
81
82 static ssize_t emv_pk_read_ymv(char *buf, unsigned *ymv)
83 {
84 int i;
85 unsigned char temp[3];
86 char *p = buf;
87
88 *ymv = 0;
89
90 while (*p && (*p == ' ' || *p == '\t'))
91 p++;
92
93 for (i = 0; i < 3; i++) {
94 int c1, c2;
95 c1 = BCD(*p);
96 if (c1 == -1)
97 return -(p - buf);
98 p++;
99 c2 = BCD(*p);
100 if (c2 == -1)
101 return -(p - buf);
102 p++;
103 temp[i] = (c1 * 16 + c2);
104 }
105
106 while (*p && (*p == ' ' || *p == '\t'))
107 p++;
108
109 p--;
110
111 if (temp[1] > 0x12 || temp[2] > 0x31)
112 return -(p - buf);
113
114 *ymv = (temp[0] * 0x10000 + temp[1] * 0x100 + temp[2]);
115
116 return (p - buf);
117 }
118
119 static ssize_t emv_pk_read_string(char *buf, char *str, size_t size)
120 {
121 char *p = buf;
122 while (*p && (*p == ' ' || *p == '\t'))
123 p++;
124
125 while (size > 1) {
126 if (*p == ' ' || *p == '\t')
127 break;
128 else if (*p < 0x20 || *p >= 0x7f)
129 return -(p - buf);
130 *str = *p;
131 p++;
132 str ++;
133 size --;
134 }
135
136 *str = 0;
137
138 while (*p && (*p == ' ' || *p == '\t'))
139 p++;
140
141 p--;
142
143 return (p - buf);
144 }
145
146
147 struct emv_pk *emv_pk_parse_pk(char *buf)
148 {
149 struct emv_pk *r = calloc(1, sizeof(*r));
150 ssize_t l;
151 char temp[10];
152
153 l = emv_pk_read_bin(buf, r->rid, 5, NULL);
154 if (l <= 0)
155 goto out;
156 buf += l;
157
158 l = emv_pk_read_bin(buf, &r->index, 1, NULL);
159 if (l <= 0)
160 goto out;
161 buf += l;
162
163 l = emv_pk_read_ymv(buf, &r->expire);
164 if (l <= 0)
165 goto out;
166 buf += l;
167
168 l = emv_pk_read_string(buf, temp, sizeof(temp));
169 if (l <= 0)
170 goto out;
171 buf += l;
172
173 if (!strcmp(temp, "rsa"))
174 r->pk_algo = PK_RSA;
175 else
176 goto out;
177
178 l = emv_pk_read_bin(buf, r->exp, sizeof(r->exp), &r->elen);
179 if (l <= 0)
180 goto out;
181 buf += l;
182
183 r->modulus = malloc(2048/8);
184 l = emv_pk_read_bin(buf, r->modulus, 2048/8, &r->mlen);
185 if (l <= 0)
186 goto out2;
187 buf += l;
188
189 l = emv_pk_read_string(buf, temp, sizeof(temp));
190 if (l <= 0)
191 goto out2;
192 buf += l;
193
194 if (!strcmp(temp, "sha1"))
195 r->hash_algo = HASH_SHA_1;
196 else
197 goto out2;
198
199 l = emv_pk_read_bin(buf, r->hash, 20, NULL);
200 if (l <= 0)
201 goto out2;
202
203 return r;
204
205 out2:
206 free(r->modulus);
207 out:
208 free(r);
209 return NULL;
210 }
211
212 static size_t emv_pk_write_bin(char *out, size_t outlen, const unsigned char *buf, size_t len)
213 {
214 int i;
215 size_t pos = 0;
216
217 if (len == 0)
218 return 0;
219 if (outlen < len * 3)
220 return 0;
221
222 out[pos++] = TOHEX(buf[0] >> 4);
223 out[pos++] = TOHEX(buf[0] & 0xf);
224 for (i = 1; i < len; i++) {
225 out[pos++] = ':';
226 out[pos++] = TOHEX(buf[i] >> 4);
227 out[pos++] = TOHEX(buf[i] & 0xf);
228 }
229 out[pos++] = ' ';
230
231 return pos;
232 }
233
234 static size_t emv_pk_write_str(char *out, size_t outlen, const char *str)
235 {
236 size_t len = strlen(str);
237
238 if (len == 0)
239 return 0;
240 if (outlen < len)
241 return 0;
242
243 memcpy(out, str, len);
244
245 return len;
246 }
247
248 char *emv_pk_dump_pk(const struct emv_pk *pk)
249 {
250 size_t outsize = 1024; /* should be enough */
251 char *out = malloc(outsize); /* should be enough */
252 size_t outpos = 0;
253 size_t rc;
254
255 if (!out)
256 return NULL;
257
258 rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->rid, 5);
259 if (rc == 0)
260 goto err;
261 outpos += rc;
262
263 rc = emv_pk_write_bin(out + outpos, outsize - outpos, &pk->index, 1);
264 if (rc == 0)
265 goto err;
266 outpos += rc;
267
268 if (outpos + 7 > outsize)
269 goto err;
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);
276 out[outpos++] = ' ';
277
278 if (pk->pk_algo == PK_RSA) {
279 rc = emv_pk_write_str(out + outpos, outsize - outpos, "rsa");
280 if (rc == 0)
281 goto err;
282 outpos += rc;
283 out[outpos++] = ' ';
284 } else {
285 if (outpos + 4 > outsize)
286 goto err;
287 out[outpos++] = '?';
288 out[outpos++] = '?';
289 out[outpos++] = TOHEX(pk->pk_algo >> 4);
290 out[outpos++] = TOHEX(pk->pk_algo & 0xf);
291 }
292
293 rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->exp, pk->elen);
294 if (rc == 0)
295 goto err;
296 outpos += rc;
297
298 rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->modulus, pk->mlen);
299 if (rc == 0)
300 goto err;
301 outpos += rc;
302
303 if (pk->hash_algo == HASH_SHA_1) {
304 rc = emv_pk_write_str(out + outpos, outsize - outpos, "sha1");
305 if (rc == 0)
306 goto err;
307 outpos += rc;
308 out[outpos++] = ' ';
309 } else {
310 if (outpos + 4 > outsize)
311 goto err;
312 out[outpos++] = '?';
313 out[outpos++] = '?';
314 out[outpos++] = TOHEX(pk->pk_algo >> 4);
315 out[outpos++] = TOHEX(pk->pk_algo & 0xf);
316 }
317
318
319 rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->hash, 20);
320 if (rc == 0)
321 goto err;
322 outpos += rc;
323
324 out[outpos-1] = '\0';
325
326 return out;
327
328 err:
329 free(out);
330 return NULL;
331 }
332
333 bool emv_pk_verify(const struct emv_pk *pk)
334 {
335 struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
336 if (!ch)
337 return false;
338
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);
343
344 unsigned char *h = crypto_hash_read(ch);
345 if (!h) {
346 crypto_hash_close(ch);
347 return false;
348 }
349
350 size_t hsize = crypto_hash_get_size(ch);
351 bool r = hsize && !memcmp(h, pk->hash, hsize) ? true : false;
352
353 crypto_hash_close(ch);
354
355 return r;
356 }
357
358 struct emv_pk *emv_pk_new(size_t modlen, size_t explen)
359 {
360 struct emv_pk *pk;
361
362 /* Not supported ATM */
363 if (explen > 3)
364 return NULL;
365
366 pk = calloc(1, sizeof(*pk));
367 if (!pk)
368 return NULL;
369
370 pk->mlen = modlen;
371 pk->elen = explen;
372
373 pk->modulus = calloc(modlen, 1);
374 if (!pk->modulus) {
375 free(pk);
376 pk = NULL;
377 }
378
379 return pk;
380 }
381
382 void emv_pk_free(struct emv_pk *pk)
383 {
384 if (!pk)
385 return;
386
387 free(pk->modulus);
388 free(pk);
389 }
390
391 static struct emv_pk *emv_pk_get_ca_pk_from_file(const char *fname,
392 const unsigned char *rid,
393 unsigned char idx)
394 {
395 if (!fname)
396 return NULL;
397
398 FILE *f = fopen(fname, "r");
399 if (!f) {
400 perror("fopen");
401 return NULL;
402 }
403
404 while (!feof(f)) {
405 char buf[2048];
406 if (fgets(buf, sizeof(buf), f) == NULL)
407 break;
408
409 struct emv_pk *pk = emv_pk_parse_pk(buf);
410 if (!pk)
411 continue;
412 if (memcmp(pk->rid, rid, 5) || pk->index != idx) {
413 emv_pk_free(pk);
414 continue;
415 }
416
417 fclose(f);
418
419 return pk;
420 }
421
422 fclose(f);
423
424 return NULL;
425 }
426
427 char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsigned char idx)
428 {
429 if (!dirname)
430 dirname = ".";//openemv_config_get_str("capk.dir", NULL);
431
432 if (!dirname)
433 return NULL;
434
435 char *filename;
436 int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0",
437 dirname,
438 rid[0],
439 rid[1],
440 rid[2],
441 rid[3],
442 rid[4],
443 idx);
444
445 if (ret <= 0)
446 return NULL;
447
448 return filename;
449 }
450
451 char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid)
452 {
453 if (!dirname)
454 dirname = "."; //openemv_config_get_str("capk.dir", NULL);
455
456 if (!dirname)
457 return NULL;
458
459 char *filename;
460 int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks",
461 dirname,
462 rid[0],
463 rid[1],
464 rid[2],
465 rid[3],
466 rid[4]);
467
468 if (ret <= 0)
469 return NULL;
470
471 return filename;
472 }
473
474 struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx)
475 {
476 struct emv_pk *pk = NULL;
477
478 /* if (!pk) {
479 char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
480 if (fname) {
481 pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
482 free(fname);
483 }
484 }
485
486 if (!pk) {
487 char *fname = emv_pk_get_ca_pk_rid_file(NULL, rid);
488 if (fname) {
489 pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
490 free(fname);
491 }
492 }
493 */
494 if (!pk) {
495 const char *relfname = "emv/capk.txt";
496
497 char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
498 strcpy(fname, get_my_executable_directory());
499 strcat(fname, relfname);
500
501 pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
502 }
503 if (!pk)
504 return NULL;
505
506 printf("Verifying CA Public Key for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...",
507 pk->rid[0],
508 pk->rid[1],
509 pk->rid[2],
510 pk->rid[3],
511 pk->rid[4],
512 pk->index,
513 pk->mlen * 8);
514 if (emv_pk_verify(pk)) {
515 printf("OK\n");
516
517 return pk;
518 }
519
520 printf("Failed!\n");
521 emv_pk_free(pk);
522
523 return NULL;
524 }
Impressum, Datenschutz