Merge pull request #2664 from piotrva/hf-mf-ultimatecard-script-max-rw-blocks
[RRG-proxmark3.git] / client / src / emv / dol.c
blobdddefaf4a3b667a1bae3e070257d331ca979267a
1 //-----------------------------------------------------------------------------
2 // Borrowed initially from https://github.com/lumag/emv-tools/
3 // Copyright (C) 2012, 2015 Dmitry Eremin-Solenikov
4 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // See LICENSE.txt for the text of the license.
17 //-----------------------------------------------------------------------------
18 // libopenemv - a library to work with EMV family of smart cards
19 //-----------------------------------------------------------------------------
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include "emv/dol.h"
26 #include "emv/tlv.h"
28 #include <stdlib.h>
29 #include <string.h>
31 static size_t dol_calculate_len(const struct tlv *tlv, size_t data_len) {
32 if (!tlv)
33 return 0;
35 const unsigned char *buf = tlv->value;
36 size_t left = tlv->len;
37 size_t count = 0;
39 while (left) {
40 struct tlv cur_tlv;
41 if (!tlv_parse_tl(&buf, &left, &cur_tlv))
42 return 0;
44 count += cur_tlv.len;
46 /* Last tag can be of variable length */
47 if (cur_tlv.len == 0 && left == 0)
48 count = data_len;
51 return count;
54 struct tlv *dol_process(const struct tlv *tlv, const struct tlvdb *tlvdb, tlv_tag_t tag) {
55 size_t res_len;
56 if (!tlv || !(res_len = dol_calculate_len(tlv, 0))) {
57 struct tlv *res_tlv = calloc(1, sizeof(*res_tlv));
59 res_tlv->tag = tag;
60 res_tlv->len = 0;
61 res_tlv->value = NULL;
63 return res_tlv;
66 struct tlv *res_tlv = calloc(1, sizeof(*res_tlv) + res_len);
67 if (!res_tlv)
68 return NULL;
70 const unsigned char *buf = tlv->value;
71 size_t left = tlv->len;
72 unsigned char *res = (unsigned char *)(res_tlv + 1);
73 size_t pos = 0;
75 while (left) {
76 struct tlv cur_tlv;
77 if (!tlv_parse_tl(&buf, &left, &cur_tlv) || pos + cur_tlv.len > res_len) {
78 free(res_tlv);
80 return NULL;
83 const struct tlv *tag_tlv = tlvdb_get(tlvdb, cur_tlv.tag, NULL);
84 if (!tag_tlv) {
85 memset(res + pos, 0, cur_tlv.len);
86 } else if (tag_tlv->len > cur_tlv.len) {
87 memcpy(res + pos, tag_tlv->value, cur_tlv.len);
88 } else {
89 // FIXME: cn data should be padded with 0xFF !!!
90 memcpy(res + pos, tag_tlv->value, tag_tlv->len);
91 memset(res + pos + tag_tlv->len, 0, cur_tlv.len - tag_tlv->len);
93 pos += cur_tlv.len;
96 res_tlv->tag = tag;
97 res_tlv->len = res_len;
98 res_tlv->value = res;
100 return res_tlv;
103 struct tlvdb *dol_parse(const struct tlv *tlv, const unsigned char *data, size_t data_len) {
104 if (!tlv)
105 return NULL;
107 const unsigned char *buf = tlv->value;
108 size_t left = tlv->len;
109 size_t res_len = dol_calculate_len(tlv, data_len);
110 size_t pos = 0;
111 struct tlvdb *db = NULL;
113 if (res_len != data_len)
114 return NULL;
116 while (left) {
117 struct tlv cur_tlv;
118 if (!tlv_parse_tl(&buf, &left, &cur_tlv) || pos + cur_tlv.len > res_len) {
119 tlvdb_free(db);
120 return NULL;
123 /* Last tag can be of variable length */
124 if (cur_tlv.len == 0 && left == 0)
125 cur_tlv.len = res_len - pos;
127 struct tlvdb *tag_db = tlvdb_fixed(cur_tlv.tag, cur_tlv.len, data + pos);
128 if (!db)
129 db = tag_db;
130 else
131 tlvdb_add(db, tag_db);
133 pos += cur_tlv.len;
136 return db;