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.
15 * https://github.com/lumag/emv-tools/blob/master/lib/tlv.c
27 #define TLV_TAG_CLASS_MASK 0xc0
28 #define TLV_TAG_COMPLEX 0x20
29 #define TLV_TAG_VALUE_MASK 0x1f
30 #define TLV_TAG_VALUE_CONT 0x1f
31 #define TLV_TAG_INVALID 0
33 #define TLV_LEN_LONG 0x80
34 #define TLV_LEN_MASK 0x7f
35 #define TLV_LEN_INVALID (~0)
37 // http://radek.io/2012/11/10/magical-container_of-macro/
38 //#define container_of(ptr, type, member) ({
39 // const typeof( ((type *)0)->member ) *__mptr = (ptr);
40 // (type *)( (char *)__mptr - offsetof(type,member) );})
46 struct tlvdb
*children
;
55 static tlv_tag_t
tlv_parse_tag(const unsigned char **buf
, size_t *len
) {
59 return TLV_TAG_INVALID
;
63 if ((tag
& TLV_TAG_VALUE_MASK
) != TLV_TAG_VALUE_CONT
)
67 return TLV_TAG_INVALID
;
77 static size_t tlv_parse_len(const unsigned char **buf
, size_t *len
) {
81 return TLV_LEN_INVALID
;
87 if (!(l
& TLV_LEN_LONG
))
90 size_t ll
= l
& ~ TLV_LEN_LONG
;
92 return TLV_LEN_INVALID
;
95 for (int i
= 1; i
<= ll
; i
++) {
104 bool tlv_parse_tl(const unsigned char **buf
, size_t *len
, struct tlv
*tlv
) {
107 tlv
->tag
= tlv_parse_tag(buf
, len
);
108 if (tlv
->tag
== TLV_TAG_INVALID
)
111 tlv
->len
= tlv_parse_len(buf
, len
);
112 if (tlv
->len
== TLV_LEN_INVALID
)
118 static struct tlvdb
*tlvdb_parse_children(struct tlvdb
*parent
);
120 static bool tlvdb_parse_one(struct tlvdb
*tlvdb
,
121 struct tlvdb
*parent
,
122 const unsigned char **tmp
,
124 tlvdb
->next
= tlvdb
->children
= NULL
;
125 tlvdb
->parent
= parent
;
127 tlvdb
->tag
.tag
= tlv_parse_tag(tmp
, left
);
128 if (tlvdb
->tag
.tag
== TLV_TAG_INVALID
)
131 tlvdb
->tag
.len
= tlv_parse_len(tmp
, left
);
132 if (tlvdb
->tag
.len
== TLV_LEN_INVALID
)
135 if (tlvdb
->tag
.len
> *left
)
138 tlvdb
->tag
.value
= *tmp
;
140 *tmp
+= tlvdb
->tag
.len
;
141 *left
-= tlvdb
->tag
.len
;
143 if (tlv_is_constructed(&tlvdb
->tag
) && (tlvdb
->tag
.len
!= 0)) {
144 tlvdb
->children
= tlvdb_parse_children(tlvdb
);
145 if (!tlvdb
->children
)
148 tlvdb
->children
= NULL
;
157 static struct tlvdb
*tlvdb_parse_children(struct tlvdb
*parent
) {
158 const unsigned char *tmp
= parent
->tag
.value
;
159 size_t left
= parent
->tag
.len
;
160 struct tlvdb
*tlvdb
, *first
= NULL
, *prev
= NULL
;
163 tlvdb
= malloc(sizeof(*tlvdb
));
170 if (!tlvdb_parse_one(tlvdb
, parent
, &tmp
, &left
))
173 tlvdb
->parent
= parent
;
184 struct tlvdb
*tlvdb_parse(const unsigned char *buf
, size_t len
) {
185 struct tlvdb_root
*root
;
186 const unsigned char *tmp
;
192 root
= malloc(sizeof(*root
) + len
);
194 memcpy(root
->buf
, buf
, len
);
199 if (!tlvdb_parse_one(&root
->db
, NULL
, &tmp
, &left
))
208 tlvdb_free(&root
->db
);
213 struct tlvdb
*tlvdb_parse_multi(const unsigned char *buf
, size_t len
) {
214 struct tlvdb_root
*root
;
215 const unsigned char *tmp
;
221 root
= malloc(sizeof(*root
) + len
);
223 memcpy(root
->buf
, buf
, len
);
228 if (!tlvdb_parse_one(&root
->db
, NULL
, &tmp
, &left
))
232 struct tlvdb
*db
= malloc(sizeof(*db
));
233 if (!tlvdb_parse_one(db
, NULL
, &tmp
, &left
)) {
238 tlvdb_add(&root
->db
, db
);
244 tlvdb_free(&root
->db
);
249 struct tlvdb
*tlvdb_fixed(tlv_tag_t tag
, size_t len
, const unsigned char *value
) {
250 struct tlvdb_root
*root
= malloc(sizeof(*root
) + len
);
253 memcpy(root
->buf
, value
, len
);
255 root
->db
.parent
= root
->db
.next
= root
->db
.children
= NULL
;
256 root
->db
.tag
.tag
= tag
;
257 root
->db
.tag
.len
= len
;
258 root
->db
.tag
.value
= root
->buf
;
263 struct tlvdb
*tlvdb_external(tlv_tag_t tag
, size_t len
, const unsigned char *value
) {
264 struct tlvdb_root
*root
= malloc(sizeof(*root
));
268 root
->db
.parent
= root
->db
.next
= root
->db
.children
= NULL
;
269 root
->db
.tag
.tag
= tag
;
270 root
->db
.tag
.len
= len
;
271 root
->db
.tag
.value
= value
;
276 void tlvdb_free(struct tlvdb
*tlvdb
) {
277 struct tlvdb
*next
= NULL
;
282 for (; tlvdb
; tlvdb
= next
) {
284 tlvdb_free(tlvdb
->children
);
289 struct tlvdb
*tlvdb_find_next(struct tlvdb
*tlvdb
, tlv_tag_t tag
) {
293 return tlvdb_find(tlvdb
->next
, tag
);
296 struct tlvdb
*tlvdb_find(struct tlvdb
*tlvdb
, tlv_tag_t tag
) {
300 for (; tlvdb
; tlvdb
= tlvdb
->next
) {
301 if (tlvdb
->tag
.tag
== tag
)
308 struct tlvdb
*tlvdb_find_full(struct tlvdb
*tlvdb
, tlv_tag_t tag
) {
312 for (; tlvdb
; tlvdb
= tlvdb
->next
) {
313 if (tlvdb
->tag
.tag
== tag
)
316 if (tlvdb
->children
) {
317 struct tlvdb
*ch
= tlvdb_find_full(tlvdb
->children
, tag
);
326 struct tlvdb
*tlvdb_find_path(struct tlvdb
*tlvdb
, tlv_tag_t tag
[]) {
328 struct tlvdb
*tnext
= tlvdb
;
330 while (tnext
&& tag
[i
]) {
331 tnext
= tlvdb_find(tnext
, tag
[i
]);
333 if (tag
[i
] && tnext
) {
334 tnext
= tnext
->children
;
341 void tlvdb_add(struct tlvdb
*tlvdb
, struct tlvdb
*other
) {
345 while (tlvdb
->next
) {
346 if (tlvdb
->next
== other
)
355 void tlvdb_change_or_add_node_ex(struct tlvdb
*tlvdb
, tlv_tag_t tag
, size_t len
, const unsigned char *value
, struct tlvdb
**tlvdb_elm
) {
356 struct tlvdb
*telm
= tlvdb_find_full(tlvdb
, tag
);
359 struct tlvdb
*elm
= tlvdb_fixed(tag
, len
, value
);
360 tlvdb_add(tlvdb
, elm
);
364 // the same tlv structure
365 if (telm
->tag
.tag
== tag
&& telm
->tag
.len
== len
&& !memcmp(telm
->tag
.value
, value
, len
))
368 // replace tlv element
369 struct tlvdb
*tnewelm
= tlvdb_fixed(tag
, len
, value
);
370 bool tnewelm_linked
= false;
371 tnewelm
->next
= telm
->next
;
372 tnewelm
->parent
= telm
->parent
;
374 // if telm stayed first in children chain
375 if (telm
->parent
&& telm
->parent
->children
== telm
) {
376 telm
->parent
->children
= tnewelm
;
377 tnewelm_linked
= true;
380 // if telm have previous element
383 struct tlvdb
*celm
= tlvdb
;
384 // elm in child list of node
385 if (telm
->parent
&& telm
->parent
->children
)
386 celm
= telm
->parent
->children
;
388 // find previous element
389 for (; celm
; celm
= celm
->next
) {
390 if (celm
->next
== telm
) {
391 celm
->next
= tnewelm
;
392 tnewelm_linked
= true;
398 // free old element with childrens
403 *tlvdb_elm
= tnewelm
;
404 tnewelm_linked
= true;
406 if (! tnewelm_linked
) {
414 void tlvdb_change_or_add_node(struct tlvdb
*tlvdb
, tlv_tag_t tag
, size_t len
, const unsigned char *value
) {
415 tlvdb_change_or_add_node_ex(tlvdb
, tag
, len
, value
, NULL
);
418 void tlvdb_visit(const struct tlvdb
*tlvdb
, tlv_cb cb
, void *data
, int level
) {
419 struct tlvdb
*next
= NULL
;
424 for (; tlvdb
; tlvdb
= next
) {
426 cb(data
, &tlvdb
->tag
, level
, (tlvdb
->children
== NULL
));
427 tlvdb_visit(tlvdb
->children
, cb
, data
, level
+ 1);
431 static const struct tlvdb
*tlvdb_next(const struct tlvdb
*tlvdb
) {
433 return tlvdb
->children
;
439 tlvdb
= tlvdb
->parent
;
445 const struct tlv
*tlvdb_get(const struct tlvdb
*tlvdb
, tlv_tag_t tag
, const struct tlv
*prev
) {
447 // tlvdb = tlvdb_next(container_of(prev, struct tlvdb, tag));
448 tlvdb
= tlvdb_next((struct tlvdb
*)prev
);
453 if (tlvdb
->tag
.tag
== tag
)
456 tlvdb
= tlvdb_next(tlvdb
);
462 const struct tlv
*tlvdb_get_inchild(const struct tlvdb
*tlvdb
, tlv_tag_t tag
, const struct tlv
*prev
) {
463 tlvdb
= tlvdb
->children
;
464 return tlvdb_get(tlvdb
, tag
, prev
);
467 const struct tlv
*tlvdb_get_tlv(const struct tlvdb
*tlvdb
) {
474 unsigned char *tlv_encode(const struct tlv
*tlv
, size_t *len
) {
475 size_t size
= tlv
->len
;
479 if (tlv
->tag
> 0x100)
497 if (tlv
->tag
> 0x100) {
498 data
[pos
++] = tlv
->tag
>> 8;
499 data
[pos
++] = tlv
->tag
& 0xff;
501 data
[pos
++] = tlv
->tag
;
503 if (tlv
->len
> 0x7f) {
505 data
[pos
++] = tlv
->len
;
507 data
[pos
++] = tlv
->len
;
509 memcpy(data
+ pos
, tlv
->value
, tlv
->len
);
516 bool tlv_is_constructed(const struct tlv
*tlv
) {
517 return (((tlv
->tag
< 0x100 ? tlv
->tag
: tlv
->tag
>> 8) & TLV_TAG_COMPLEX
) == TLV_TAG_COMPLEX
);
520 bool tlv_equal(const struct tlv
*a
, const struct tlv
*b
) {
527 return a
->tag
== b
->tag
&& a
->len
== b
->len
&& !memcmp(a
->value
, b
->value
, a
->len
);
530 struct tlvdb
*tlvdb_elm_get_next(struct tlvdb
*tlvdb
) {
534 struct tlvdb
*tlvdb_elm_get_children(struct tlvdb
*tlvdb
) {
535 return tlvdb
->children
;
538 struct tlvdb
*tlvdb_elm_get_parent(struct tlvdb
*tlvdb
) {
539 return tlvdb
->parent
;
542 bool tlvdb_get_uint8(struct tlvdb
*tlvRoot
, tlv_tag_t tag
, uint8_t *value
) {
543 const struct tlv
*tlvelm
= tlvdb_get(tlvRoot
, tag
, NULL
);
544 return tlv_get_uint8(tlvelm
, value
);
547 bool tlv_get_uint8(const struct tlv
*etlv
, uint8_t *value
) {
553 if (etlv
->len
== 1) {
554 *value
= etlv
->value
[0];
561 bool tlv_get_int(const struct tlv
*etlv
, int *value
) {
567 if (etlv
->len
<= 4) {
568 for (int i
= 0; i
< etlv
->len
; i
++) {
569 *value
+= etlv
->value
[i
] * (1 << (i
* 8));