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