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