/**
* XML Security Library (http://www.aleksey.com/xmlsec).
*
* XPath transform
*
* This is free software; see Copyright file in the source
* distribution for preciese wording.
*
* Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
* Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
*/
#include "xmlsec_globals.h"
#include <stdlib.h>
#include <string.h>
#include <stdapis/libxml2/libxml2_tree.h>
#include <stdapis/libxml2/libxml2_globals.h>
#include <stdapis/libxml2/libxml2_valid.h>
#include <stdapis/libxml2/libxml2_xpath.h>
#include <stdapis/libxml2/libxml2_xpathinternals.h>
#include <stdapis/libxml2/libxml2_xpointer.h>
#include "xmlsec_xmlsec.h"
#include "xmlsec_xmltree.h"
#include "xmlsec_keys.h"
#include "xmlsec_list.h"
#include "xmlsec_transforms.h"
#include "xmlsec_errors.h"
/**************************************************************************
*
* xmlSecXPathHereFunction:
* @ctxt: the ponter to XPath context.
* @nargs: the arguments nubmer.
*
* The implementation of XPath "here()" function.
* See xmlXPtrHereFunction() in xpointer.c. the only change is that
* we return NodeSet instead of NodeInterval.
*
*****************************************************************************/
static void
xmlSecXPathHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(0);
if((ctxt == NULL) || (ctxt->context == NULL) || (ctxt->context->here == NULL)) {
XP_ERROR(XPTR_SYNTAX_ERROR);
}
valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->here));
}
/**************************************************************************
*
* XPath/XPointer data
*
*****************************************************************************/
typedef struct _xmlSecXPathData xmlSecXPathData,
*xmlSecXPathDataPtr;
typedef enum {
xmlSecXPathDataTypeXPath,
xmlSecXPathDataTypeXPath2,
xmlSecXPathDataTypeXPointer
} xmlSecXPathDataType;
struct _xmlSecXPathData {
xmlSecXPathDataType type;
xmlXPathContextPtr ctx;
xmlChar* expr;
xmlSecNodeSetOp nodeSetOp;
xmlSecNodeSetType nodeSetType;
};
static xmlSecXPathDataPtr xmlSecXPathDataCreate (xmlSecXPathDataType type);
static void xmlSecXPathDataDestroy (xmlSecXPathDataPtr data);
static int xmlSecXPathDataSetExpr (xmlSecXPathDataPtr data,
const xmlChar* expr);
static int xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data,
xmlNodePtr node);
static int xmlSecXPathDataNodeRead (xmlSecXPathDataPtr data,
xmlNodePtr node);
static xmlSecNodeSetPtr xmlSecXPathDataExecute (xmlSecXPathDataPtr data,
xmlDocPtr doc,
xmlNodePtr hereNode);
static xmlSecXPathDataPtr
xmlSecXPathDataCreate(xmlSecXPathDataType type) {
xmlSecXPathDataPtr data;
data = (xmlSecXPathDataPtr) xmlMalloc(sizeof(xmlSecXPathData));
if(data == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_MALLOC_FAILED,
"sizeof(xmlSecXPathData)=%d",
sizeof(xmlSecXPathData));
return(NULL);
}
memset(data, 0, sizeof(xmlSecXPathData));
data->type = type;
data->nodeSetType = xmlSecNodeSetTree;
/* create xpath or xpointer context */
switch(data->type) {
case xmlSecXPathDataTypeXPath:
case xmlSecXPathDataTypeXPath2:
data->ctx = xmlXPathNewContext(NULL); /* we'll set doc in the context later */
if(data->ctx == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlXPathNewContext",
XMLSEC_ERRORS_R_XML_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(NULL);
}
break;
case xmlSecXPathDataTypeXPointer:
data->ctx = xmlXPtrNewContext(NULL, NULL, NULL); /* we'll set doc in the context later */
if(data->ctx == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlXPtrNewContext",
XMLSEC_ERRORS_R_XML_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(NULL);
}
break;
}
return(data);
}
static void
xmlSecXPathDataDestroy(xmlSecXPathDataPtr data) {
xmlSecAssert(data != NULL);
if(data->expr != NULL) {
xmlFree(data->expr);
}
if(data->ctx != NULL) {
xmlXPathFreeContext(data->ctx);
}
memset(data, 0, sizeof(xmlSecXPathData));
xmlFree(data);
}
static int
xmlSecXPathDataSetExpr(xmlSecXPathDataPtr data, const xmlChar* expr) {
xmlSecAssert2(data != NULL, -1);
xmlSecAssert2(data->expr == NULL, -1);
xmlSecAssert2(data->ctx != NULL, -1);
xmlSecAssert2(expr != NULL, -1);
data->expr = xmlStrdup(expr);
if(data->expr == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_STRDUP_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
static int
xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data, xmlNodePtr node) {
xmlNodePtr cur;
xmlNsPtr ns;
int ret;
xmlSecAssert2(data != NULL, -1);
xmlSecAssert2(data->ctx != NULL, -1);
xmlSecAssert2(node != NULL, -1);
/* register namespaces */
for(cur = node; cur != NULL; cur = cur->parent) {
for(ns = cur->nsDef; ns != NULL; ns = ns->next) {
/* check that we have no other namespace with same prefix already */
if((ns->prefix != NULL) && (xmlXPathNsLookup(data->ctx, ns->prefix) == NULL)){
ret = xmlXPathRegisterNs(data->ctx, ns->prefix, ns->href);
if(ret != 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlXPathRegisterNs",
XMLSEC_ERRORS_R_XML_FAILED,
"href=%s;prefix=%s",
xmlSecErrorsSafeString(ns->href),
xmlSecErrorsSafeString(ns->prefix));
return(-1);
}
}
}
}
return(0);
}
static int
xmlSecXPathDataNodeRead(xmlSecXPathDataPtr data, xmlNodePtr node) {
int ret;
xmlSecAssert2(data != NULL, -1);
xmlSecAssert2(data->expr == NULL, -1);
xmlSecAssert2(data->ctx != NULL, -1);
xmlSecAssert2(node != NULL, -1);
ret = xmlSecXPathDataRegisterNamespaces (data, node);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecXPathDataRegisterNamespaces",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
/* read node content and set expr */
data->expr = xmlNodeGetContent(node);
if(data->expr == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
static xmlSecNodeSetPtr
xmlSecXPathDataExecute(xmlSecXPathDataPtr data, xmlDocPtr doc, xmlNodePtr hereNode) {
xmlXPathObjectPtr xpathObj = NULL;
xmlSecNodeSetPtr nodes = NULL;
xmlSecAssert2(data != NULL, NULL);
xmlSecAssert2(data->expr != NULL, NULL);
xmlSecAssert2(data->ctx != NULL, NULL);
xmlSecAssert2(doc != NULL, NULL);
xmlSecAssert2(hereNode != NULL, NULL);
/* do not forget to set the doc */
data->ctx->doc = doc;
/* here function works only on the same document */
if(hereNode->doc == doc) {
xmlXPathRegisterFunc(data->ctx, (xmlChar *)"here", xmlSecXPathHereFunction);
data->ctx->here = hereNode;
data->ctx->xptr = 1;
}
/* execute xpath or xpointer expression */
switch(data->type) {
case xmlSecXPathDataTypeXPath:
case xmlSecXPathDataTypeXPath2:
xpathObj = xmlXPathEvalExpression(data->expr, data->ctx);
if(xpathObj == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlXPathEvalExpression",
XMLSEC_ERRORS_R_XML_FAILED,
"expr=%s",
xmlSecErrorsSafeString(data->expr));
return(NULL);
}
break;
case xmlSecXPathDataTypeXPointer:
xpathObj = xmlXPtrEval(data->expr, data->ctx);
if(xpathObj == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlXPtrEval",
XMLSEC_ERRORS_R_XML_FAILED,
"expr=%s",
xmlSecErrorsSafeString(data->expr));
return(NULL);
}
break;
}
if (xpathObj != NULL) {
nodes = xmlSecNodeSetCreate(doc, xpathObj->nodesetval, data->nodeSetType);
}
if(nodes == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecNodeSetCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"type=%d", data->nodeSetType);
xmlXPathFreeObject(xpathObj);
return(NULL);
}
xpathObj->nodesetval = NULL;
xmlXPathFreeObject(xpathObj);
return(nodes);
}
/**************************************************************************
*
* XPath data list
*
*****************************************************************************/
#define xmlSecXPathDataListId \
xmlSecXPathDataListGetKlass()
static xmlSecPtrListId xmlSecXPathDataListGetKlass (void);
static xmlSecNodeSetPtr xmlSecXPathDataListExecute (xmlSecPtrListPtr dataList,
xmlDocPtr doc,
xmlNodePtr hereNode,
xmlSecNodeSetPtr nodes);
static xmlSecPtrListKlass xmlSecXPathDataListKlass = {
BAD_CAST "xpath-data-list",
NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */
(xmlSecPtrDestroyItemMethod)xmlSecXPathDataDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */
NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
NULL, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
};
static xmlSecPtrListId
xmlSecXPathDataListGetKlass(void) {
return(&xmlSecXPathDataListKlass);
}
static xmlSecNodeSetPtr
xmlSecXPathDataListExecute(xmlSecPtrListPtr dataList, xmlDocPtr doc,
xmlNodePtr hereNode, xmlSecNodeSetPtr nodes) {
xmlSecXPathDataPtr data;
xmlSecNodeSetPtr res, tmp, tmp2;
xmlSecSize pos;
xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), NULL);
xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, NULL);
xmlSecAssert2(doc != NULL, NULL);
xmlSecAssert2(hereNode != NULL, NULL);
res = nodes;
for(pos = 0; pos < xmlSecPtrListGetSize(dataList); ++pos) {
data = (xmlSecXPathDataPtr)xmlSecPtrListGetItem(dataList, pos);
if(data == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecPtrListGetItem",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"pos=%d", pos);
if((res != NULL) && (res != nodes)) {
xmlSecNodeSetDestroy(res);
}
return(NULL);
}
tmp = xmlSecXPathDataExecute(data, doc, hereNode);
if(tmp == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecXPathDataExecute",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
if((res != NULL) && (res != nodes)) {
xmlSecNodeSetDestroy(res);
}
return(NULL);
}
tmp2 = xmlSecNodeSetAdd(res, tmp, data->nodeSetOp);
if(tmp2 == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecNodeSetAdd",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"xmlSecNodeSetIntersection");
if((res != NULL) && (res != nodes)) {
xmlSecNodeSetDestroy(res);
}
xmlSecNodeSetDestroy(tmp);
return(NULL);
}
res = tmp2;
}
return(res);
}
/******************************************************************************
*
* XPath/XPointer transforms
*
* xmlSecXPathDataList is located after xmlSecTransform structure
*
*****************************************************************************/
#define xmlSecXPathTransformSize \
(sizeof(xmlSecTransform) + sizeof(xmlSecPtrList))
#define xmlSecXPathTransformGetDataList(transform) \
((xmlSecTransformCheckSize((transform), xmlSecXPathTransformSize)) ? \
(xmlSecPtrListPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \
(xmlSecPtrListPtr)NULL)
#define xmlSecTransformXPathCheckId(transform) \
(xmlSecTransformCheckId((transform), xmlSecTransformXPathId) || \
xmlSecTransformCheckId((transform), xmlSecTransformXPath2Id) || \
xmlSecTransformCheckId((transform), xmlSecTransformXPointerId))
static int xmlSecTransformXPathInitialize (xmlSecTransformPtr transform);
static void xmlSecTransformXPathFinalize (xmlSecTransformPtr transform);
static int xmlSecTransformXPathExecute (xmlSecTransformPtr transform,
int last,
xmlSecTransformCtxPtr transformCtx);
static int
xmlSecTransformXPathInitialize(xmlSecTransformPtr transform) {
xmlSecPtrListPtr dataList;
int ret;
xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1);
dataList = xmlSecXPathTransformGetDataList(transform);
xmlSecAssert2(dataList != NULL, -1);
ret = xmlSecPtrListInitialize(dataList, xmlSecXPathDataListId);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecPtrListInitialize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
static void
xmlSecTransformXPathFinalize(xmlSecTransformPtr transform) {
xmlSecPtrListPtr dataList;
xmlSecAssert(xmlSecTransformXPathCheckId(transform));
dataList = xmlSecXPathTransformGetDataList(transform);
xmlSecAssert(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId));
xmlSecPtrListFinalize(dataList);
}
static int
xmlSecTransformXPathExecute(xmlSecTransformPtr transform, int last,
xmlSecTransformCtxPtr transformCtx) {
xmlSecPtrListPtr dataList;
xmlDocPtr doc;
xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1);
xmlSecAssert2(transform->hereNode != NULL, -1);
xmlSecAssert2(transform->outNodes == NULL, -1);
xmlSecAssert2(last != 0, -1);
xmlSecAssert2(transformCtx != NULL, -1);
dataList = xmlSecXPathTransformGetDataList(transform);
xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, -1);
doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc;
xmlSecAssert2(doc != NULL, -1);
transform->outNodes = xmlSecXPathDataListExecute(dataList, doc,
transform->hereNode, transform->inNodes);
if(transform->outNodes == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataExecute",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
/******************************************************************************
*
* XPath transform
*
*****************************************************************************/
static int xmlSecTransformXPathNodeRead (xmlSecTransformPtr transform,
xmlNodePtr node,
xmlSecTransformCtxPtr transformCtx);
static xmlSecTransformKlass xmlSecTransformXPathKlass = {
/* klass/object sizes */
sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */
xmlSecXPathTransformSize, /* xmlSecSize objSize */
xmlSecNameXPath, /* const xmlChar* name; */
xmlSecXPathNs, /* const xmlChar* href; */
xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */
xmlSecTransformXPathInitialize, /* xmlSecTransformInitializeMethod initialize; */
xmlSecTransformXPathFinalize, /* xmlSecTransformFinalizeMethod finalize; */
xmlSecTransformXPathNodeRead, /* xmlSecTransformNodeReadMethod readNode; */
NULL, /* xmlSecTransformNodeWriteMethod writeNode; */
NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */
NULL, /* xmlSecTransformSetKeyMethod setKey; */
NULL, /* xmlSecTransformValidateMethod validate; */
xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */
NULL, /* xmlSecTransformPushBinMethod pushBin; */
NULL, /* xmlSecTransformPopBinMethod popBin; */
xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */
xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */
xmlSecTransformXPathExecute, /* xmlSecTransformExecuteMethod execute; */
NULL, /* void* reserved0; */
NULL, /* void* reserved1; */
};
/**
* xmlSecTransformXPathGetKlass:
*
* The XPath transform evaluates given XPath expression and
* intersects the result with the previous nodes set. See
* http://www.w3.org/TR/xmldsig-core/#sec-XPath for more details.
*
* Returns XPath transform id.
*/
EXPORT_C
xmlSecTransformId
xmlSecTransformXPathGetKlass(void) {
return(&xmlSecTransformXPathKlass);
}
static const char xpathPattern[] = "(//. | //@* | //namespace::*)[%s]";
static int
xmlSecTransformXPathNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
xmlSecPtrListPtr dataList;
xmlSecXPathDataPtr data;
xmlNodePtr cur;
xmlChar* tmp;
int ret;
xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPathId), -1);
xmlSecAssert2(node != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
dataList = xmlSecXPathTransformGetDataList(transform);
xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
/* there is only one required node */
cur = xmlSecGetNextElementNode(node->children);
if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPath, xmlSecDSigNs))) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
XMLSEC_ERRORS_R_INVALID_NODE,
"expected=%s",
xmlSecErrorsSafeString(xmlSecNodeXPath));
return(-1);
}
/* read information from the node */
data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath);
if(data == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
ret = xmlSecXPathDataNodeRead(data, cur);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataNodeRead",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(-1);
}
/* append it to the list */
ret = xmlSecPtrListAdd(dataList, data);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecPtrListAdd",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(-1);
}
/* create full XPath expression */
xmlSecAssert2(data->expr != NULL, -1);
tmp = (xmlChar*) xmlMalloc(sizeof(xmlChar) * (xmlStrlen(data->expr) +
strlen(xpathPattern) + 1));
if(tmp == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
NULL,
XMLSEC_ERRORS_R_MALLOC_FAILED,
"size=%d",
xmlStrlen(data->expr) + strlen(xpathPattern) + 1);
return(-1);
}
sprintf((char*)tmp, xpathPattern, (char*)data->expr);
xmlFree(data->expr);
data->expr = tmp;
/* set correct node set type and operation */
data->nodeSetOp = xmlSecNodeSetIntersection;
data->nodeSetType = xmlSecNodeSetNormal;
/* check that we have nothing else */
cur = xmlSecGetNextElementNode(cur->next);
if(cur != NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
XMLSEC_ERRORS_R_UNEXPECTED_NODE,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
/******************************************************************************
*
* XPath2 transform
*
*****************************************************************************/
static int xmlSecTransformXPath2NodeRead (xmlSecTransformPtr transform,
xmlNodePtr node,
xmlSecTransformCtxPtr transformCtx);
static xmlSecTransformKlass xmlSecTransformXPath2Klass = {
/* klass/object sizes */
sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */
xmlSecXPathTransformSize, /* xmlSecSize objSize */
xmlSecNameXPath2, /* const xmlChar* name; */
xmlSecXPath2Ns, /* const xmlChar* href; */
xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */
xmlSecTransformXPathInitialize, /* xmlSecTransformInitializeMethod initialize; */
xmlSecTransformXPathFinalize, /* xmlSecTransformFinalizeMethod finalize; */
xmlSecTransformXPath2NodeRead, /* xmlSecTransformNodeReadMethod readNode; */
NULL, /* xmlSecTransformNodeWriteMethod writeNode; */
NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */
NULL, /* xmlSecTransformSetKeyMethod setKey; */
NULL, /* xmlSecTransformValidateMethod validate; */
xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */
NULL, /* xmlSecTransformPushBinMethod pushBin; */
NULL, /* xmlSecTransformPopBinMethod popBin; */
xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */
xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */
xmlSecTransformXPathExecute, /* xmlSecTransformExecuteMethod execute; */
NULL, /* void* reserved0; */
NULL, /* void* reserved1; */
};
/**
* xmlSecTransformXPath2GetKlass:
*
* The XPath2 transform (http://www.w3.org/TR/xmldsig-filter2/).
*
* Returns XPath2 transform klass.
*/
EXPORT_C
xmlSecTransformId
xmlSecTransformXPath2GetKlass(void) {
return(&xmlSecTransformXPath2Klass);
}
static int
xmlSecTransformXPath2NodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
xmlSecPtrListPtr dataList;
xmlSecXPathDataPtr data;
xmlNodePtr cur;
xmlChar* op;
int ret;
xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPath2Id), -1);
xmlSecAssert2(node != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
dataList = xmlSecXPathTransformGetDataList(transform);
xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
/* There are only xpath nodes */
cur = xmlSecGetNextElementNode(node->children);
while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeXPath2, xmlSecXPath2Ns)) {
/* read information from the node */
data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath2);
if(data == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
ret = xmlSecXPathDataNodeRead(data, cur);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataNodeRead",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(-1);
}
/* append it to the list */
ret = xmlSecPtrListAdd(dataList, data);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecPtrListAdd",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(-1);
}
/* set correct node set type and operation */
data->nodeSetType = xmlSecNodeSetTree;
op = xmlGetProp(cur, xmlSecAttrFilter);
if(op == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
xmlSecErrorsSafeString(xmlSecAttrFilter),
XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
return(-1);
}
if(xmlStrEqual(op, xmlSecXPath2FilterIntersect)) {
data->nodeSetOp = xmlSecNodeSetIntersection;
} else if(xmlStrEqual(op, xmlSecXPath2FilterSubtract)) {
data->nodeSetOp = xmlSecNodeSetSubtraction;
} else if(xmlStrEqual(op, xmlSecXPath2FilterUnion)) {
data->nodeSetOp = xmlSecNodeSetUnion;
} else {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
xmlSecErrorsSafeString(xmlSecAttrFilter),
XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE,
"filter=%s",
xmlSecErrorsSafeString(op));
xmlFree(op);
return(-1);
}
xmlFree(op);
cur = xmlSecGetNextElementNode(cur->next);
}
/* check that we have nothing else */
if(cur != NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
XMLSEC_ERRORS_R_UNEXPECTED_NODE,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
/******************************************************************************
*
* XPointer transform
*
*****************************************************************************/
static int xmlSecTransformXPointerNodeRead (xmlSecTransformPtr transform,
xmlNodePtr node,
xmlSecTransformCtxPtr transformCtx);
static xmlSecTransformKlass xmlSecTransformXPointerKlass = {
/* klass/object sizes */
sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */
xmlSecXPathTransformSize, /* xmlSecSize objSize */
xmlSecNameXPointer, /* const xmlChar* name; */
xmlSecXPointerNs, /* const xmlChar* href; */
xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */
xmlSecTransformXPathInitialize, /* xmlSecTransformInitializeMethod initialize; */
xmlSecTransformXPathFinalize, /* xmlSecTransformFinalizeMethod finalize; */
xmlSecTransformXPointerNodeRead, /* xmlSecTransformNodeReadMethod readNode; */
NULL, /* xmlSecTransformNodeWriteMethod writeNode; */
NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */
NULL, /* xmlSecTransformSetKeyMethod setKey; */
NULL, /* xmlSecTransformValidateMethod validate; */
xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */
NULL, /* xmlSecTransformPushBinMethod pushBin; */
NULL, /* xmlSecTransformPopBinMethod popBin; */
xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */
xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */
xmlSecTransformXPathExecute, /* xmlSecTransformExecuteMethod execute; */
NULL, /* void* reserved0; */
NULL, /* void* reserved1; */
};
/**
* xmlSecTransformXPointerGetKlass:
*
* The XPointer transform klass
* (http://www.ietf.org/internet-drafts/draft-eastlake-xmldsig-uri-02.txt).
*
* Returns XPointer transform klass.
*/
EXPORT_C
xmlSecTransformId
xmlSecTransformXPointerGetKlass(void) {
return(&xmlSecTransformXPointerKlass);
}
/**
* xmlSecTransformXPointerSetExpr:
* @transform: the pointer to XPointer transform.
* @expr: the XPointer expression.
* @nodeSetType: the type of evaluated XPointer expression.
* @hereNode: the pointer to "here" node.
*
* Sets the XPointer expression for an XPointer @transform.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformXPointerSetExpr(xmlSecTransformPtr transform, const xmlChar* expr,
xmlSecNodeSetType nodeSetType, xmlNodePtr hereNode) {
xmlSecPtrListPtr dataList;
xmlSecXPathDataPtr data;
int ret;
xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1);
xmlSecAssert2(transform->hereNode == NULL, -1);
xmlSecAssert2(expr != NULL, -1);
xmlSecAssert2(hereNode != NULL, -1);
transform->hereNode = hereNode;
dataList = xmlSecXPathTransformGetDataList(transform);
xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer);
if(data == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
ret = xmlSecXPathDataRegisterNamespaces(data, hereNode);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataRegisterNamespaces",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(-1);
}
ret = xmlSecXPathDataSetExpr(data, expr);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataSetExpr",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(-1);
}
/* append it to the list */
ret = xmlSecPtrListAdd(dataList, data);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecPtrListAdd",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(-1);
}
/* set correct node set type and operation */
data->nodeSetOp = xmlSecNodeSetIntersection;
data->nodeSetType = nodeSetType;
return(0);
}
static int
xmlSecTransformXPointerNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
xmlSecPtrListPtr dataList;
xmlSecXPathDataPtr data;
xmlNodePtr cur;
int ret;
xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1);
xmlSecAssert2(node != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
dataList = xmlSecXPathTransformGetDataList(transform);
xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
/* there is only one required node */
cur = xmlSecGetNextElementNode(node->children);
if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPointer, xmlSecXPointerNs))) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
XMLSEC_ERRORS_R_INVALID_NODE,
"expected=%s",
xmlSecErrorsSafeString(xmlSecNodeXPath));
return(-1);
}
/* read information from the node */
data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer);
if(data == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
ret = xmlSecXPathDataNodeRead(data, cur);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecXPathDataNodeRead",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(-1);
}
/* append it to the list */
ret = xmlSecPtrListAdd(dataList, data);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecPtrListAdd",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecXPathDataDestroy(data);
return(-1);
}
/* set correct node set type and operation */
data->nodeSetOp = xmlSecNodeSetIntersection;
data->nodeSetType = xmlSecNodeSetTree;
/* check that we have nothing else */
cur = xmlSecGetNextElementNode(cur->next);
if(cur != NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
XMLSEC_ERRORS_R_UNEXPECTED_NODE,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
/******************************************************************************
*
* Visa3DHack transform
*
*****************************************************************************/
#define xmlSecVisa3DHackTransformSize \
(sizeof(xmlSecTransform) + sizeof(xmlChar*))
#define xmlSecVisa3DHackTransformGetIDPtr(transform) \
((xmlSecTransformCheckSize((transform), xmlSecVisa3DHackTransformSize)) ? \
(xmlChar**)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \
(xmlChar**)NULL)
#define xmlSecTransformVisa3DHackCheckId(transform) \
(xmlSecTransformCheckId((transform), xmlSecTransformVisa3DHackId))
static int xmlSecTransformVisa3DHackInitialize (xmlSecTransformPtr transform);
static void xmlSecTransformVisa3DHackFinalize (xmlSecTransformPtr transform);
static int xmlSecTransformVisa3DHackExecute (xmlSecTransformPtr transform,
int last,
xmlSecTransformCtxPtr transformCtx);
static xmlSecTransformKlass xmlSecTransformVisa3DHackKlass = {
/* klass/object sizes */
sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */
xmlSecVisa3DHackTransformSize, /* xmlSecSize objSize */
BAD_CAST "Visa3DHackTransform", /* const xmlChar* name; */
NULL, /* const xmlChar* href; */
xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */
xmlSecTransformVisa3DHackInitialize, /* xmlSecTransformInitializeMethod initialize; */
xmlSecTransformVisa3DHackFinalize, /* xmlSecTransformFinalizeMethod finalize; */
NULL, /* xmlSecTransformNodeReadMethod readNode; */
NULL, /* xmlSecTransformNodeWriteMethod writeNode; */
NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */
NULL, /* xmlSecTransformSetKeyMethod setKey; */
NULL, /* xmlSecTransformValidateMethod validate; */
xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */
NULL, /* xmlSecTransformPushBinMethod pushBin; */
NULL, /* xmlSecTransformPopBinMethod popBin; */
xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */
xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */
xmlSecTransformVisa3DHackExecute, /* xmlSecTransformExecuteMethod execute; */
NULL, /* void* reserved0; */
NULL, /* void* reserved1; */
};
/**
* xmlSecTransformVisa3DHackGetKlass:
*
* The Visa3DHack transform klass. The only reason why we need this
* is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows
* something like "#12345" in the URI attribute.
*
* Returns Visa3DHack transform klass.
*/
EXPORT_C
xmlSecTransformId
xmlSecTransformVisa3DHackGetKlass(void) {
return(&xmlSecTransformVisa3DHackKlass);
}
/**
* xmlSecTransformVisa3DHackSetID:
* @transform: the pointer to Visa3DHack transform.
* @id: the ID value.
*
* Sets the ID value for an Visa3DHack @transform.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformVisa3DHackSetID(xmlSecTransformPtr transform, const xmlChar* id) {
xmlChar** idPtr;
xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformVisa3DHackId), -1);
xmlSecAssert2(id != NULL, -1);
idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform);
xmlSecAssert2(idPtr != NULL, -1);
xmlSecAssert2((*idPtr) == NULL, -1);
(*idPtr) = xmlStrdup(id);
if((*idPtr) == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlStrdup",
XMLSEC_ERRORS_R_MALLOC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
static int
xmlSecTransformVisa3DHackInitialize(xmlSecTransformPtr transform) {
xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1);
return(0);
}
static void
xmlSecTransformVisa3DHackFinalize(xmlSecTransformPtr transform) {
xmlChar** idPtr;
xmlSecAssert(xmlSecTransformVisa3DHackCheckId(transform));
idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform);
xmlSecAssert(idPtr != NULL);
if((*idPtr) != NULL) {
xmlFree((*idPtr));
}
(*idPtr) = NULL;
}
static int
xmlSecTransformVisa3DHackExecute(xmlSecTransformPtr transform, int last,
xmlSecTransformCtxPtr transformCtx) {
xmlChar** idPtr;
xmlDocPtr doc;
xmlAttrPtr attr;
xmlNodeSetPtr nodeSet;
xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1);
xmlSecAssert2(transform->outNodes == NULL, -1);
xmlSecAssert2(last != 0, -1);
xmlSecAssert2(transformCtx != NULL, -1);
idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform);
xmlSecAssert2(idPtr != NULL, -1);
xmlSecAssert2((*idPtr) != NULL, -1);
doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc;
xmlSecAssert2(doc != NULL, -1);
attr = xmlGetID(doc, (*idPtr));
if((attr == NULL) || (attr->parent == NULL)) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlGetID",
XMLSEC_ERRORS_R_XML_FAILED,
"id=\"%s\"",
xmlSecErrorsSafeString((*idPtr)));
return(-1);
}
nodeSet = xmlXPathNodeSetCreate(attr->parent);
if(nodeSet == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlXPathNodeSetCreate",
XMLSEC_ERRORS_R_XML_FAILED,
"id=\"%s\"",
xmlSecErrorsSafeString((*idPtr)));
return(-1);
}
transform->outNodes = xmlSecNodeSetCreate(doc, nodeSet, xmlSecNodeSetTreeWithoutComments);
if(transform->outNodes == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecNodeSetCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlXPathFreeNodeSet(nodeSet);
return(-1);
}
return(0);
}