1 /***************************************************************************
2 begin : Sun Jun 13 2004
3 copyright : (C) 2004-2010 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * Please see toplevel file COPYING for license details *
8 ***************************************************************************/
9
10
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14
15 #include "tlv_p.h"
16 #include <gwenhywfar/debug.h>
17 #include <gwenhywfar/inherit.h>
18 #include <gwenhywfar/misc.h>
19 #include <gwenhywfar/text.h>
20
21 #include <chipcard/chipcard.h>
22
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <string.h>
26
27
GWEN_LIST_FUNCTIONS(LC_TLV,LC_TLV)28 GWEN_LIST_FUNCTIONS(LC_TLV, LC_TLV)
29
30
31 LC_TLV *LC_TLV_new() {
32 LC_TLV *tlv;
33
34 GWEN_NEW_OBJECT(LC_TLV, tlv);
35 GWEN_LIST_INIT(LC_TLV, tlv);
36
37 return tlv;
38 }
39
40
41
LC_TLV_free(LC_TLV * tlv)42 void LC_TLV_free(LC_TLV *tlv) {
43 if (tlv) {
44 free(tlv->tagData);
45 GWEN_LIST_FINI(LC_TLV, tlv);
46 GWEN_FREE_OBJECT(tlv);
47 }
48 }
49
50
51
LC_TLV_IsBerTlv(const LC_TLV * tlv)52 int LC_TLV_IsBerTlv(const LC_TLV *tlv){
53 assert(tlv);
54 return tlv->isBerTlv;
55 }
56
57
58
LC_TLV_GetTagType(const LC_TLV * tlv)59 unsigned int LC_TLV_GetTagType(const LC_TLV *tlv){
60 assert(tlv);
61 return tlv->tagType;
62 }
63
64
65
LC_TLV_GetTagLength(const LC_TLV * tlv)66 unsigned int LC_TLV_GetTagLength(const LC_TLV *tlv){
67 assert(tlv);
68 return tlv->tagLength;
69 }
70
71
72
LC_TLV_GetTagSize(const LC_TLV * tlv)73 unsigned int LC_TLV_GetTagSize(const LC_TLV *tlv){
74 assert(tlv);
75 return tlv->tagSize;
76 }
77
78
79
LC_TLV_GetTagData(const LC_TLV * tlv)80 const void *LC_TLV_GetTagData(const LC_TLV *tlv){
81 assert(tlv);
82 return tlv->tagData;
83 }
84
85
86
LC_TLV_fromBuffer(GWEN_BUFFER * mbuf,int isBerTlv)87 LC_TLV *LC_TLV_fromBuffer(GWEN_BUFFER *mbuf, int isBerTlv) {
88 const char *p;
89 unsigned int tagMode;
90 unsigned int tagType;
91 unsigned int tagLength;
92 const char *tagData;
93 unsigned int size;
94 unsigned int pos;
95 unsigned int j;
96 LC_TLV *tlv;
97 uint32_t startPos;
98
99 if (!GWEN_Buffer_GetBytesLeft(mbuf)) {
100 DBG_ERROR(LC_LOGDOMAIN, "Buffer empty");
101 return 0;
102 }
103
104 startPos=GWEN_Buffer_GetPos(mbuf);
105
106 tagMode=tagType=tagLength=0;
107
108 p=GWEN_Buffer_GetPosPointer(mbuf);
109 pos=0;
110 size=GWEN_Buffer_GetBytesLeft(mbuf);
111
112 /* get tag type */
113 if (size<2) {
114 DBG_ERROR(LC_LOGDOMAIN, "Too few bytes for BER-TLV");
115 return 0;
116 }
117 j=(unsigned char)(p[pos]);
118 tagMode=(j & 0xe0);
119 if (isBerTlv) {
120 if ((j & 0x1f)==0x1f) {
121 pos++;
122 if (pos>=size) {
123 DBG_ERROR(LC_LOGDOMAIN, "Too few bytes");
124 return 0;
125 }
126 j=(unsigned char)(p[pos]);
127 }
128 else
129 j&=0x1f;
130 }
131 DBG_DEBUG(LC_LOGDOMAIN, "Tag type %02x%s", j,
132 isBerTlv?" (BER-TLV)":"");
133 tagType=j;
134
135 /* get length */
136 pos++;
137 if (pos>=size) {
138 DBG_ERROR(LC_LOGDOMAIN, "Too few bytes");
139 return 0;
140 }
141 j=(unsigned char)(p[pos]);
142 if (isBerTlv) {
143 if (j & 0x80) {
144 if (j==0x81) {
145 pos++;
146 if (pos>=size) {
147 DBG_ERROR(LC_LOGDOMAIN, "Too few bytes");
148 return 0;
149 }
150 j=(unsigned char)(p[pos]);
151 } /* 0x81 */
152 else if (j==0x82) {
153 if (pos+1>=size) {
154 DBG_ERROR(LC_LOGDOMAIN, "Too few bytes");
155 return 0;
156 }
157 pos++;
158 j=((unsigned char)(p[pos]))<<8;
159 pos++;
160 j+=(unsigned char)(p[pos]);
161 } /* 0x82 */
162 else {
163 DBG_ERROR(LC_LOGDOMAIN, "Unexpected tag length modifier %02x", j);
164 return 0;
165 }
166 } /* if tag length modifier */
167 }
168 else {
169 if (j==255) {
170 if (pos+2>=size) {
171 DBG_ERROR(LC_LOGDOMAIN, "Too few bytes");
172 return 0;
173 }
174 pos++;
175 j=((unsigned char)(p[pos]))<<8;
176 pos++;
177 j+=(unsigned char)(p[pos]);
178 }
179 }
180 pos++;
181 tagLength=j;
182 tagData=p+pos;
183 GWEN_Buffer_IncrementPos(mbuf, pos);
184
185 DBG_DEBUG(LC_LOGDOMAIN, "Tag: %02x (%d bytes)", tagType, tagLength);
186 if (pos+j>size) {
187 DBG_ERROR(LC_LOGDOMAIN, "Too few bytes");
188 return 0;
189 }
190
191 tlv=LC_TLV_new();
192 assert(tlv);
193 tlv->isBerTlv=isBerTlv;
194 tlv->tagMode=tagMode;
195 tlv->tagType=tagType;
196 tlv->tagLength=tagLength;
197 if (tagLength) {
198 tlv->tagData=(void*)malloc(tagLength);
199 memmove(tlv->tagData, tagData, tagLength);
200 }
201
202 GWEN_Buffer_IncrementPos(mbuf, tagLength);
203 tlv->tagSize=GWEN_Buffer_GetPos(mbuf)-startPos;
204 return tlv;
205 }
206
207
208
LC_TLV_IsContructed(const LC_TLV * tlv)209 int LC_TLV_IsContructed(const LC_TLV *tlv){
210 assert(tlv);
211 return (tlv->tagMode & 0x20);
212 }
213
214
215
LC_TLV_GetClass(const LC_TLV * tlv)216 unsigned int LC_TLV_GetClass(const LC_TLV *tlv){
217 assert(tlv);
218 return (tlv->tagMode & 0xc0);
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233