1 /***************************************************************************
2  begin       : Fri Jul 04 2019
3  copyright   : (C) 2019 by Martin Preuss
4  email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  * This file is part of the project "AqBanking".                           *
8  * Please see toplevel file COPYING of that project for license details.   *
9  ***************************************************************************/
10 
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14 
15 
16 #include "parser_hbci.h"
17 #include "parser_normalize.h"
18 
19 #include <gwenhywfar/syncio_memory.h>
20 #include <gwenhywfar/debug.h>
21 
22 #include <ctype.h>
23 
24 
25 
26 #define AQFINTS_PARSER_HBCI_BUFFERSIZE 1024
27 
28 
29 
30 /* ------------------------------------------------------------------------------------------------
31  * forward declarations
32  * ------------------------------------------------------------------------------------------------
33  */
34 
35 static int readSeg(AQFINTS_SEGMENT *targetSegment, const uint8_t *ptrBuf, uint32_t lenBuf);
36 static int readDeg(AQFINTS_ELEMENT *targetElement, const uint8_t *ptrBuf, uint32_t lenBuf);
37 static int readDe(AQFINTS_ELEMENT *targetElement, const uint8_t *ptrBuf, uint32_t lenBuf);
38 static int readString(AQFINTS_ELEMENT *targetElement, const uint8_t *ptrBuf, uint32_t lenBuf);
39 static int readBin(AQFINTS_ELEMENT *targetElement, const uint8_t *ptrBuf, uint32_t lenBuf);
40 static void parseSegHeader(AQFINTS_SEGMENT *segment);
41 
42 static void writeDegSequence(AQFINTS_ELEMENT *element, GWEN_BUFFER *destBuf, int elementCount,
43                              int *pEndOfLastNonEmptyElement);
44 static int writeDeg(AQFINTS_ELEMENT *element, GWEN_BUFFER *destBuf);
45 static void writeDeSequence(AQFINTS_ELEMENT *element, GWEN_BUFFER *destBuf, int elementCount,
46                             int *pEndOfLastNonEmptyElement);
47 static int writeDe(AQFINTS_ELEMENT *element, GWEN_BUFFER *destBuf);
48 static void writeBin(const uint8_t *ptrBuf, uint32_t lenBuf, GWEN_BUFFER *destBuf);
49 static void writeString(const char *s, GWEN_BUFFER *destBuf);
50 
51 
52 
53 
54 /* ------------------------------------------------------------------------------------------------
55  * implementations
56  * ------------------------------------------------------------------------------------------------
57  */
58 
59 
60 
61 
AQFINTS_Parser_Hbci_ReadBuffer(AQFINTS_SEGMENT_LIST * targetSegmentList,const uint8_t * ptrBuf,uint32_t lenBuf)62 int AQFINTS_Parser_Hbci_ReadBuffer(AQFINTS_SEGMENT_LIST *targetSegmentList,
63                                    const uint8_t *ptrBuf,
64                                    uint32_t lenBuf)
65 {
66   uint32_t origLenBuf;
67 
68   origLenBuf=lenBuf;
69 
70   while (lenBuf && *ptrBuf) {
71     AQFINTS_SEGMENT *targetSegment;
72     int rv;
73 
74     targetSegment=AQFINTS_Segment_new();
75 
76     rv=readSeg(targetSegment, ptrBuf, lenBuf);
77     if (rv<0) {
78       DBG_INFO(AQFINTS_PARSER_LOGDOMAIN, "here (%d)", rv);
79       AQFINTS_Segment_free(targetSegment);
80       return rv;
81     }
82     parseSegHeader(targetSegment);
83 
84     AQFINTS_Parser_Segment_RemoveTrailingEmptyElements(targetSegment);
85 
86     AQFINTS_Segment_List_Add(targetSegment, targetSegmentList);
87 
88     /* store copy of segment data */
89     if (lenBuf>rv) {
90       if (ptrBuf[rv]!='\'') {
91         DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "Segment not terminated by quotation mark");
92         return GWEN_ERROR_BAD_DATA;
93       }
94       AQFINTS_Segment_SetDataAsCopy(targetSegment, ptrBuf, rv+1);
95     }
96     else {
97       DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "Segment too small (no room for terminating quotation mark)");
98       return GWEN_ERROR_BAD_DATA;
99     }
100 
101     /* advance pointer and size */
102     lenBuf-=rv;
103     ptrBuf+=rv;
104 
105     if (lenBuf) {
106       if (*ptrBuf!='\'') {
107         /* DE was terminated, but not by "'", error */
108         return GWEN_ERROR_BAD_DATA;
109       }
110       ptrBuf++;
111       lenBuf--;
112     }
113   } /* while */
114 
115   return (int)(origLenBuf-lenBuf);
116 }
117 
118 
119 
AQFINTS_Parser_Hbci_WriteBuffer(AQFINTS_SEGMENT_LIST * segmentList)120 void AQFINTS_Parser_Hbci_WriteBuffer(AQFINTS_SEGMENT_LIST *segmentList)
121 {
122   AQFINTS_SEGMENT *segment;
123 
124   segment=AQFINTS_Segment_List_First(segmentList);
125   while (segment) {
126     AQFINTS_Parser_Hbci_WriteSegment(segment);
127     segment=AQFINTS_Segment_List_Next(segment);
128   }
129 }
130 
131 
132 
AQFINTS_Parser_Hbci_WriteSegment(AQFINTS_SEGMENT * segment)133 void AQFINTS_Parser_Hbci_WriteSegment(AQFINTS_SEGMENT *segment)
134 {
135   AQFINTS_ELEMENT *rootElement;
136   uint32_t segmentStartPos;
137   int endOfLastNonEmptyElement=0;
138   uint32_t pos;
139   GWEN_BUFFER *destBuf;
140   int rv;
141 
142   destBuf=GWEN_Buffer_new(0, 256, 0, 1);
143   segmentStartPos=GWEN_Buffer_GetPos(destBuf);
144   rootElement=AQFINTS_Segment_GetElements(segment);
145   if (rootElement) {
146     writeDegSequence(rootElement, destBuf, 0, &endOfLastNonEmptyElement);
147 
148     /* remove trailing '+'s */
149     pos=GWEN_Buffer_GetPos(destBuf);
150     if (pos>endOfLastNonEmptyElement) {
151       uint32_t cropPos;
152 
153       cropPos=endOfLastNonEmptyElement?endOfLastNonEmptyElement:segmentStartPos;
154 
155       /*DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "Crop destbuffer: %d->%d", pos, cropPos);*/
156       GWEN_Buffer_Crop(destBuf, 0, cropPos);
157     }
158   }
159 
160   /* append segment end sign */
161   GWEN_Buffer_AppendByte(destBuf, '\'');
162 
163   /* set data to segment, take over GWEN_BUFFER content */
164   AQFINTS_Segment_SetData(segment, (uint8_t *) GWEN_Buffer_GetStart(destBuf), GWEN_Buffer_GetUsedBytes(destBuf));
165   rv=GWEN_Buffer_Relinquish(destBuf);
166   if (rv<0) {
167     DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "here (%d)", rv);
168     abort();
169   }
170   GWEN_Buffer_free(destBuf);
171 }
172 
173 
174 
parseSegHeader(AQFINTS_SEGMENT * segment)175 void parseSegHeader(AQFINTS_SEGMENT *segment)
176 {
177   AQFINTS_ELEMENT *element;
178 
179   element=AQFINTS_Segment_GetElements(segment);
180   if (element) {
181     AQFINTS_ELEMENT *deg1;
182 
183     deg1=AQFINTS_Element_Tree2_GetFirstChild(element);
184     if (deg1) {
185       AQFINTS_ELEMENT *de;
186 
187       de=AQFINTS_Element_Tree2_GetFirstChild(deg1);
188       if (de) {
189         const char *s;
190         int i;
191 
192         /* read segment code */
193         s=AQFINTS_Element_GetDataAsChar(de, NULL);
194         if (s && *s)
195           AQFINTS_Segment_SetCode(segment, s);
196 
197         /* read segment number */
198         de=AQFINTS_Element_Tree2_GetNext(de);
199         if (de) {
200           i=AQFINTS_Element_GetDataAsInt(de, 0);
201           AQFINTS_Segment_SetSegmentNumber(segment, i);
202 
203           /* read segment version */
204           de=AQFINTS_Element_Tree2_GetNext(de);
205           if (de) {
206             i=AQFINTS_Element_GetDataAsInt(de, 0);
207             AQFINTS_Segment_SetSegmentVersion(segment, i);
208 
209             /* read reference segment number */
210             de=AQFINTS_Element_Tree2_GetNext(de);
211             if (de) {
212               i=AQFINTS_Element_GetDataAsInt(de, 0);
213               AQFINTS_Segment_SetRefSegmentNumber(segment, i);
214             } /* if fourth de */
215           } /* if third de */
216         } /* if second de */
217       } /* if first de */
218     } /* if deg1 */
219   } /* if element */
220 }
221 
222 
223 
readSeg(AQFINTS_SEGMENT * targetSegment,const uint8_t * ptrBuf,uint32_t lenBuf)224 int readSeg(AQFINTS_SEGMENT *targetSegment, const uint8_t *ptrBuf, uint32_t lenBuf)
225 {
226   AQFINTS_ELEMENT *targetElement;
227   uint32_t origLenBuf;
228 
229   origLenBuf=lenBuf;
230 
231   targetElement=AQFINTS_Segment_GetElements(targetSegment);
232   if (targetElement==NULL) {
233     targetElement=AQFINTS_Element_new();
234     AQFINTS_Element_SetElementType(targetElement, AQFINTS_ElementType_Root);
235     AQFINTS_Segment_SetElements(targetSegment, targetElement);
236   }
237 
238 
239   while (lenBuf && *ptrBuf) {
240     AQFINTS_ELEMENT *targetDegElement;
241     int rv;
242 
243     targetDegElement=AQFINTS_Element_new();
244     AQFINTS_Element_SetElementType(targetDegElement, AQFINTS_ElementType_Deg);
245 
246 
247     rv=readDeg(targetDegElement, ptrBuf, lenBuf);
248     if (rv<0) {
249       DBG_INFO(AQFINTS_PARSER_LOGDOMAIN, "here (%d)", rv);
250       AQFINTS_Element_free(targetDegElement);
251       return rv;
252     }
253     AQFINTS_Element_Tree2_AddChild(targetElement, targetDegElement);
254 
255     /* advance pointer and size */
256     lenBuf-=rv;
257     ptrBuf+=rv;
258 
259     if (lenBuf) {
260       if (*ptrBuf!='+') {
261         /* DE was terminated, but not by ':', so a higher syntax element ended */
262         return (int)(origLenBuf-lenBuf);
263       }
264       ptrBuf++;
265       lenBuf--;
266     }
267   } /* while */
268 
269   DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "No delimiter at end of data");
270   return GWEN_ERROR_BAD_DATA;
271 }
272 
273 
274 
readDeg(AQFINTS_ELEMENT * targetElement,const uint8_t * ptrBuf,uint32_t lenBuf)275 int readDeg(AQFINTS_ELEMENT *targetElement, const uint8_t *ptrBuf, uint32_t lenBuf)
276 {
277   uint32_t origLenBuf;
278 
279   origLenBuf=lenBuf;
280 
281   while (lenBuf && *ptrBuf) {
282     AQFINTS_ELEMENT *targetDeElement;
283     int rv;
284 
285     targetDeElement=AQFINTS_Element_new();
286     AQFINTS_Element_SetElementType(targetDeElement, AQFINTS_ElementType_De);
287 
288 
289     rv=readDe(targetDeElement, ptrBuf, lenBuf);
290     if (rv<0) {
291       DBG_INFO(AQFINTS_PARSER_LOGDOMAIN, "here (%d)", rv);
292       AQFINTS_Element_free(targetDeElement);
293       return rv;
294     }
295     AQFINTS_Element_Tree2_AddChild(targetElement, targetDeElement);
296 
297     /* advance pointer and size */
298     lenBuf-=rv;
299     ptrBuf+=rv;
300 
301     if (lenBuf) {
302       if (*ptrBuf!=':') {
303         /* DE was terminated, but not by ':', so a higher syntax element ended */
304         return (int)(origLenBuf-lenBuf);
305       }
306       ptrBuf++;
307       lenBuf--;
308     }
309   } /* while */
310 
311   DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "No delimiter at end of data");
312   return GWEN_ERROR_BAD_DATA;
313 }
314 
315 
316 
317 
readDe(AQFINTS_ELEMENT * targetElement,const uint8_t * ptrBuf,uint32_t lenBuf)318 int readDe(AQFINTS_ELEMENT *targetElement, const uint8_t *ptrBuf, uint32_t lenBuf)
319 {
320   if (lenBuf) {
321     if (*ptrBuf=='@') {
322       int rv;
323 
324       rv=readBin(targetElement, ptrBuf, lenBuf);
325       if (rv<0) {
326         DBG_INFO(AQFINTS_PARSER_LOGDOMAIN, "here (%d)", rv);
327         return rv;
328       }
329       return rv;
330     }
331     else {
332       int rv;
333 
334       rv=readString(targetElement, ptrBuf, lenBuf);
335       if (rv<0) {
336         DBG_INFO(AQFINTS_PARSER_LOGDOMAIN, "here (%d)", rv);
337         return rv;
338       }
339       return rv;
340     }
341   }
342   DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "Empty data buffer");
343   return GWEN_ERROR_NO_DATA;
344 }
345 
346 
347 
readString(AQFINTS_ELEMENT * targetElement,const uint8_t * ptrBuf,uint32_t lenBuf)348 int readString(AQFINTS_ELEMENT *targetElement, const uint8_t *ptrBuf, uint32_t lenBuf)
349 {
350   uint32_t origLenBuf;
351   GWEN_BUFFER *destBuf;
352 
353   origLenBuf=lenBuf;
354   destBuf=GWEN_Buffer_new(0, 256, 0, 1);
355 
356   while (*ptrBuf && lenBuf) {
357     switch (*ptrBuf) {
358     case '\'':
359     case '+':
360     case ':':
361       /* end of segment, DEG or DE reached */
362       if (GWEN_Buffer_GetUsedBytes(destBuf))
363         AQFINTS_Element_SetTextDataCopy(targetElement, GWEN_Buffer_GetStart(destBuf));
364       GWEN_Buffer_free(destBuf);
365       return (int)(origLenBuf-lenBuf);
366     case '?':
367       /* escape character */
368       ptrBuf++;
369       lenBuf--;
370       if (lenBuf && *ptrBuf)
371         GWEN_Buffer_AppendByte(destBuf, *ptrBuf);
372       else {
373         DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "Premature end of data (question mark was last character)");
374         GWEN_Buffer_free(destBuf);
375         return GWEN_ERROR_BAD_DATA;
376       }
377       break;
378     default:
379       GWEN_Buffer_AppendByte(destBuf, *ptrBuf);
380     } /* switch */
381 
382     ptrBuf++;
383     lenBuf--;
384   } /* while */
385 
386   DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "No delimiter at end of data");
387   GWEN_Buffer_free(destBuf);
388   return GWEN_ERROR_BAD_DATA;
389 }
390 
391 
392 
readBin(AQFINTS_ELEMENT * targetElement,const uint8_t * ptrBuf,uint32_t lenBuf)393 int readBin(AQFINTS_ELEMENT *targetElement, const uint8_t *ptrBuf, uint32_t lenBuf)
394 {
395   uint32_t origLenBuf;
396 
397   origLenBuf=lenBuf;
398 
399   if (lenBuf && *ptrBuf=='@') {
400     uint32_t lenBinary=0;
401 
402     ptrBuf++;
403     lenBuf--;
404 
405     while (lenBuf && *ptrBuf && isdigit(*ptrBuf)) {
406       lenBinary*=10;
407       lenBinary+=((*ptrBuf)-'0');
408       ptrBuf++;
409       lenBuf--;
410     }
411     if (lenBuf && *ptrBuf=='@') {
412       ptrBuf++;
413       lenBuf--;
414 
415       if (lenBuf<lenBinary) {
416         DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "Invalid size of binary data (%lu < %lu)",
417                   (unsigned long int) lenBuf,
418                   (unsigned long int) lenBinary);
419         return GWEN_ERROR_BAD_DATA;
420       }
421 
422       if (lenBinary)
423         AQFINTS_Element_SetDataCopy(targetElement, ptrBuf, lenBinary);
424       AQFINTS_Element_AddFlags(targetElement, AQFINTS_ELEMENT_FLAGS_ISBIN);
425       ptrBuf+=lenBinary;
426       lenBuf-=lenBinary;
427       return (int)(origLenBuf-lenBuf);
428     }
429   }
430 
431   DBG_ERROR(AQFINTS_PARSER_LOGDOMAIN, "Error in binary data spec");
432   return GWEN_ERROR_BAD_DATA;
433 }
434 
435 
436 
writeDegSequence(AQFINTS_ELEMENT * element,GWEN_BUFFER * destBuf,int elementCount,int * pEndOfLastNonEmptyElement)437 void writeDegSequence(AQFINTS_ELEMENT *element, GWEN_BUFFER *destBuf, int elementCount, int *pEndOfLastNonEmptyElement)
438 {
439   AQFINTS_ELEMENT *childElement;
440 
441   childElement=AQFINTS_Element_Tree2_GetFirstChild(element);
442   while (childElement) {
443     if (elementCount)
444       GWEN_Buffer_AppendByte(destBuf, '+');
445 
446     if (AQFINTS_Element_GetElementType(childElement)==AQFINTS_ElementType_Group)
447       writeDegSequence(childElement, destBuf, elementCount, pEndOfLastNonEmptyElement);
448     else {
449       int rv;
450 
451       rv=writeDeg(childElement, destBuf);
452       if (rv>0)
453         *pEndOfLastNonEmptyElement=GWEN_Buffer_GetPos(destBuf);
454     }
455     elementCount++;
456     childElement=AQFINTS_Element_Tree2_GetNext(childElement);
457   }
458 }
459 
460 
461 
writeDeg(AQFINTS_ELEMENT * element,GWEN_BUFFER * destBuf)462 int writeDeg(AQFINTS_ELEMENT *element, GWEN_BUFFER *destBuf)
463 {
464   uint32_t elementStartPos;
465   uint32_t elementSize;
466   int endOfLastNonEmptyElement=0;
467   uint32_t pos;
468 
469   elementStartPos=GWEN_Buffer_GetPos(destBuf);
470   writeDeSequence(element, destBuf, 0, &endOfLastNonEmptyElement);
471 
472   /* remove trailing ':'s */
473   pos=GWEN_Buffer_GetPos(destBuf);
474   if (pos>endOfLastNonEmptyElement) {
475     uint32_t cropPos;
476 
477     cropPos=endOfLastNonEmptyElement?endOfLastNonEmptyElement:elementStartPos;
478 
479     DBG_DEBUG(AQFINTS_PARSER_LOGDOMAIN, "Crop destbuffer: %d->%d", pos, cropPos);
480     GWEN_Buffer_Crop(destBuf, 0, cropPos);
481   }
482 
483   /* set size and pos */
484   elementSize=GWEN_Buffer_GetPos(destBuf)-elementStartPos;
485   return (elementSize>0)?1:0;
486 }
487 
488 
489 
writeDeSequence(AQFINTS_ELEMENT * element,GWEN_BUFFER * destBuf,int elementCount,int * pEndOfLastNonEmptyElement)490 void writeDeSequence(AQFINTS_ELEMENT *element, GWEN_BUFFER *destBuf, int elementCount, int *pEndOfLastNonEmptyElement)
491 {
492   AQFINTS_ELEMENT *childElement;
493 
494   childElement=AQFINTS_Element_Tree2_GetFirstChild(element);
495   while (childElement) {
496     if (elementCount)
497       GWEN_Buffer_AppendByte(destBuf, ':');
498 
499     if (AQFINTS_Element_GetElementType(childElement)==AQFINTS_ElementType_Group)
500       writeDeSequence(childElement, destBuf, elementCount, pEndOfLastNonEmptyElement);
501     else {
502       int rv;
503 
504       rv=writeDe(childElement, destBuf);
505       if (rv>0) {
506         *pEndOfLastNonEmptyElement=GWEN_Buffer_GetPos(destBuf);
507         DBG_DEBUG(AQFINTS_PARSER_LOGDOMAIN, "Nonempty element ends at %d", GWEN_Buffer_GetPos(destBuf));
508       }
509       else {
510         DBG_DEBUG(AQFINTS_PARSER_LOGDOMAIN, "Empty element ends at %d", GWEN_Buffer_GetPos(destBuf));
511       }
512     }
513     elementCount++;
514     childElement=AQFINTS_Element_Tree2_GetNext(childElement);
515   }
516 }
517 
518 
519 
writeDe(AQFINTS_ELEMENT * element,GWEN_BUFFER * destBuf)520 int writeDe(AQFINTS_ELEMENT *element, GWEN_BUFFER *destBuf)
521 {
522   uint32_t elementStartPos;
523   uint32_t elementSize;
524 
525   elementStartPos=GWEN_Buffer_GetPos(destBuf);
526 
527   if (AQFINTS_Element_GetFlags(element) & AQFINTS_ELEMENT_FLAGS_ISBIN) {
528     uint32_t lenBuf;
529     const uint8_t *ptrBuf;
530 
531     lenBuf=AQFINTS_Element_GetDataLength(element);
532     ptrBuf=AQFINTS_Element_GetDataPointer(element);
533     if (lenBuf && ptrBuf)
534       writeBin(ptrBuf, lenBuf, destBuf);
535   }
536   else {
537     const char *s;
538 
539     s=AQFINTS_Element_GetDataAsChar(element, NULL);
540     if (s && *s)
541       writeString(s, destBuf);
542   }
543 
544   elementSize=GWEN_Buffer_GetPos(destBuf)-elementStartPos;
545   return (elementSize>0)?1:0;
546 }
547 
548 
549 
writeBin(const uint8_t * ptrBuf,uint32_t lenBuf,GWEN_BUFFER * destBuf)550 void writeBin(const uint8_t *ptrBuf, uint32_t lenBuf, GWEN_BUFFER *destBuf)
551 {
552   char numbuf[32];
553   int i;
554 
555   i=snprintf(numbuf, sizeof(numbuf)-1, "%u", (unsigned int) lenBuf);
556   assert(i<sizeof(numbuf));
557 
558   GWEN_Buffer_AppendByte(destBuf, '@');
559   GWEN_Buffer_AppendString(destBuf, numbuf);
560   GWEN_Buffer_AppendByte(destBuf, '@');
561   GWEN_Buffer_AppendBytes(destBuf, (const char *) ptrBuf, lenBuf);
562 }
563 
564 
565 
writeString(const char * s,GWEN_BUFFER * destBuf)566 void writeString(const char *s, GWEN_BUFFER *destBuf)
567 {
568   if (s) {
569     while (*s) {
570       if (NULL!=strchr("+:@?'", *s))
571         GWEN_Buffer_AppendByte(destBuf, '?');    /* prepend by '?' */
572       GWEN_Buffer_AppendByte(destBuf, *s);
573       s++;
574     }
575   }
576 }
577 
578 
579