2 * libopenemv - a library to work with EMV family of smart cards
3 * Copyright (C) 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 static size_t dol_calculate_len(const struct tlv
*tlv
, size_t data_len
)
31 const unsigned char *buf
= tlv
->value
;
32 size_t left
= tlv
->len
;
37 if (!tlv_parse_tl(&buf
, &left
, &tlv
))
42 /* Last tag can be of variable length */
43 if (tlv
.len
== 0 && left
== 0)
50 struct tlv
*dol_process(const struct tlv
*tlv
, const struct tlvdb
*tlvdb
, tlv_tag_t tag
)
53 if (!tlv
|| !(res_len
= dol_calculate_len(tlv
, 0))) {
54 struct tlv
*res_tlv
= malloc(sizeof(*res_tlv
));
58 res_tlv
->value
= NULL
;
63 struct tlv
*res_tlv
= malloc(sizeof(*res_tlv
) + res_len
);
67 const unsigned char *buf
= tlv
->value
;
68 size_t left
= tlv
->len
;
69 unsigned char *res
= (unsigned char *)(res_tlv
+ 1);
74 if (!tlv_parse_tl(&buf
, &left
, &cur_tlv
) || pos
+ cur_tlv
.len
> res_len
) {
80 const struct tlv
*tag_tlv
= tlvdb_get(tlvdb
, cur_tlv
.tag
, NULL
);
82 memset(res
+ pos
, 0, cur_tlv
.len
);
83 } else if (tag_tlv
->len
> cur_tlv
.len
) {
84 memcpy(res
+ pos
, tag_tlv
->value
, cur_tlv
.len
);
86 // FIXME: cn data should be padded with 0xFF !!!
87 memcpy(res
+ pos
, tag_tlv
->value
, tag_tlv
->len
);
88 memset(res
+ pos
+ tag_tlv
->len
, 0, cur_tlv
.len
- tag_tlv
->len
);
94 res_tlv
->len
= res_len
;
100 struct tlvdb
*dol_parse(const struct tlv
*tlv
, const unsigned char *data
, size_t data_len
)
105 const unsigned char *buf
= tlv
->value
;
106 size_t left
= tlv
->len
;
107 size_t res_len
= dol_calculate_len(tlv
, data_len
);
109 struct tlvdb
*db
= NULL
;
111 if (res_len
!= data_len
)
116 if (!tlv_parse_tl(&buf
, &left
, &cur_tlv
) || pos
+ cur_tlv
.len
> res_len
) {
121 /* Last tag can be of variable length */
122 if (cur_tlv
.len
== 0 && left
== 0)
123 cur_tlv
.len
= res_len
- pos
;
125 struct tlvdb
*tag_db
= tlvdb_fixed(cur_tlv
.tag
, cur_tlv
.len
, data
+ pos
);
129 tlvdb_add(db
, tag_db
);