1 /***************************************************************************
2 begin : Mon Mar 01 2004
3 copyright : (C) 2019 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * Please see toplevel file COPYING for license details *
8 ***************************************************************************/
9
10 #ifdef HAVE_CONFIG_H
11 # include <config.h>
12 #endif
13
14 #include "msg_p.h"
15 #include "xml.h"
16 #include "aqebics/client/provider_l.h"
17
18 #include <xmlsec/transforms.h>
19 #include <xmlsec/errors.h>
20
21 #include <libxml/xpathInternals.h>
22
23 #include <gwenhywfar/debug.h>
24 #include <gwenhywfar/misc.h>
25 #include <gwenhywfar/mdigest.h>
26 #include <gwenhywfar/base64.h>
27
28
GWEN_INHERIT_FUNCTIONS(EB_MSG)29 GWEN_INHERIT_FUNCTIONS(EB_MSG)
30
31
32
33 void EB_Msg__initWithDoc(EB_MSG *m)
34 {
35 xmlNodePtr rootNode;
36 const char *s;
37
38 assert(m);
39 m->xpathCtx=xmlXPathNewContext(m->doc);
40
41 if (xmlXPathRegisterNs(m->xpathCtx,
42 BAD_CAST "ds",
43 BAD_CAST "http://www.w3.org/2000/09/xmldsig#")!= 0) {
44 DBG_ERROR(AQEBICS_LOGDOMAIN, "Unable to register NS");
45 abort();
46 }
47
48 if (xmlXPathRegisterNs(m->xpathCtx,
49 BAD_CAST "xsi",
50 BAD_CAST "http://www.w3.org/2001/XMLSchema-instance")!= 0) {
51 DBG_ERROR(AQEBICS_LOGDOMAIN, "Unable to register NS");
52 abort();
53 }
54
55 if (m->hVersion==NULL) {
56 rootNode=xmlDocGetRootElement(m->doc);
57 s=(const char *)xmlGetProp(rootNode, BAD_CAST "Version");
58 if (!(s && *s))
59 s="H000";
60 free(m->hVersion);
61 m->hVersion=strdup(s);
62 }
63 }
64
65
66
EB_Msg_new()67 EB_MSG *EB_Msg_new()
68 {
69 EB_MSG *m;
70
71 GWEN_NEW_OBJECT(EB_MSG, m);
72 GWEN_INHERIT_INIT(EB_MSG, m);
73 m->usage=1;
74 m->doc=xmlNewDoc(BAD_CAST "1.0");
75 m->doc->encoding=xmlCharStrdup("UTF-8");
76 EB_Msg__initWithDoc(m);
77
78 return m;
79 }
80
81
82
EB_Msg_fromBuffer(const char * buffer,int size)83 EB_MSG *EB_Msg_fromBuffer(const char *buffer, int size)
84 {
85 EB_MSG *m;
86
87 GWEN_NEW_OBJECT(EB_MSG, m);
88 GWEN_INHERIT_INIT(EB_MSG, m);
89 m->usage=1;
90 m->doc=xmlParseMemory(buffer, size);
91 if (m->doc==0) {
92 DBG_ERROR(AQEBICS_LOGDOMAIN, "Unable to parser buffer as XML doc");
93 EB_Msg_free(m);
94 return 0;
95 }
96 EB_Msg__initWithDoc(m);
97
98 return m;
99 }
100
101
102
EB_Msg_fromFile(const char * fname)103 EB_MSG *EB_Msg_fromFile(const char *fname)
104 {
105 EB_MSG *m;
106
107 GWEN_NEW_OBJECT(EB_MSG, m);
108 GWEN_INHERIT_INIT(EB_MSG, m);
109 m->usage=1;
110 m->doc=xmlParseFile(fname);
111 if (m->doc==0) {
112 DBG_ERROR(AQEBICS_LOGDOMAIN, "Unable to parser file \"%s\" as XML doc",
113 fname);
114 EB_Msg_free(m);
115 return 0;
116 }
117 EB_Msg__initWithDoc(m);
118
119 return m;
120 }
121
122
123
EB_Msg_newResponse(int willSign,const char * rName,const char * hVersion)124 EB_MSG *EB_Msg_newResponse(int willSign, const char *rName, const char *hVersion)
125 {
126 EB_MSG *m;
127
128 GWEN_NEW_OBJECT(EB_MSG, m);
129 GWEN_INHERIT_INIT(EB_MSG, m);
130 m->usage=1;
131 m->doc=EB_Msg__generateResponse(willSign, rName, hVersion);
132 assert(m->doc);
133 EB_Msg__initWithDoc(m);
134
135 return m;
136 }
137
138
139
EB_Msg_newRequest(int willSign,const char * hVersion)140 EB_MSG *EB_Msg_newRequest(int willSign, const char *hVersion)
141 {
142 EB_MSG *m;
143
144 GWEN_NEW_OBJECT(EB_MSG, m);
145 GWEN_INHERIT_INIT(EB_MSG, m);
146 m->usage=1;
147 m->doc=EB_Msg__generateRequest(willSign, hVersion);
148 assert(m->doc);
149 EB_Msg__initWithDoc(m);
150
151 return m;
152 }
153
154
155
EB_Msg_toBuffer(EB_MSG * m,GWEN_BUFFER * buf)156 void EB_Msg_toBuffer(EB_MSG *m, GWEN_BUFFER *buf)
157 {
158 xmlChar *xmlbuff;
159 int buffersize;
160
161 assert(m);
162 assert(m->usage);
163 xmlDocDumpFormatMemory(m->doc, &xmlbuff, &buffersize, 0);
164 GWEN_Buffer_AppendBytes(buf, (const char *)xmlbuff, (uint32_t)buffersize);
165 xmlFree(xmlbuff);
166 }
167
168
169
EB_Msg_free(EB_MSG * m)170 void EB_Msg_free(EB_MSG *m)
171 {
172 if (m) {
173 assert(m->usage);
174 if (m->usage==1) {
175 GWEN_INHERIT_FINI(EB_MSG, m);
176 m->usage=0;
177 free(m->hVersion);
178 xmlFreeDoc(m->doc);
179 GWEN_FREE_OBJECT(m);
180 }
181 else
182 m->usage--;
183 }
184 }
185
186
187
188 #if 0
189 xmlNodeSetPtr EB_Xml_GetNodes(EB_MSG *m, const char *xpathExpr)
190 {
191 xmlNodeSetPtr nodes;
192 xmlXPathObjectPtr xpathObj;
193
194 assert(m);
195 assert(m->usage);
196 xpathObj=xmlXPathEvalExpression(BAD_CAST xpathExpr, m->xpathCtx);
197 if (xpathObj == NULL) {
198 DBG_ERROR(AQEBICS_LOGDOMAIN,
199 "Unable to evaluate xpath expression \"%s\"",
200 xpathExpr);
201 return 0;
202 }
203
204 nodes=xpathObj->nodesetval;
205 if (!nodes) {
206 DBG_INFO(AQEBICS_LOGDOMAIN, "No matching nodes");
207 xmlXPathFreeObject(xpathObj);
208 return 0;
209 }
210 xpathObj->nodesetval=NULL;
211
212 xmlXPathFreeObject(xpathObj);
213 return nodes;
214 }
215 #endif
216
217
218
EB_Msg_GetDoc(const EB_MSG * m)219 xmlDocPtr EB_Msg_GetDoc(const EB_MSG *m)
220 {
221 assert(m);
222 assert(m->usage);
223 return m->doc;
224 }
225
226
227
EB_Msg_GetRootNode(EB_MSG * m)228 xmlNodePtr EB_Msg_GetRootNode(EB_MSG *m)
229 {
230 assert(m);
231 assert(m->usage);
232 assert(m->doc);
233 return xmlDocGetRootElement(m->doc);
234 }
235
236
237
EB_Msg_GetHVersion(const EB_MSG * m)238 const char *EB_Msg_GetHVersion(const EB_MSG *m)
239 {
240 assert(m);
241 assert(m->usage);
242 return m->hVersion;
243 }
244
245
246
EB_Msg_SetHVersion(EB_MSG * m,const char * s)247 void EB_Msg_SetHVersion(EB_MSG *m, const char *s)
248 {
249 assert(m);
250 assert(m->usage);
251 free(m->hVersion);
252 if (s)
253 m->hVersion=strdup(s);
254 else
255 m->hVersion=NULL;
256 }
257
258
259
EB_Msg_BuildHashData(EB_MSG * m,GWEN_BUFFER * hbuf)260 int EB_Msg_BuildHashData(EB_MSG *m, GWEN_BUFFER *hbuf)
261 {
262 int rv;
263
264 assert(m);
265 assert(m->usage);
266
267 rv=EB_Xml_BuildHashData(xmlDocGetRootElement(m->doc),
268 BAD_CAST "#xpointer(//*[@authenticate='true'])",
269 hbuf);
270 if (rv) {
271 DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
272 return rv;
273 }
274
275 return 0;
276 }
277
278
279
EB_Msg_BuildHashSha1(EB_MSG * m,GWEN_BUFFER * hbuf)280 int EB_Msg_BuildHashSha1(EB_MSG *m, GWEN_BUFFER *hbuf)
281 {
282 return EB_Xml_BuildNodeHashSha1(xmlDocGetRootElement(m->doc),
283 "#xpointer(//*[@authenticate='true'])",
284 hbuf);
285 }
286
287
288
EB_Msg_BuildHashSha256(EB_MSG * m,GWEN_BUFFER * hbuf)289 int EB_Msg_BuildHashSha256(EB_MSG *m, GWEN_BUFFER *hbuf)
290 {
291 return EB_Xml_BuildNodeHashSha256(xmlDocGetRootElement(m->doc),
292 "#xpointer(//*[@authenticate='true'])",
293 hbuf);
294 }
295
296
297
EB_Msg_BuildHashSha256Sha256(EB_MSG * m,GWEN_BUFFER * hbuf)298 int EB_Msg_BuildHashSha256Sha256(EB_MSG *m, GWEN_BUFFER *hbuf)
299 {
300 return EB_Xml_BuildNodeHashSha256Sha256(xmlDocGetRootElement(m->doc),
301 "#xpointer(//*[@authenticate='true'])",
302 hbuf);
303 }
304
305
306
EB_Msg_ReadHash(EB_MSG * m,GWEN_BUFFER * hbuf)307 int EB_Msg_ReadHash(EB_MSG *m, GWEN_BUFFER *hbuf)
308 {
309 const char *s;
310 int rv;
311
312 assert(m);
313 assert(m->usage);
314
315 s=EB_Xml_GetCharValue(xmlDocGetRootElement(m->doc),
316 "AuthSignature/"
317 "ds:SignedInfo/ds:Reference/ds:DigestValue",
318 0);
319 if (!s) {
320 DBG_ERROR(AQEBICS_LOGDOMAIN, "No hash");
321 return -1;
322 }
323
324 rv=GWEN_Base64_Decode((const unsigned char *)s, 0, hbuf);
325 if (rv) {
326 DBG_ERROR(AQEBICS_LOGDOMAIN, "Could not decode hash");
327 return -1;
328 }
329
330 return 0;
331 }
332
333
334
EB_Msg_WriteHash(EB_MSG * m,const unsigned char * hash,int hsize)335 int EB_Msg_WriteHash(EB_MSG *m, const unsigned char *hash, int hsize)
336 {
337 int rv;
338 GWEN_BUFFER *hbuf;
339
340 assert(m);
341 assert(m->usage);
342
343 if (hsize!=20) {
344 DBG_ERROR(AQEBICS_LOGDOMAIN, "Bad hash size (expected 20, was %d)",
345 hsize);
346 return -1;
347 }
348
349 hbuf=GWEN_Buffer_new(0, 40, 0, 1);
350 rv=GWEN_Base64_Encode(hash, (uint32_t) hsize, hbuf, 0);
351 if (rv) {
352 DBG_ERROR(AQEBICS_LOGDOMAIN, "Could not base64-encode hash (%d)", rv);
353 GWEN_Buffer_free(hbuf);
354 return -1;
355 }
356 EB_Xml_SetCharValue(xmlDocGetRootElement(m->doc),
357 "AuthSignature/"
358 "ds:SignedInfo/ds:Reference/ds:DigestValue",
359 GWEN_Buffer_GetStart(hbuf));
360 GWEN_Buffer_free(hbuf);
361
362 return 0;
363 }
364
365
366
EB_Msg_ReadSignature(EB_MSG * m,GWEN_BUFFER * hbuf)367 int EB_Msg_ReadSignature(EB_MSG *m, GWEN_BUFFER *hbuf)
368 {
369 const char *s;
370 int rv;
371
372 assert(m);
373 assert(m->usage);
374
375 s=EB_Xml_GetCharValue(xmlDocGetRootElement(m->doc),
376 "AuthSignature/"
377 "ds:SignatureValue",
378 0);
379 if (!s) {
380 DBG_ERROR(AQEBICS_LOGDOMAIN, "No hash");
381 return -1;
382 }
383
384 rv=GWEN_Base64_Decode((const unsigned char *)s, 0, hbuf);
385 if (rv) {
386 DBG_ERROR(AQEBICS_LOGDOMAIN, "Could not decode signature");
387 return -1;
388 }
389
390 return 0;
391 }
392
393
394
EB_Msg_WriteSignature(EB_MSG * m,const unsigned char * hash,int hsize)395 int EB_Msg_WriteSignature(EB_MSG *m, const unsigned char *hash, int hsize)
396 {
397 int rv;
398 GWEN_BUFFER *hbuf;
399
400 assert(m);
401 assert(m->usage);
402
403 if (hsize!=128) {
404 DBG_ERROR(AQEBICS_LOGDOMAIN,
405 "Bad signature size (expected 128, was %d)",
406 hsize);
407 return -1;
408 }
409
410 hbuf=GWEN_Buffer_new(0, 256, 0, 1);
411 rv=GWEN_Base64_Encode(hash, (uint32_t) hsize, hbuf, 0);
412 if (rv) {
413 DBG_ERROR(AQEBICS_LOGDOMAIN,
414 "Could not base64-encode signature (%d)", rv);
415 GWEN_Buffer_free(hbuf);
416 return -1;
417 }
418 EB_Xml_SetCharValue(xmlDocGetRootElement(m->doc),
419 "AuthSignature/"
420 "ds:SignatureValue",
421 GWEN_Buffer_GetStart(hbuf));
422 GWEN_Buffer_free(hbuf);
423
424 return 0;
425 }
426
427
428
EB_Msg_SetCharValue(EB_MSG * m,const char * path,const char * value)429 int EB_Msg_SetCharValue(EB_MSG *m, const char *path, const char *value)
430 {
431 assert(m);
432 assert(m->usage);
433
434 return EB_Xml_SetCharValue(xmlDocGetRootElement(m->doc), path, value);
435 }
436
437
438
EB_Msg_GetCharValue(const EB_MSG * m,const char * path,const char * defValue)439 const char *EB_Msg_GetCharValue(const EB_MSG *m, const char *path,
440 const char *defValue)
441 {
442 assert(m);
443 assert(m->usage);
444
445 return EB_Xml_GetCharValue(xmlDocGetRootElement(m->doc),
446 path, defValue);
447 }
448
449
450
EB_Msg_SetIntValue(EB_MSG * m,const char * path,int value)451 int EB_Msg_SetIntValue(EB_MSG *m, const char *path, int value)
452 {
453 assert(m);
454 assert(m->usage);
455
456 return EB_Xml_SetIntValue(xmlDocGetRootElement(m->doc), path, value);
457 }
458
459
460
EB_Msg_GetIntValue(const EB_MSG * m,const char * path,int defValue)461 int EB_Msg_GetIntValue(const EB_MSG *m, const char *path, int defValue)
462 {
463 assert(m);
464 assert(m->usage);
465
466 return EB_Xml_GetIntValue(xmlDocGetRootElement(m->doc),
467 path, defValue);
468 }
469
470
471
EB_Msg_GetResultCode(const EB_MSG * m)472 EB_RC EB_Msg_GetResultCode(const EB_MSG *m)
473 {
474 const char *s;
475
476 s=EB_Msg_GetCharValue(m, "header/mutable/ReturnCode", 0);
477 if (s) {
478 long unsigned int i;
479
480 sscanf(s, "%lx", &i);
481 return (EB_RC) i;
482 }
483 return EB_RC_INTERNAL_ERROR;
484 }
485
486
487
EB_Msg_GetBodyResultCode(const EB_MSG * m)488 EB_RC EB_Msg_GetBodyResultCode(const EB_MSG *m)
489 {
490 const char *s;
491
492 s=EB_Msg_GetCharValue(m, "body/ReturnCode", 0);
493 if (s) {
494 long unsigned int i;
495
496 sscanf(s, "%lx", &i);
497 return (EB_RC) i;
498 }
499 return EB_RC_INTERNAL_ERROR;
500 }
501
502
503
504
505
506
507
EB_Msg__generateRequest(int willSign,const char * hVersion)508 xmlDocPtr EB_Msg__generateRequest(int willSign, const char *hVersion)
509 {
510 xmlDocPtr doc=NULL;
511 xmlNodePtr root_node = NULL;
512 xmlNodePtr node = NULL;
513 xmlNodePtr nodeX = NULL;
514 xmlNodePtr nodeXX = NULL;
515
516 /*
517 * Creates a new document, a node and set it as a root node
518 */
519 doc=xmlNewDoc(BAD_CAST "1.0");
520 root_node=xmlNewNode(NULL, BAD_CAST "ebics");
521 xmlDocSetRootElement(doc, root_node);
522 EB_Xml_Ebicsify(root_node, hVersion);
523
524 node=xmlNewChild(root_node, NULL, BAD_CAST "header", NULL);
525 xmlNewProp(node, BAD_CAST "authenticate", BAD_CAST "true");
526
527 nodeX=xmlNewChild(node, NULL, BAD_CAST "static", NULL);
528 xmlNewChild(nodeX, NULL, BAD_CAST "PartnerID", NULL);
529 xmlNewChild(nodeX, NULL, BAD_CAST "UserID", NULL);
530 nodeXX=xmlNewChild(nodeX, NULL, BAD_CAST "OrderDetails", NULL);
531 xmlNewChild(nodeXX, NULL, BAD_CAST "OrderType", NULL);
532 xmlNewChild(nodeXX, NULL, BAD_CAST "OrderID", NULL);
533 xmlNewChild(nodeXX, NULL, BAD_CAST "OrderAttribute", NULL);
534
535 nodeX=xmlNewChild(node, NULL, BAD_CAST "mutable", NULL);
536 xmlNewChild(nodeX, NULL, BAD_CAST "TransactionPhase", NULL);
537
538 if (willSign)
539 EB_Msg__prepareSignature(doc);
540
541 node=xmlNewChild(root_node, NULL, BAD_CAST "body", NULL);
542
543 return doc;
544 }
545
546
547
EB_Msg__generateResponse(int willSign,const char * rName,const char * hVersion)548 xmlDocPtr EB_Msg__generateResponse(int willSign, const char *rName, const char *hVersion)
549 {
550 xmlDocPtr doc=NULL;
551 xmlNodePtr root_node = NULL;
552 xmlNodePtr node = NULL;
553 xmlNodePtr nodeX = NULL;
554
555 /*
556 * Creates a new document, a node and set it as a root node
557 */
558 doc=xmlNewDoc(BAD_CAST "1.0");
559 root_node=xmlNewNode(NULL, BAD_CAST rName);
560 xmlDocSetRootElement(doc, root_node);
561 EB_Xml_Ebicsify(root_node, hVersion);
562
563 node=xmlNewChild(root_node, NULL, BAD_CAST "header", NULL);
564 xmlNewProp(node, BAD_CAST "authenticate", BAD_CAST "true");
565
566 nodeX=xmlNewChild(node, NULL, BAD_CAST "static", NULL);
567
568 nodeX=xmlNewChild(node, NULL, BAD_CAST "mutable", NULL);
569 //if (!isKeyMgt)
570 xmlNewChild(nodeX, NULL, BAD_CAST "TransactionPhase", NULL);
571 xmlNewChild(nodeX, NULL, BAD_CAST "ReturnCode", NULL);
572 xmlNewChild(nodeX, NULL, BAD_CAST "ReportText", NULL);
573
574 if (willSign)
575 EB_Msg__prepareSignature(doc);
576
577 node=xmlNewChild(root_node, NULL, BAD_CAST "body", NULL);
578
579 return doc;
580 }
581
582
583
EB_Msg__prepareSignature(xmlDocPtr doc)584 int EB_Msg__prepareSignature(xmlDocPtr doc)
585 {
586 xmlNodePtr node;
587 xmlNsPtr ns;
588 xmlNodePtr n;
589 xmlNodePtr nn;
590 xmlNodePtr nnn;
591 xmlNodePtr nnnn;
592
593 node=xmlNewChild(xmlDocGetRootElement(doc),
594 NULL, BAD_CAST "AuthSignature", NULL);
595 ns=xmlSearchNs(doc, node, BAD_CAST "ds");
596 assert(ns);
597
598 n=xmlNewChild(node, ns, BAD_CAST "SignedInfo", NULL);
599 nn=xmlNewChild(n, ns, BAD_CAST "CanonicalizationMethod", NULL);
600 xmlNewProp(nn,
601 BAD_CAST "Algorithm",
602 BAD_CAST "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
603
604 nn=xmlNewChild(n, ns, BAD_CAST "SignatureMethod", NULL);
605 xmlNewProp(nn,
606 BAD_CAST "Algorithm",
607 BAD_CAST "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
608
609 nn=xmlNewChild(n, ns, BAD_CAST "Reference", NULL);
610 xmlNewProp(nn,
611 BAD_CAST "URI",
612 BAD_CAST "#xpointer(//*[@authenticate='true'])");
613
614 nnn=xmlNewChild(nn, ns, BAD_CAST "Transforms", NULL);
615 nnnn=xmlNewChild(nnn, ns, BAD_CAST "Transform", NULL);
616 xmlNewProp(nnnn,
617 BAD_CAST "Algorithm",
618 BAD_CAST "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
619
620 nn=xmlNewChild(n, ns, BAD_CAST "DigestMethod", NULL);
621 xmlNewProp(nn,
622 BAD_CAST "Algorithm",
623 BAD_CAST "http://www.w3.org/2000/09/xmldsig#sha1");
624
625 return 0;
626 }
627
628
629
EB_Msg_ExtractAndDecodeSessionKey(EB_MSG * msg,AB_PROVIDER * pro,AB_USER * u)630 GWEN_CRYPT_KEY *EB_Msg_ExtractAndDecodeSessionKey(EB_MSG *msg, AB_PROVIDER *pro, AB_USER *u)
631 {
632 xmlNodePtr node=NULL;
633 GWEN_CRYPT_KEY *skey=NULL;
634 int rv;
635
636 assert(msg);
637 assert(msg->usage);
638
639 /* extract keys and store them */
640 node=EB_Xml_GetNode(xmlDocGetRootElement(msg->doc),
641 "body/DataTransfer/DataEncryptionInfo",
642 GWEN_PATH_FLAGS_NAMEMUSTEXIST);
643 if (node==NULL) {
644 DBG_ERROR(AQEBICS_LOGDOMAIN, "Bad message: Missing session key");
645 return NULL;
646 }
647 rv=EBC_Provider_ExtractSessionKey(pro, u, node, &skey);
648 if (rv<0) {
649 DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
650 return NULL;
651 }
652 DBG_INFO(AQEBICS_LOGDOMAIN, "Got session key");
653
654 return skey;
655 }
656
657
658
659
660
661