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