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