1 /*
2  * XML Security Library (http://www.aleksey.com/xmlsec).
3  *
4  *
5  * This is free software; see Copyright file in the source
6  * distribution for preciese wording.
7  *
8  * Copyright (C) 2002-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
9  */
10 /**
11  * SECTION:xpath
12  * @Short_description: XPath transform implementation.
13  * @Stability: Private
14  *
15  *
16  */
17 
18 #include "globals.h"
19 
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <libxml/tree.h>
24 #include <libxml/xpath.h>
25 #include <libxml/xpathInternals.h>
26 #include <libxml/xpointer.h>
27 
28 #include <xmlsec/xmlsec.h>
29 #include <xmlsec/xmltree.h>
30 #include <xmlsec/keys.h>
31 #include <xmlsec/list.h>
32 #include <xmlsec/transforms.h>
33 #include <xmlsec/errors.h>
34 
35 
36 /**************************************************************************
37  *
38  * xmlSecXPathHereFunction:
39  * @ctxt:               the ponter to XPath context.
40  * @nargs:              the arguments number.
41  *
42  * The implementation of XPath "here()" function.
43  * See xmlXPtrHereFunction() in xpointer.c. the only change is that
44  * we return NodeSet instead of NodeInterval.
45  *
46  *****************************************************************************/
47 static void
xmlSecXPathHereFunction(xmlXPathParserContextPtr ctxt,int nargs)48 xmlSecXPathHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
49     CHECK_ARITY(0);
50 
51     if((ctxt == NULL) || (ctxt->context == NULL) || (ctxt->context->here == NULL)) {
52         XP_ERROR(XPTR_SYNTAX_ERROR);
53     }
54     valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->here));
55 }
56 
57 /**************************************************************************
58  *
59  * XPath/XPointer data
60  *
61  *****************************************************************************/
62 typedef struct _xmlSecXPathData                 xmlSecXPathData,
63                                                 *xmlSecXPathDataPtr;
64 typedef enum {
65     xmlSecXPathDataTypeXPath,
66     xmlSecXPathDataTypeXPath2,
67     xmlSecXPathDataTypeXPointer
68 } xmlSecXPathDataType;
69 
70 struct _xmlSecXPathData {
71     xmlSecXPathDataType                 type;
72     xmlXPathContextPtr                  ctx;
73     xmlChar*                            expr;
74     xmlSecNodeSetOp                     nodeSetOp;
75     xmlSecNodeSetType                   nodeSetType;
76 };
77 
78 static xmlSecXPathDataPtr       xmlSecXPathDataCreate           (xmlSecXPathDataType type);
79 static void                     xmlSecXPathDataDestroy          (xmlSecXPathDataPtr data);
80 static int                      xmlSecXPathDataSetExpr          (xmlSecXPathDataPtr data,
81                                                                  const xmlChar* expr);
82 static int                      xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data,
83                                                                  xmlNodePtr node);
84 static int                      xmlSecXPathDataNodeRead         (xmlSecXPathDataPtr data,
85                                                                  xmlNodePtr node);
86 static xmlSecNodeSetPtr         xmlSecXPathDataExecute          (xmlSecXPathDataPtr data,
87                                                                  xmlDocPtr doc,
88                                                                  xmlNodePtr hereNode);
89 
90 static xmlSecXPathDataPtr
xmlSecXPathDataCreate(xmlSecXPathDataType type)91 xmlSecXPathDataCreate(xmlSecXPathDataType type) {
92     xmlSecXPathDataPtr data;
93 
94     data = (xmlSecXPathDataPtr) xmlMalloc(sizeof(xmlSecXPathData));
95     if(data == NULL) {
96         xmlSecMallocError(sizeof(xmlSecXPathData), NULL);
97         return(NULL);
98     }
99     memset(data, 0, sizeof(xmlSecXPathData));
100 
101     data->type = type;
102     data->nodeSetType = xmlSecNodeSetTree;
103 
104     /* create xpath or xpointer context */
105     switch(data->type) {
106     case xmlSecXPathDataTypeXPath:
107     case xmlSecXPathDataTypeXPath2:
108         data->ctx = xmlXPathNewContext(NULL); /* we'll set doc in the context later */
109         if(data->ctx == NULL) {
110             xmlSecXmlError("xmlXPathNewContext", NULL);
111             xmlSecXPathDataDestroy(data);
112             return(NULL);
113         }
114         break;
115     case xmlSecXPathDataTypeXPointer:
116         data->ctx = xmlXPtrNewContext(NULL, NULL, NULL); /* we'll set doc in the context later */
117         if(data->ctx == NULL) {
118             xmlSecXmlError("xmlXPtrNewContext", NULL);
119             xmlSecXPathDataDestroy(data);
120             return(NULL);
121         }
122         break;
123     }
124 
125     return(data);
126 }
127 
128 static void
xmlSecXPathDataDestroy(xmlSecXPathDataPtr data)129 xmlSecXPathDataDestroy(xmlSecXPathDataPtr data) {
130     xmlSecAssert(data != NULL);
131 
132     if(data->expr != NULL) {
133         xmlFree(data->expr);
134     }
135     if(data->ctx != NULL) {
136         xmlXPathFreeContext(data->ctx);
137     }
138     memset(data, 0, sizeof(xmlSecXPathData));
139     xmlFree(data);
140 }
141 
142 static int
xmlSecXPathDataSetExpr(xmlSecXPathDataPtr data,const xmlChar * expr)143 xmlSecXPathDataSetExpr(xmlSecXPathDataPtr data, const xmlChar* expr) {
144     xmlSecAssert2(data != NULL, -1);
145     xmlSecAssert2(data->expr == NULL, -1);
146     xmlSecAssert2(data->ctx != NULL, -1);
147     xmlSecAssert2(expr != NULL, -1);
148 
149     data->expr = xmlStrdup(expr);
150     if(data->expr == NULL) {
151         xmlSecStrdupError(expr, NULL);
152         return(-1);
153     }
154     return(0);
155 }
156 
157 
158 static int
xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data,xmlNodePtr node)159 xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data, xmlNodePtr node) {
160     xmlNodePtr cur;
161     xmlNsPtr ns;
162     int ret;
163 
164     xmlSecAssert2(data != NULL, -1);
165     xmlSecAssert2(data->ctx != NULL, -1);
166     xmlSecAssert2(node != NULL, -1);
167 
168     /* register namespaces */
169     for(cur = node; cur != NULL; cur = cur->parent) {
170         for(ns = cur->nsDef; ns != NULL; ns = ns->next) {
171             /* check that we have no other namespace with same prefix already */
172             if((ns->prefix != NULL) && (xmlXPathNsLookup(data->ctx, ns->prefix) == NULL)){
173                 ret = xmlXPathRegisterNs(data->ctx, ns->prefix, ns->href);
174                 if(ret != 0) {
175                     xmlSecXmlError2("xmlXPathRegisterNs", NULL,
176                                     "prefix=%s", xmlSecErrorsSafeString(ns->prefix));
177                     return(-1);
178                 }
179             }
180         }
181     }
182 
183     return(0);
184 }
185 
186 static int
xmlSecXPathDataNodeRead(xmlSecXPathDataPtr data,xmlNodePtr node)187 xmlSecXPathDataNodeRead(xmlSecXPathDataPtr data, xmlNodePtr node) {
188     int ret;
189 
190     xmlSecAssert2(data != NULL, -1);
191     xmlSecAssert2(data->expr == NULL, -1);
192     xmlSecAssert2(data->ctx != NULL, -1);
193     xmlSecAssert2(node != NULL, -1);
194 
195     ret = xmlSecXPathDataRegisterNamespaces (data, node);
196     if(ret < 0) {
197         xmlSecInternalError("xmlSecXPathDataRegisterNamespaces", NULL);
198         return(-1);
199     }
200 
201     /* read node content and set expr */
202     data->expr = xmlNodeGetContent(node);
203     if(data->expr == NULL) {
204         xmlSecInvalidNodeContentError(node, NULL, "empty");
205         return(-1);
206     }
207 
208     return(0);
209 }
210 
211 static xmlSecNodeSetPtr
xmlSecXPathDataExecute(xmlSecXPathDataPtr data,xmlDocPtr doc,xmlNodePtr hereNode)212 xmlSecXPathDataExecute(xmlSecXPathDataPtr data, xmlDocPtr doc, xmlNodePtr hereNode) {
213     xmlXPathObjectPtr xpathObj = NULL;
214     xmlSecNodeSetPtr nodes;
215 
216     xmlSecAssert2(data != NULL, NULL);
217     xmlSecAssert2(data->expr != NULL, NULL);
218     xmlSecAssert2(data->ctx != NULL, NULL);
219     xmlSecAssert2(doc != NULL, NULL);
220     xmlSecAssert2(hereNode != NULL, NULL);
221 
222     /* do not forget to set the doc */
223     data->ctx->doc = doc;
224 
225     /* here function works only on the same document */
226     if(hereNode->doc == doc) {
227         xmlXPathRegisterFunc(data->ctx, (xmlChar *)"here", xmlSecXPathHereFunction);
228         data->ctx->here = hereNode;
229         data->ctx->xptr = 1;
230     }
231 
232     /* execute xpath or xpointer expression */
233     switch(data->type) {
234     case xmlSecXPathDataTypeXPath:
235     case xmlSecXPathDataTypeXPath2:
236         xpathObj = xmlXPathEvalExpression(data->expr, data->ctx);
237         if(xpathObj == NULL) {
238             xmlSecXmlError2("xmlXPathEvalExpression", NULL,
239                             "expr=%s", xmlSecErrorsSafeString(data->expr));
240             return(NULL);
241         }
242         break;
243     case xmlSecXPathDataTypeXPointer:
244         xpathObj = xmlXPtrEval(data->expr, data->ctx);
245         if(xpathObj == NULL) {
246             xmlSecXmlError2("xmlXPtrEval", NULL,
247                             "expr=%s", xmlSecErrorsSafeString(data->expr));
248             return(NULL);
249         }
250         break;
251     }
252 
253     /* sometime LibXML2 returns an empty nodeset or just NULL, we want
254     to reserve NULL for our own purposes so we simply create an empty
255     node set here */
256     if(xpathObj->nodesetval == NULL) {
257     	xpathObj->nodesetval = xmlXPathNodeSetCreate(NULL);
258     	if(xpathObj->nodesetval == NULL) {
259     		xmlXPathFreeObject(xpathObj);
260             xmlSecXmlError2("xmlXPathNodeSetCreate", NULL,
261                             "expr=%s", xmlSecErrorsSafeString(data->expr));
262     		return(NULL);
263     	}
264     }
265 
266     nodes = xmlSecNodeSetCreate(doc, xpathObj->nodesetval, data->nodeSetType);
267     if(nodes == NULL) {
268         xmlSecInternalError2("xmlSecNodeSetCreate", NULL, "type=%d", data->nodeSetType);
269         xmlXPathFreeObject(xpathObj);
270         return(NULL);
271     }
272     xpathObj->nodesetval = NULL;
273     xmlXPathFreeObject(xpathObj);
274 
275     return(nodes);
276 }
277 
278 
279 /**************************************************************************
280  *
281  * XPath data list
282  *
283  *****************************************************************************/
284 #define xmlSecXPathDataListId   \
285         xmlSecXPathDataListGetKlass()
286 static xmlSecPtrListId  xmlSecXPathDataListGetKlass             (void);
287 static xmlSecNodeSetPtr xmlSecXPathDataListExecute              (xmlSecPtrListPtr dataList,
288                                                                  xmlDocPtr doc,
289                                                                  xmlNodePtr hereNode,
290                                                                  xmlSecNodeSetPtr nodes);
291 
292 static xmlSecPtrListKlass xmlSecXPathDataListKlass = {
293     BAD_CAST "xpath-data-list",
294     NULL,                                               /* xmlSecPtrDuplicateItemMethod duplicateItem; */
295     (xmlSecPtrDestroyItemMethod)xmlSecXPathDataDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */
296     NULL,                                               /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
297     NULL,                                               /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
298 };
299 
300 static xmlSecPtrListId
xmlSecXPathDataListGetKlass(void)301 xmlSecXPathDataListGetKlass(void) {
302     return(&xmlSecXPathDataListKlass);
303 }
304 
305 static xmlSecNodeSetPtr
xmlSecXPathDataListExecute(xmlSecPtrListPtr dataList,xmlDocPtr doc,xmlNodePtr hereNode,xmlSecNodeSetPtr nodes)306 xmlSecXPathDataListExecute(xmlSecPtrListPtr dataList, xmlDocPtr doc,
307                            xmlNodePtr hereNode, xmlSecNodeSetPtr nodes) {
308     xmlSecXPathDataPtr data;
309     xmlSecNodeSetPtr res, tmp, tmp2;
310     xmlSecSize pos;
311 
312     xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), NULL);
313     xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, NULL);
314     xmlSecAssert2(doc != NULL, NULL);
315     xmlSecAssert2(hereNode != NULL, NULL);
316 
317     res = nodes;
318     for(pos = 0; pos < xmlSecPtrListGetSize(dataList); ++pos) {
319         data = (xmlSecXPathDataPtr)xmlSecPtrListGetItem(dataList, pos);
320         if(data == NULL) {
321             xmlSecInternalError2("xmlSecPtrListGetItem", NULL, "pos=%d", pos);
322             if((res != NULL) && (res != nodes)) {
323                 xmlSecNodeSetDestroy(res);
324             }
325             return(NULL);
326         }
327 
328         tmp = xmlSecXPathDataExecute(data, doc, hereNode);
329         if(tmp == NULL) {
330             xmlSecInternalError("xmlSecXPathDataExecute", NULL);
331             if((res != NULL) && (res != nodes)) {
332                 xmlSecNodeSetDestroy(res);
333             }
334             return(NULL);
335         }
336 
337         tmp2 = xmlSecNodeSetAdd(res, tmp, data->nodeSetOp);
338         if(tmp2 == NULL) {
339             xmlSecInternalError2("xmlSecNodeSetAdd", NULL,
340                                  "nodeSetOp=%d", (int)data->nodeSetOp);
341             if((res != NULL) && (res != nodes)) {
342                 xmlSecNodeSetDestroy(res);
343             }
344             xmlSecNodeSetDestroy(tmp);
345             return(NULL);
346         }
347         res = tmp2;
348     }
349 
350     return(res);
351 }
352 
353 /******************************************************************************
354  *
355  * XPath/XPointer transforms
356  *
357  * xmlSecXPathDataList is located after xmlSecTransform structure
358  *
359  *****************************************************************************/
360 #define xmlSecXPathTransformSize        \
361     (sizeof(xmlSecTransform) + sizeof(xmlSecPtrList))
362 #define xmlSecXPathTransformGetDataList(transform) \
363     ((xmlSecTransformCheckSize((transform), xmlSecXPathTransformSize)) ? \
364         (xmlSecPtrListPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \
365         (xmlSecPtrListPtr)NULL)
366 #define xmlSecTransformXPathCheckId(transform) \
367     (xmlSecTransformCheckId((transform), xmlSecTransformXPathId) || \
368      xmlSecTransformCheckId((transform), xmlSecTransformXPath2Id) || \
369      xmlSecTransformCheckId((transform), xmlSecTransformXPointerId))
370 
371 static int              xmlSecTransformXPathInitialize  (xmlSecTransformPtr transform);
372 static void             xmlSecTransformXPathFinalize    (xmlSecTransformPtr transform);
373 static int              xmlSecTransformXPathExecute     (xmlSecTransformPtr transform,
374                                                          int last,
375                                                          xmlSecTransformCtxPtr transformCtx);
376 
377 static int
xmlSecTransformXPathInitialize(xmlSecTransformPtr transform)378 xmlSecTransformXPathInitialize(xmlSecTransformPtr transform) {
379     xmlSecPtrListPtr dataList;
380     int ret;
381 
382     xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1);
383 
384     dataList = xmlSecXPathTransformGetDataList(transform);
385     xmlSecAssert2(dataList != NULL, -1);
386 
387     ret = xmlSecPtrListInitialize(dataList, xmlSecXPathDataListId);
388     if(ret < 0) {
389         xmlSecInternalError("xmlSecPtrListInitialize",
390                             xmlSecTransformGetName(transform));
391         return(-1);
392     }
393     return(0);
394 }
395 
396 static void
xmlSecTransformXPathFinalize(xmlSecTransformPtr transform)397 xmlSecTransformXPathFinalize(xmlSecTransformPtr transform) {
398     xmlSecPtrListPtr dataList;
399 
400     xmlSecAssert(xmlSecTransformXPathCheckId(transform));
401 
402     dataList = xmlSecXPathTransformGetDataList(transform);
403     xmlSecAssert(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId));
404 
405     xmlSecPtrListFinalize(dataList);
406 }
407 
408 static int
xmlSecTransformXPathExecute(xmlSecTransformPtr transform,int last,xmlSecTransformCtxPtr transformCtx)409 xmlSecTransformXPathExecute(xmlSecTransformPtr transform, int last,
410                             xmlSecTransformCtxPtr transformCtx) {
411     xmlSecPtrListPtr dataList;
412     xmlDocPtr doc;
413 
414     xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1);
415     xmlSecAssert2(transform->hereNode != NULL, -1);
416     xmlSecAssert2(transform->outNodes == NULL, -1);
417     xmlSecAssert2(last != 0, -1);
418     xmlSecAssert2(transformCtx != NULL, -1);
419 
420     dataList = xmlSecXPathTransformGetDataList(transform);
421     xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
422     xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, -1);
423 
424     doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc;
425     xmlSecAssert2(doc != NULL, -1);
426 
427     transform->outNodes = xmlSecXPathDataListExecute(dataList, doc,
428                                 transform->hereNode, transform->inNodes);
429     if(transform->outNodes == NULL) {
430         xmlSecInternalError("xmlSecXPathDataListExecute",
431                             xmlSecTransformGetName(transform));
432         return(-1);
433     }
434     return(0);
435 }
436 
437 /******************************************************************************
438  *
439  * XPath transform
440  *
441  *****************************************************************************/
442 static int              xmlSecTransformXPathNodeRead    (xmlSecTransformPtr transform,
443                                                          xmlNodePtr node,
444                                                          xmlSecTransformCtxPtr transformCtx);
445 
446 static xmlSecTransformKlass xmlSecTransformXPathKlass = {
447     /* klass/object sizes */
448     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
449     xmlSecXPathTransformSize,                   /* xmlSecSize objSize */
450 
451     xmlSecNameXPath,                            /* const xmlChar* name; */
452     xmlSecXPathNs,                              /* const xmlChar* href; */
453     xmlSecTransformUsageDSigTransform,          /* xmlSecTransformUsage usage; */
454 
455     xmlSecTransformXPathInitialize,             /* xmlSecTransformInitializeMethod initialize; */
456     xmlSecTransformXPathFinalize,               /* xmlSecTransformFinalizeMethod finalize; */
457     xmlSecTransformXPathNodeRead,               /* xmlSecTransformNodeReadMethod readNode; */
458     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
459     NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
460     NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
461     NULL,                                       /* xmlSecTransformValidateMethod validate; */
462     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
463     NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
464     NULL,                                       /* xmlSecTransformPopBinMethod popBin; */
465     xmlSecTransformDefaultPushXml,              /* xmlSecTransformPushXmlMethod pushXml; */
466     xmlSecTransformDefaultPopXml,               /* xmlSecTransformPopXmlMethod popXml; */
467     xmlSecTransformXPathExecute,                /* xmlSecTransformExecuteMethod execute; */
468 
469     NULL,                                       /* void* reserved0; */
470     NULL,                                       /* void* reserved1; */
471 };
472 
473 /**
474  * xmlSecTransformXPathGetKlass:
475  *
476  * The XPath transform evaluates given XPath expression and
477  * intersects the result with the previous nodes set. See
478  * http://www.w3.org/TR/xmldsig-core/#sec-XPath for more details.
479  *
480  * Returns: XPath transform id.
481  */
482 xmlSecTransformId
xmlSecTransformXPathGetKlass(void)483 xmlSecTransformXPathGetKlass(void) {
484     return(&xmlSecTransformXPathKlass);
485 }
486 
487 static const char xpathPattern[] = "(//. | //@* | //namespace::*)[boolean(%s)]";
488 static int
xmlSecTransformXPathNodeRead(xmlSecTransformPtr transform,xmlNodePtr node,xmlSecTransformCtxPtr transformCtx)489 xmlSecTransformXPathNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
490     xmlSecPtrListPtr dataList;
491     xmlSecXPathDataPtr data;
492     xmlNodePtr cur;
493     xmlChar* tmp;
494     int tmpSize;
495     int ret;
496 
497     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPathId), -1);
498     xmlSecAssert2(node != NULL, -1);
499     xmlSecAssert2(transformCtx != NULL, -1);
500 
501     dataList = xmlSecXPathTransformGetDataList(transform);
502     xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
503     xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
504 
505     /* there is only one required node */
506     cur = xmlSecGetNextElementNode(node->children);
507     if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPath, xmlSecDSigNs))) {
508         xmlSecInvalidNodeError(cur, xmlSecNodeXPath,
509                                xmlSecTransformGetName(transform));
510         return(-1);
511     }
512 
513     /* read information from the node */
514     data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath);
515     if(data == NULL) {
516         xmlSecInternalError("xmlSecXPathDataCreate",
517                             xmlSecTransformGetName(transform));
518         return(-1);
519     }
520 
521     ret = xmlSecXPathDataNodeRead(data, cur);
522     if(ret < 0) {
523         xmlSecInternalError("xmlSecXPathDataNodeRead",
524                             xmlSecTransformGetName(transform));
525         xmlSecXPathDataDestroy(data);
526         return(-1);
527     }
528 
529     /* append it to the list */
530     ret = xmlSecPtrListAdd(dataList, data);
531     if(ret < 0) {
532         xmlSecInternalError("xmlSecPtrListAdd",
533                             xmlSecTransformGetName(transform));
534         xmlSecXPathDataDestroy(data);
535         return(-1);
536     }
537 
538     /* create full XPath expression */
539     xmlSecAssert2(data->expr != NULL, -1);
540     tmpSize = xmlStrlen(data->expr) + xmlStrlen(BAD_CAST xpathPattern) + 1;
541     tmp = (xmlChar*) xmlMalloc(sizeof(xmlChar) * tmpSize);
542     if(tmp == NULL) {
543         xmlSecMallocError(sizeof(xmlChar) * tmpSize,
544                           xmlSecTransformGetName(transform));
545         return(-1);
546     }
547     ret = xmlStrPrintf(tmp, tmpSize, xpathPattern, (char*)data->expr);
548     if(ret < 0) {
549        xmlSecXmlError("xmlStrPrintf", xmlSecTransformGetName(transform));
550        xmlFree(tmp);
551        return(-1);
552     }
553     xmlFree(data->expr);
554     data->expr = tmp;
555 
556     /* set correct node set type and operation */
557     data->nodeSetOp     = xmlSecNodeSetIntersection;
558     data->nodeSetType   = xmlSecNodeSetNormal;
559 
560     /* check that we have nothing else */
561     cur = xmlSecGetNextElementNode(cur->next);
562     if(cur != NULL) {
563         xmlSecUnexpectedNodeError(cur, xmlSecTransformGetName(transform));
564         return(-1);
565     }
566     return(0);
567 }
568 
569 /******************************************************************************
570  *
571  * XPath2 transform
572  *
573  *****************************************************************************/
574 static int              xmlSecTransformXPath2NodeRead   (xmlSecTransformPtr transform,
575                                                          xmlNodePtr node,
576                                                          xmlSecTransformCtxPtr transformCtx);
577 static xmlSecTransformKlass xmlSecTransformXPath2Klass = {
578     /* klass/object sizes */
579     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
580     xmlSecXPathTransformSize,                   /* xmlSecSize objSize */
581 
582     xmlSecNameXPath2,                           /* const xmlChar* name; */
583     xmlSecXPath2Ns,                             /* const xmlChar* href; */
584     xmlSecTransformUsageDSigTransform,          /* xmlSecTransformUsage usage; */
585 
586     xmlSecTransformXPathInitialize,             /* xmlSecTransformInitializeMethod initialize; */
587     xmlSecTransformXPathFinalize,               /* xmlSecTransformFinalizeMethod finalize; */
588     xmlSecTransformXPath2NodeRead,              /* xmlSecTransformNodeReadMethod readNode; */
589     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
590     NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
591     NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
592     NULL,                                       /* xmlSecTransformValidateMethod validate; */
593     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
594     NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
595     NULL,                                       /* xmlSecTransformPopBinMethod popBin; */
596     xmlSecTransformDefaultPushXml,              /* xmlSecTransformPushXmlMethod pushXml; */
597     xmlSecTransformDefaultPopXml,               /* xmlSecTransformPopXmlMethod popXml; */
598     xmlSecTransformXPathExecute,                /* xmlSecTransformExecuteMethod execute; */
599 
600     NULL,                                       /* void* reserved0; */
601     NULL,                                       /* void* reserved1; */
602 };
603 
604 /**
605  * xmlSecTransformXPath2GetKlass:
606  *
607  * The XPath2 transform (http://www.w3.org/TR/xmldsig-filter2/).
608  *
609  * Returns: XPath2 transform klass.
610  */
611 xmlSecTransformId
xmlSecTransformXPath2GetKlass(void)612 xmlSecTransformXPath2GetKlass(void) {
613     return(&xmlSecTransformXPath2Klass);
614 }
615 
616 static int
xmlSecTransformXPath2NodeRead(xmlSecTransformPtr transform,xmlNodePtr node,xmlSecTransformCtxPtr transformCtx)617 xmlSecTransformXPath2NodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
618     xmlSecPtrListPtr dataList;
619     xmlSecXPathDataPtr data;
620     xmlNodePtr cur;
621     xmlChar* op;
622     int ret;
623 
624     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPath2Id), -1);
625     xmlSecAssert2(node != NULL, -1);
626     xmlSecAssert2(transformCtx != NULL, -1);
627 
628     dataList = xmlSecXPathTransformGetDataList(transform);
629     xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
630     xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
631 
632     /* There are only xpath nodes */
633     cur = xmlSecGetNextElementNode(node->children);
634     while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeXPath2, xmlSecXPath2Ns)) {
635         /* read information from the node */
636         data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath2);
637         if(data == NULL) {
638             xmlSecInternalError("xmlSecXPathDataCreate",
639                                 xmlSecTransformGetName(transform));
640             return(-1);
641         }
642 
643         ret = xmlSecXPathDataNodeRead(data, cur);
644         if(ret < 0) {
645             xmlSecInternalError("xmlSecXPathDataNodeRead",
646                                 xmlSecTransformGetName(transform));
647             xmlSecXPathDataDestroy(data);
648             return(-1);
649         }
650 
651         /* append it to the list */
652         ret = xmlSecPtrListAdd(dataList, data);
653         if(ret < 0) {
654             xmlSecInternalError("xmlSecPtrListAdd",
655                                 xmlSecTransformGetName(transform));
656             xmlSecXPathDataDestroy(data);
657             return(-1);
658         }
659 
660         /* set correct node set type and operation */
661         data->nodeSetType = xmlSecNodeSetTree;
662         op = xmlGetProp(cur, xmlSecAttrFilter);
663         if(op == NULL) {
664             xmlSecInvalidNodeAttributeError(cur, xmlSecAttrFilter,
665                                             xmlSecTransformGetName(transform),
666                                             "empty");
667             return(-1);
668         }
669         if(xmlStrEqual(op, xmlSecXPath2FilterIntersect)) {
670             data->nodeSetOp = xmlSecNodeSetIntersection;
671         } else if(xmlStrEqual(op, xmlSecXPath2FilterSubtract)) {
672             data->nodeSetOp = xmlSecNodeSetSubtraction;
673         } else if(xmlStrEqual(op, xmlSecXPath2FilterUnion)) {
674             data->nodeSetOp = xmlSecNodeSetUnion;
675         } else {
676             xmlSecInvalidNodeAttributeError(cur, xmlSecAttrFilter,
677                                             xmlSecTransformGetName(transform),
678                                             "unknown");
679             xmlFree(op);
680             return(-1);
681         }
682         xmlFree(op);
683 
684         cur = xmlSecGetNextElementNode(cur->next);
685     }
686 
687     /* check that we have nothing else */
688     if(cur != NULL) {
689         xmlSecUnexpectedNodeError(cur, xmlSecTransformGetName(transform));
690         return(-1);
691     }
692     return(0);
693 }
694 
695 /******************************************************************************
696  *
697  * XPointer transform
698  *
699  *****************************************************************************/
700 static int              xmlSecTransformXPointerNodeRead (xmlSecTransformPtr transform,
701                                                          xmlNodePtr node,
702                                                          xmlSecTransformCtxPtr transformCtx);
703 static xmlSecTransformKlass xmlSecTransformXPointerKlass = {
704     /* klass/object sizes */
705     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
706     xmlSecXPathTransformSize,                   /* xmlSecSize objSize */
707 
708     xmlSecNameXPointer,                         /* const xmlChar* name; */
709     xmlSecXPointerNs,                           /* const xmlChar* href; */
710     xmlSecTransformUsageDSigTransform,          /* xmlSecTransformUsage usage; */
711 
712     xmlSecTransformXPathInitialize,             /* xmlSecTransformInitializeMethod initialize; */
713     xmlSecTransformXPathFinalize,               /* xmlSecTransformFinalizeMethod finalize; */
714     xmlSecTransformXPointerNodeRead,            /* xmlSecTransformNodeReadMethod readNode; */
715     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
716     NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
717     NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
718     NULL,                                       /* xmlSecTransformValidateMethod validate; */
719     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
720     NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
721     NULL,                                       /* xmlSecTransformPopBinMethod popBin; */
722     xmlSecTransformDefaultPushXml,              /* xmlSecTransformPushXmlMethod pushXml; */
723     xmlSecTransformDefaultPopXml,               /* xmlSecTransformPopXmlMethod popXml; */
724     xmlSecTransformXPathExecute,                /* xmlSecTransformExecuteMethod execute; */
725 
726     NULL,                                       /* void* reserved0; */
727     NULL,                                       /* void* reserved1; */
728 };
729 
730 /**
731  * xmlSecTransformXPointerGetKlass:
732  *
733  * The XPointer transform klass
734  * (http://www.ietf.org/internet-drafts/draft-eastlake-xmldsig-uri-02.txt).
735  *
736  * Returns: XPointer transform klass.
737  */
738 xmlSecTransformId
xmlSecTransformXPointerGetKlass(void)739 xmlSecTransformXPointerGetKlass(void) {
740     return(&xmlSecTransformXPointerKlass);
741 }
742 
743 /**
744  * xmlSecTransformXPointerSetExpr:
745  * @transform:          the pointer to XPointer transform.
746  * @expr:               the XPointer expression.
747  * @nodeSetType:        the type of evaluated XPointer expression.
748  * @hereNode:           the pointer to "here" node.
749  *
750  * Sets the XPointer expression for an XPointer @transform.
751  *
752  * Returns: 0 on success or a negative value if an error occurs.
753  */
754 int
xmlSecTransformXPointerSetExpr(xmlSecTransformPtr transform,const xmlChar * expr,xmlSecNodeSetType nodeSetType,xmlNodePtr hereNode)755 xmlSecTransformXPointerSetExpr(xmlSecTransformPtr transform, const xmlChar* expr,
756                             xmlSecNodeSetType  nodeSetType, xmlNodePtr hereNode) {
757     xmlSecPtrListPtr dataList;
758     xmlSecXPathDataPtr data;
759     int ret;
760 
761     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1);
762     xmlSecAssert2(transform->hereNode == NULL, -1);
763     xmlSecAssert2(expr != NULL, -1);
764     xmlSecAssert2(hereNode != NULL, -1);
765 
766     transform->hereNode = hereNode;
767 
768     dataList = xmlSecXPathTransformGetDataList(transform);
769     xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
770     xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
771 
772     data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer);
773     if(data == NULL) {
774         xmlSecInternalError("xmlSecXPathDataCreate",
775                             xmlSecTransformGetName(transform));
776         return(-1);
777     }
778 
779     ret = xmlSecXPathDataRegisterNamespaces(data, hereNode);
780     if(ret < 0) {
781         xmlSecInternalError("xmlSecXPathDataRegisterNamespaces",
782                             xmlSecTransformGetName(transform));
783         xmlSecXPathDataDestroy(data);
784         return(-1);
785     }
786 
787     ret = xmlSecXPathDataSetExpr(data, expr);
788     if(ret < 0) {
789         xmlSecInternalError("xmlSecXPathDataSetExpr",
790                             xmlSecTransformGetName(transform));
791         xmlSecXPathDataDestroy(data);
792         return(-1);
793     }
794 
795     /* append it to the list */
796     ret = xmlSecPtrListAdd(dataList, data);
797     if(ret < 0) {
798         xmlSecInternalError("xmlSecPtrListAdd",
799                             xmlSecTransformGetName(transform));
800         xmlSecXPathDataDestroy(data);
801         return(-1);
802     }
803 
804     /* set correct node set type and operation */
805     data->nodeSetOp     = xmlSecNodeSetIntersection;
806     data->nodeSetType   = nodeSetType;
807 
808     return(0);
809 }
810 
811 static int
xmlSecTransformXPointerNodeRead(xmlSecTransformPtr transform,xmlNodePtr node,xmlSecTransformCtxPtr transformCtx)812 xmlSecTransformXPointerNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
813     xmlSecPtrListPtr dataList;
814     xmlSecXPathDataPtr data;
815     xmlNodePtr cur;
816     int ret;
817 
818     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1);
819     xmlSecAssert2(node != NULL, -1);
820     xmlSecAssert2(transformCtx != NULL, -1);
821 
822     dataList = xmlSecXPathTransformGetDataList(transform);
823     xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
824     xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
825 
826     /* there is only one required node */
827     cur = xmlSecGetNextElementNode(node->children);
828     if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPointer, xmlSecXPointerNs))) {
829         xmlSecInvalidNodeError(cur, xmlSecNodeXPointer,
830                                xmlSecTransformGetName(transform));
831         return(-1);
832     }
833 
834     /* read information from the node */
835     data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer);
836     if(data == NULL) {
837         xmlSecInternalError("xmlSecXPathDataCreate",
838                             xmlSecTransformGetName(transform));
839         return(-1);
840     }
841 
842     ret = xmlSecXPathDataNodeRead(data, cur);
843     if(ret < 0) {
844         xmlSecInternalError("xmlSecXPathDataNodeRead",
845                             xmlSecTransformGetName(transform));
846         xmlSecXPathDataDestroy(data);
847         return(-1);
848     }
849 
850     /* append it to the list */
851     ret = xmlSecPtrListAdd(dataList, data);
852     if(ret < 0) {
853         xmlSecInternalError("xmlSecPtrListAdd",
854                             xmlSecTransformGetName(transform));
855         xmlSecXPathDataDestroy(data);
856         return(-1);
857     }
858 
859     /* set correct node set type and operation */
860     data->nodeSetOp     = xmlSecNodeSetIntersection;
861     data->nodeSetType   = xmlSecNodeSetTree;
862 
863     /* check that we have nothing else */
864     cur = xmlSecGetNextElementNode(cur->next);
865     if(cur != NULL) {
866         xmlSecUnexpectedNodeError(cur, xmlSecTransformGetName(transform));
867         return(-1);
868     }
869     return(0);
870 }
871 
872 
873 /******************************************************************************
874  *
875  * Visa3DHack transform
876  *
877  *****************************************************************************/
878 #define xmlSecVisa3DHackTransformSize   \
879     (sizeof(xmlSecTransform) + sizeof(xmlChar*))
880 #define xmlSecVisa3DHackTransformGetIDPtr(transform) \
881     ((xmlSecTransformCheckSize((transform), xmlSecVisa3DHackTransformSize)) ? \
882         (xmlChar**)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \
883         (xmlChar**)NULL)
884 #define xmlSecTransformVisa3DHackCheckId(transform) \
885     (xmlSecTransformCheckId((transform), xmlSecTransformVisa3DHackId))
886 
887 static int              xmlSecTransformVisa3DHackInitialize     (xmlSecTransformPtr transform);
888 static void             xmlSecTransformVisa3DHackFinalize       (xmlSecTransformPtr transform);
889 static int              xmlSecTransformVisa3DHackExecute        (xmlSecTransformPtr transform,
890                                                                  int last,
891                                                                  xmlSecTransformCtxPtr transformCtx);
892 
893 static xmlSecTransformKlass xmlSecTransformVisa3DHackKlass = {
894     /* klass/object sizes */
895     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
896     xmlSecVisa3DHackTransformSize,              /* xmlSecSize objSize */
897 
898     BAD_CAST "Visa3DHackTransform",             /* const xmlChar* name; */
899     NULL,                                       /* const xmlChar* href; */
900     xmlSecTransformUsageDSigTransform,          /* xmlSecTransformUsage usage; */
901 
902     xmlSecTransformVisa3DHackInitialize,        /* xmlSecTransformInitializeMethod initialize; */
903     xmlSecTransformVisa3DHackFinalize,          /* xmlSecTransformFinalizeMethod finalize; */
904     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
905     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
906     NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
907     NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
908     NULL,                                       /* xmlSecTransformValidateMethod validate; */
909     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
910     NULL,                                       /* xmlSecTransformPushBinMethod pushBin; */
911     NULL,                                       /* xmlSecTransformPopBinMethod popBin; */
912     xmlSecTransformDefaultPushXml,              /* xmlSecTransformPushXmlMethod pushXml; */
913     xmlSecTransformDefaultPopXml,               /* xmlSecTransformPopXmlMethod popXml; */
914     xmlSecTransformVisa3DHackExecute,           /* xmlSecTransformExecuteMethod execute; */
915 
916     NULL,                                       /* void* reserved0; */
917     NULL,                                       /* void* reserved1; */
918 };
919 
920 /**
921  * xmlSecTransformVisa3DHackGetKlass:
922  *
923  * The Visa3DHack transform klass. The only reason why we need this
924  * is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows
925  * invalid XPointer expressions in the URI attribute. Since we couldn't evaluate
926  * such expressions thru XPath/XPointer engine, we need to have this hack here.
927  *
928  * Returns: Visa3DHack transform klass.
929  */
930 xmlSecTransformId
xmlSecTransformVisa3DHackGetKlass(void)931 xmlSecTransformVisa3DHackGetKlass(void) {
932     return(&xmlSecTransformVisa3DHackKlass);
933 }
934 
935 /**
936  * xmlSecTransformVisa3DHackSetID:
937  * @transform:          the pointer to Visa3DHack transform.
938  * @id:                 the ID value.
939  *
940  * Sets the ID value for an Visa3DHack @transform.
941  *
942  * Returns: 0 on success or a negative value if an error occurs.
943  */
944 int
xmlSecTransformVisa3DHackSetID(xmlSecTransformPtr transform,const xmlChar * id)945 xmlSecTransformVisa3DHackSetID(xmlSecTransformPtr transform, const xmlChar* id) {
946     xmlChar** idPtr;
947 
948     xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformVisa3DHackId), -1);
949     xmlSecAssert2(id != NULL, -1);
950 
951     idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform);
952     xmlSecAssert2(idPtr != NULL, -1);
953     xmlSecAssert2((*idPtr) == NULL, -1);
954 
955     (*idPtr) = xmlStrdup(id);
956     if((*idPtr) == NULL) {
957         xmlSecStrdupError(id, xmlSecTransformGetName(transform));
958         return(-1);
959     }
960 
961     return(0);
962 }
963 
964 static int
xmlSecTransformVisa3DHackInitialize(xmlSecTransformPtr transform)965 xmlSecTransformVisa3DHackInitialize(xmlSecTransformPtr transform) {
966     xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1);
967 
968     return(0);
969 }
970 
971 static void
xmlSecTransformVisa3DHackFinalize(xmlSecTransformPtr transform)972 xmlSecTransformVisa3DHackFinalize(xmlSecTransformPtr transform) {
973     xmlChar** idPtr;
974 
975     xmlSecAssert(xmlSecTransformVisa3DHackCheckId(transform));
976 
977     idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform);
978     xmlSecAssert(idPtr != NULL);
979 
980     if((*idPtr) != NULL) {
981         xmlFree((*idPtr));
982     }
983     (*idPtr) = NULL;
984 }
985 
986 static int
xmlSecTransformVisa3DHackExecute(xmlSecTransformPtr transform,int last,xmlSecTransformCtxPtr transformCtx)987 xmlSecTransformVisa3DHackExecute(xmlSecTransformPtr transform, int last,
988                             xmlSecTransformCtxPtr transformCtx) {
989     xmlChar** idPtr;
990     xmlDocPtr doc;
991     xmlAttrPtr attr;
992     xmlNodeSetPtr nodeSet;
993 
994     xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1);
995     xmlSecAssert2(transform->outNodes == NULL, -1);
996     xmlSecAssert2(last != 0, -1);
997     xmlSecAssert2(transformCtx != NULL, -1);
998 
999     idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform);
1000     xmlSecAssert2(idPtr != NULL, -1);
1001     xmlSecAssert2((*idPtr) != NULL, -1);
1002 
1003     doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc;
1004     xmlSecAssert2(doc != NULL, -1);
1005 
1006     attr = xmlGetID(doc, (*idPtr));
1007     if((attr == NULL) || (attr->parent == NULL)) {
1008         xmlSecXmlError2("xmlGetID", xmlSecTransformGetName(transform),
1009                         "id=\"%s\"", xmlSecErrorsSafeString(*idPtr));
1010         return(-1);
1011     }
1012 
1013     nodeSet = xmlXPathNodeSetCreate(attr->parent);
1014     if(nodeSet == NULL) {
1015         xmlSecXmlError2("xmlXPathNodeSetCreate", xmlSecTransformGetName(transform),
1016                         "id=\"%s\"", xmlSecErrorsSafeString(*idPtr));
1017         return(-1);
1018     }
1019 
1020     transform->outNodes = xmlSecNodeSetCreate(doc, nodeSet, xmlSecNodeSetTreeWithoutComments);
1021     if(transform->outNodes == NULL) {
1022         xmlSecInternalError("xmlSecNodeSetCreate",
1023                             xmlSecTransformGetName(transform));
1024         xmlXPathFreeNodeSet(nodeSet);
1025         return(-1);
1026     }
1027     return(0);
1028 }
1029