From c0a2ea2b84e6dc954125ea6f2f57e9ddc29a3d5a Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Sun, 14 Feb 2016 22:12:57 +0100 Subject: [PATCH] Implement OOXML Relationships Transform Algorithm Reference: ISO/IEC 29500-2:2012(E), section 13.2.4.24 --- include/xmlsec/strings.h | 12 + include/xmlsec/transforms.h | 9 + src/strings.c | 12 + src/transforms.c | 10 + src/xpath.c | 671 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 714 insertions(+) diff --git a/include/xmlsec/strings.h b/include/xmlsec/strings.h index 5e3f6a1..5a92014 100644 --- a/include/xmlsec/strings.h +++ b/include/xmlsec/strings.h @@ -590,6 +590,18 @@ XMLSEC_EXPORT_VAR const xmlChar xmlSecNodeXPointer[]; /************************************************************************* * + * RelationshipTransform strings + * + ************************************************************************/ +XMLSEC_EXPORT_VAR const xmlChar xmlSecNameRelationship[]; +XMLSEC_EXPORT_VAR const xmlChar xmlSecHrefRelationship[]; +XMLSEC_EXPORT_VAR const xmlChar xmlSecNodeRelationship[]; +XMLSEC_EXPORT_VAR const xmlChar xmlSecNodeRelationshipReference[]; +XMLSEC_EXPORT_VAR const xmlChar xmlSecRelationshipsNs[]; +XMLSEC_EXPORT_VAR const xmlChar xmlSecRelationshipReferenceNs[]; + +/************************************************************************* + * * Xslt strings * ************************************************************************/ diff --git a/include/xmlsec/transforms.h b/include/xmlsec/transforms.h index f0c70c9..0d876f1 100644 --- a/include/xmlsec/transforms.h +++ b/include/xmlsec/transforms.h @@ -949,6 +949,15 @@ XMLSEC_EXPORT int xmlSecTransformXPointerSetExpr (xmlSecT const xmlChar* expr, xmlSecNodeSetType nodeSetType, xmlNodePtr hereNode); +/** + * xmlSecTransformRelationshipId: + * + * The Relationship transform klass. + */ +#define xmlSecTransformRelationshipId \ + xmlSecTransformRelationshipGetKlass() +XMLSEC_EXPORT xmlSecTransformId xmlSecTransformRelationshipGetKlass (void); + #ifndef XMLSEC_NO_XSLT #include diff --git a/src/strings.c b/src/strings.c index f746f4d..1e8516f 100644 --- a/src/strings.c +++ b/src/strings.c @@ -581,6 +581,18 @@ const xmlChar xmlSecNodeXPointer[] = "XPointer"; /************************************************************************* * + * Relationship strings + * + ************************************************************************/ +const xmlChar xmlSecNameRelationship[] = "relationship"; +const xmlChar xmlSecHrefRelationship[] = "http://schemas.openxmlformats.org/package/2006/RelationshipTransform"; +const xmlChar xmlSecNodeRelationship[] = "Relationship"; +const xmlChar xmlSecNodeRelationshipReference[] = "RelationshipReference"; +const xmlChar xmlSecRelationshipsNs[] = "http://schemas.openxmlformats.org/package/2006/relationships"; +const xmlChar xmlSecRelationshipReferenceNs[] = "http://schemas.openxmlformats.org/package/2006/digital-signature"; + +/************************************************************************* + * * Xslt strings * ************************************************************************/ diff --git a/src/transforms.c b/src/transforms.c index 8a2ded2..8a32629 100644 --- a/src/transforms.c +++ b/src/transforms.c @@ -281,6 +281,16 @@ xmlSecTransformIdsRegisterDefault(void) { return(-1); } + if(xmlSecTransformIdsRegister(xmlSecTransformRelationshipId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformRelationshipId))); + return(-1); + } + #ifndef XMLSEC_NO_XSLT if(xmlSecTransformIdsRegister(xmlSecTransformXsltId) < 0) { xmlSecError(XMLSEC_ERRORS_HERE, diff --git a/src/xpath.c b/src/xpath.c index e67631e..748c9da 100644 --- a/src/xpath.c +++ b/src/xpath.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -1163,3 +1164,673 @@ xmlSecTransformVisa3DHackExecute(xmlSecTransformPtr transform, int last, +/****************************************************************************** + * + * Relationship transform + * + *****************************************************************************/ +typedef struct _xmlSecRelationshipCtx xmlSecRelationshipCtx, + *xmlSecRelationshipCtxPtr; +struct _xmlSecRelationshipCtx { + xmlSecPtrListPtr sourceIdList; +}; +#define xmlSecRelationshipSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecRelationshipCtx)) +#define xmlSecRelationshipGetCtx(transform) \ + ((xmlSecRelationshipCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecRelationshipInitialize (xmlSecTransformPtr transform); +static void xmlSecRelationshipFinalize (xmlSecTransformPtr transform); +static int xmlSecTransformRelationshipPopBin (xmlSecTransformPtr transform, + xmlSecByte* data, + xmlSecSize maxDataSize, + xmlSecSize* dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecTransformRelationshipPushXml(xmlSecTransformPtr transform, + xmlSecNodeSetPtr nodes, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecRelationshipReadNode (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecRelationshipKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecRelationshipSize, /* xmlSecSize objSize */ + + xmlSecNameRelationship, /* const xmlChar* name; */ + xmlSecHrefRelationship, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ + + xmlSecRelationshipInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecRelationshipFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecRelationshipReadNode, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformRelationshipPopBin, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformRelationshipPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +xmlSecTransformId +xmlSecTransformRelationshipGetKlass(void) { + return(&xmlSecRelationshipKlass); +} + +static int +xmlSecRelationshipInitialize(xmlSecTransformPtr transform) { + xmlSecRelationshipCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformRelationshipId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecRelationshipSize), -1); + + ctx = xmlSecRelationshipGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecRelationshipCtx)); + + ctx->sourceIdList = xmlSecPtrListCreate(xmlSecStringListId); + if(ctx->sourceIdList == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static void +xmlSecRelationshipFinalize(xmlSecTransformPtr transform) { + xmlSecRelationshipCtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformRelationshipId)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecRelationshipSize)); + + ctx = xmlSecRelationshipGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->sourceIdList != NULL) { + xmlSecPtrListDestroy(ctx->sourceIdList); + } + + memset(ctx, 0, sizeof(xmlSecRelationshipCtx)); +} + +static int +xmlSecRelationshipReadNode(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecRelationshipCtxPtr ctx; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformRelationshipId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecRelationshipSize), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + ctx = xmlSecRelationshipGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + cur = node->children; + while(cur != NULL) { + if(xmlSecCheckNodeName(cur, xmlSecNodeRelationshipReference, xmlSecRelationshipReferenceNs)) { + xmlChar* sourceId; + xmlChar* tmp; + + sourceId = xmlGetProp(cur, "SourceId"); + if(sourceId == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlGetProp", + xmlSecErrorsSafeString("SourceId"), + XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + + tmp = xmlStrdup(sourceId); + if(tmp == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlStrdup", + XMLSEC_ERRORS_R_STRDUP_FAILED, + "len=%d", xmlStrlen(sourceId)); + return(-1); + } + + ret = xmlSecPtrListAdd(ctx->sourceIdList, tmp); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(tmp); + return(-1); + } + } + + cur = cur->next; + } + + return(0); +} + +/* Sorts Relationship elements by Id value in lexicographical order. */ +static int +xmlSecTransformRelationshipCompare(xmlNodePtr node1, xmlNodePtr node2) { + xmlChar* id1; + xmlChar* id2; + + if(node1 == node2) { + return(0); + } + if(node1 == NULL) { + return(-1); + } + if(node2 == NULL) { + return(1); + } + + id1 = xmlGetProp(node1, "Id"); + id2 = xmlGetProp(node2, "Id"); + + if(id1 == NULL) { + return(-1); + } + + if(id2 == NULL) { + return(1); + } + + return(xmlStrcmp(id1, id2)); +} + +static int +xmlSecTransformRelationshipProcessElementNode(xmlSecTransformPtr transform, xmlOutputBufferPtr buf, xmlNodePtr cur); + +static int +xmlSecTransformRelationshipProcessNode(xmlSecTransformPtr transform, xmlOutputBufferPtr buf, xmlNodePtr cur) { + int ret; + + if(xmlSecCheckNodeName(cur, xmlSecNodeRelationship, xmlSecRelationshipsNs)) { + xmlChar* id = xmlGetProp(cur, "Id"); + if(id == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlGetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=Id"); + return(-1); + } + + int i; + int found = -1; + xmlSecRelationshipCtxPtr ctx; + + ctx = xmlSecRelationshipGetCtx(transform); + for(i = 0; i < xmlSecPtrListGetSize(ctx->sourceIdList); ++i) { + if(xmlStrcmp(xmlSecPtrListGetItem(ctx->sourceIdList, i), id) == 0) { + found = 1; + break; + } + } + + if(found < 0) { + return(0); + } + } + + ret = xmlSecTransformRelationshipProcessElementNode(transform, buf, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformRelationshipProcessElementNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecTransformRelationshipProcessNodeList(xmlSecTransformPtr transform, xmlOutputBufferPtr buf, xmlNodePtr cur) { + xmlListPtr list; + int ret; + + list = xmlListCreate(NULL, (xmlListDataCompare)xmlSecTransformRelationshipCompare); + if(list == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlListCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + for(; cur; cur = cur->next) { + if(xmlStrcmp(cur->name, xmlSecNodeRelationship) == 0) { + if(xmlListInsert(list, cur) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlListInsert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + ret = xmlSecTransformRelationshipProcessNode(transform, buf, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformRelationshipProcessNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlListDelete(list); + return(-1); + } + } + } + + if(!xmlListEmpty(list)) { + int size; + int i; + + xmlListSort(list); + size = xmlListSize(list); + for(i = 0; i < size; ++i) { + xmlLinkPtr link = xmlListFront(list); + xmlNodePtr node = (xmlNodePtr)xmlLinkGetData(link); + + ret = xmlSecTransformRelationshipProcessNode(transform, buf, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformRelationshipProcessNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlListDelete(list); + return(-1); + } + + xmlListPopFront(list); + } + } + + xmlListDelete(list); + return(0); +} + +static int +xmlSecTransformRelationshipProcessElementNode(xmlSecTransformPtr transform, xmlOutputBufferPtr buf, xmlNodePtr cur) { + xmlAttrPtr attr; + int foundTargetMode = 0; + + if(xmlOutputBufferWriteString(buf, "<") < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(xmlOutputBufferWriteString(buf, (const char *)cur->name) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(cur->nsDef != NULL) { + if(xmlOutputBufferWriteString(buf, " xmlns=\"") < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(cur->nsDef->href != NULL) { + if(xmlOutputBufferWriteString(buf, cur->nsDef->href) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + if(xmlOutputBufferWriteString(buf, "\"") < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + for(attr = cur->properties; attr; attr = attr->next) { + if(xmlOutputBufferWriteString(buf, " ") < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(xmlOutputBufferWriteString(buf, (const char *)attr->name) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(xmlStrcmp(attr->name, "TargetMode") == 0) { + foundTargetMode = 1; + } + if(xmlOutputBufferWriteString(buf, "=\"") < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(xmlOutputBufferWriteString(buf, (const char *)xmlGetProp(cur, attr->name)) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(xmlOutputBufferWriteString(buf, "\"") < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(xmlStrcmp(cur->name, xmlSecNodeRelationship) == 0 && !foundTargetMode) { + if(xmlOutputBufferWriteString(buf, " TargetMode=\"Internal\"") < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(xmlOutputBufferWriteString(buf, ">") < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(cur->children != NULL) { + int ret = xmlSecTransformRelationshipProcessNodeList(transform, buf, cur->children); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformRelationshipProcessNodeList", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(xmlOutputBufferWriteString(buf, "name) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(xmlOutputBufferWriteString(buf, ">") < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferWriteString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecTransformRelationshipExecute(xmlSecTransformPtr transform, xmlOutputBufferPtr buf, xmlDocPtr doc) { + if(doc->children != NULL) { + int ret = xmlSecTransformRelationshipProcessNodeList(transform, buf, doc->children); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformRelationshipProcessNodeList", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +static int +xmlSecTransformRelationshipPushXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr nodes, xmlSecTransformCtxPtr transformCtx) +{ + xmlOutputBufferPtr buf; + xmlSecRelationshipCtxPtr ctx; + int ret; + + xmlSecAssert2(nodes != NULL, -1); + xmlSecAssert2(nodes->doc != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecRelationshipGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* check/update current transform status */ + switch(transform->status) { + case xmlSecTransformStatusNone: + transform->status = xmlSecTransformStatusWorking; + break; + case xmlSecTransformStatusWorking: + case xmlSecTransformStatusFinished: + return(0); + default: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + xmlSecAssert2(transform->status == xmlSecTransformStatusWorking, -1); + + /* prepare output buffer: next transform or ourselves */ + if(transform->next != NULL) { + buf = xmlSecTransformCreateOutputBuffer(transform->next, transformCtx); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + buf = xmlSecBufferCreateOutputBuffer(&(transform->outBuf)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + ret = xmlSecTransformRelationshipExecute(transform, buf, nodes->doc); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlC14NExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlOutputBufferClose(buf); + return(-1); + } + + ret = xmlOutputBufferClose(buf); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferClose", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + transform->status = xmlSecTransformStatusFinished; + return(0); +} + +static int +xmlSecTransformRelationshipPopBin(xmlSecTransformPtr transform, xmlSecByte* data, xmlSecSize maxDataSize, xmlSecSize* dataSize, xmlSecTransformCtxPtr transformCtx) { + xmlSecBufferPtr out; + int ret; + + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(dataSize != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + out = &(transform->outBuf); + if(transform->status == xmlSecTransformStatusNone) { + xmlOutputBufferPtr buf; + + xmlSecAssert2(transform->inNodes == NULL, -1); + + if(transform->prev == NULL) { + (*dataSize) = 0; + transform->status = xmlSecTransformStatusFinished; + return(0); + } + + /* get xml data from previous transform */ + ret = xmlSecTransformPopXml(transform->prev, &(transform->inNodes), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformPopXml", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* dump everything to internal buffer */ + buf = xmlSecBufferCreateOutputBuffer(out); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlC14NExecute(transform->inNodes->doc, (xmlC14NIsVisibleCallback)xmlSecNodeSetContains, transform->inNodes, XML_C14N_1_0, NULL, 0, buf); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformC14NExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlOutputBufferClose(buf); + return(-1); + } + + ret = xmlOutputBufferClose(buf); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferClose", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + xmlSecSize outSize; + + /* return chunk after chunk */ + outSize = xmlSecBufferGetSize(out); + if(outSize > maxDataSize) { + outSize = maxDataSize; + } + if(outSize > XMLSEC_TRANSFORM_BINARY_CHUNK) { + outSize = XMLSEC_TRANSFORM_BINARY_CHUNK; + } + if(outSize > 0) { + xmlSecAssert2(xmlSecBufferGetData(&(transform->outBuf)), -1); + + memcpy(data, xmlSecBufferGetData(&(transform->outBuf)), outSize); + ret = xmlSecBufferRemoveHead(&(transform->outBuf), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + } else if(xmlSecBufferGetSize(out) == 0) { + transform->status = xmlSecTransformStatusFinished; + } + (*dataSize) = outSize; + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no output */ + xmlSecAssert2(xmlSecBufferGetSize(out) == 0, -1); + (*dataSize) = 0; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + + return(0); +} -- 2.6.6