/**
* XML Security Library (http://www.aleksey.com/xmlsec).
*
* The Transforms Element (http://www.w3.org/TR/xmldsig-core/#sec-Transforms)
*
* The optional Transforms element contains an ordered list of Transform
* elements; these describe how the signer obtained the data object that
* was digested.
*
* Schema Definition:
*
* <element name="Transforms" type="ds:TransformsType"/>
* <complexType name="TransformsType">
* <sequence>
* <element ref="ds:Transform" maxOccurs="unbounded"/>
* </sequence>
* </complexType>
*
* <element name="Transform" type="ds:TransformType"/>
* <complexType name="TransformType" mixed="true">
* <choice minOccurs="0" maxOccurs="unbounded">
* <any namespace="##other" processContents="lax"/>
* <!-- (1,1) elements from (0,unbounded) namespaces -->
* <element name="XPath" type="string"/>
* </choice>
* <attribute name="Algorithm" type="anyURI" use="required"/>
* </complexType>
*
* DTD:
*
* <!ELEMENT Transforms (Transform+)>
* <!ELEMENT Transform (#PCDATA|XPath %Transform.ANY;)* >
* <!ATTLIST Transform Algorithm CDATA #REQUIRED >
* <!ELEMENT XPath (#PCDATA) >
*
* 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 <stdio.h>
#include <string.h>
#include <libxml2_tree.h>
#include <libxml2_xpath.h>
#include <libxml2_xpointer.h>
#include <libxml2_globals.h>
#include "xmlsec_xmlsec.h"
#include "xmlsec_buffer.h"
#include "xmlsec_xmltree.h"
#include "xmlsec_keysdata.h"
#include "xmlsec_keys.h"
#include "xmlsec_keyinfo.h"
#include "xmlsec_transforms.h"
#include "xmlsec_base64.h"
#include "xmlsec_io.h"
#include "xmlsec_membuf.h"
#include "xmlsec_parser.h"
#include "xmlsec_errors.h"
/**************************************************************************
*
* Global xmlSecTransformIds list functions
*
*************************************************************************/
static xmlSecPtrList xmlSecAllTransformIds;
/**
* xmlSecTransformIdsGet:
*
* Gets global registered transform klasses list.
*
* Returns the pointer to list of all registered transform klasses.
*/
EXPORT_C
xmlSecPtrListPtr
xmlSecTransformIdsGet(void) {
return(&xmlSecAllTransformIds);
}
/**
* xmlSecTransformIdsInit:
*
* Initializes the transform klasses. This function is called from the
* #xmlSecInit function and the application should not call it directly.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformIdsInit(void) {
int ret;
ret = xmlSecPtrListInitialize(xmlSecTransformIdsGet(), xmlSecTransformIdListId);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecPtrListPtrInitialize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"xmlSecTransformIdListId");
return(-1);
}
ret = xmlSecTransformIdsRegisterDefault();
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegisterDefault",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
/**
* xmlSecTransformIdsShutdown:
*
* Shuts down the keys data klasses. This function is called from the
* #xmlSecShutdown function and the application should not call it directly.
*/
EXPORT_C
void
xmlSecTransformIdsShutdown(void) {
xmlSecPtrListFinalize(xmlSecTransformIdsGet());
}
/**
* xmlSecTransformIdsRegister:
* @id: the transform klass.
*
* Registers @id in the global list of transform klasses.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformIdsRegister(xmlSecTransformId id) {
int ret;
xmlSecAssert2(id != xmlSecTransformIdUnknown, -1);
ret = xmlSecPtrListAdd(xmlSecTransformIdsGet(), (xmlSecPtr)id);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecPtrListAdd",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id)));
return(-1);
}
return(0);
}
/**
* xmlSecTransformIdsRegisterDefault:
*
* Registers default (implemented by XML Security Library)
* transform klasses: XPath transform, Base64 transform, ...
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformIdsRegisterDefault(void) {
if(xmlSecTransformIdsRegister(xmlSecTransformBase64Id) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformBase64Id)));
return(-1);
}
if(xmlSecTransformIdsRegister(xmlSecTransformEnvelopedId) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformEnvelopedId)));
return(-1);
}
/* c14n methods */
if(xmlSecTransformIdsRegister(xmlSecTransformInclC14NId) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInclC14NId)));
return(-1);
}
if(xmlSecTransformIdsRegister(xmlSecTransformInclC14NWithCommentsId) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInclC14NWithCommentsId)));
return(-1);
}
if(xmlSecTransformIdsRegister(xmlSecTransformExclC14NId) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformExclC14NId)));
return(-1);
}
if(xmlSecTransformIdsRegister(xmlSecTransformExclC14NWithCommentsId) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformExclC14NWithCommentsId)));
return(-1);
}
if(xmlSecTransformIdsRegister(xmlSecTransformXPathId) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXPathId)));
return(-1);
}
if(xmlSecTransformIdsRegister(xmlSecTransformXPath2Id) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXPath2Id)));
return(-1);
}
if(xmlSecTransformIdsRegister(xmlSecTransformXPointerId) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXPointerId)));
return(-1);
}
#ifndef XMLSEC_NO_XSLT
if(xmlSecTransformIdsRegister(xmlSecTransformXsltId) < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsRegister",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXsltId)));
return(-1);
}
#endif /* XMLSEC_NO_XSLT */
return(0);
}
/**************************************************************************
*
* utils
*
*************************************************************************/
/**
* xmlSecTransformUriTypeCheck:
* @type: the expected URI type.
* @uri: the uri for checking.
*
* Checks if @uri matches expected type @type.
*
* Returns 1 if @uri matches @type, 0 if not or a negative value
* if an error occurs.
*/
EXPORT_C
int
xmlSecTransformUriTypeCheck(xmlSecTransformUriType type, const xmlChar* uri) {
xmlSecTransformUriType uriType = 0;
if((uri == NULL) || (xmlStrlen(uri) == 0)) {
uriType = xmlSecTransformUriTypeEmpty;
} else if(uri[0] == '#') {
uriType = xmlSecTransformUriTypeSameDocument;
} else if(xmlStrncmp(uri, BAD_CAST "file://", 7) == 0) {
uriType = xmlSecTransformUriTypeLocal;
} else {
uriType = xmlSecTransformUriTypeRemote;
}
return(((uriType & type) != 0) ? 1 : 0);
}
/**************************************************************************
*
* xmlSecTransformCtx
*
*************************************************************************/
/**
* xmlSecTransformCtxCreate:
*
* Creates transforms chain processing context.
* The caller is responsible for destroying returend object by calling
* #xmlSecTransformCtxDestroy function.
*
* Returns pointer to newly allocated context object or NULL if an error
* occurs.
*/
EXPORT_C
xmlSecTransformCtxPtr
xmlSecTransformCtxCreate(void) {
xmlSecTransformCtxPtr ctx;
int ret;
/* Allocate a new xmlSecTransform and fill the fields. */
ctx = (xmlSecTransformCtxPtr)xmlMalloc(sizeof(xmlSecTransformCtx));
if(ctx == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_MALLOC_FAILED,
"size=%d", sizeof(xmlSecTransformCtx));
return(NULL);
}
ret = xmlSecTransformCtxInitialize(ctx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxInitialize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecTransformCtxDestroy(ctx);
return(NULL);
}
return(ctx);
}
/**
* xmlSecTransformCtxDestroy:
* @ctx: the pointer to transforms chain processing context.
*
* Destroy context object created with #xmlSecTransformCtxCreate function.
*/
EXPORT_C
void
xmlSecTransformCtxDestroy(xmlSecTransformCtxPtr ctx) {
xmlSecAssert(ctx != NULL);
xmlSecTransformCtxFinalize(ctx);
xmlFree(ctx);
}
/**
* xmlSecTransformCtxInitialize:
* @ctx: the pointer to transforms chain processing context.
*
* Initializes transforms chain processing context.
* The caller is responsible for cleaing up returend object by calling
* #xmlSecTransformCtxFinalize function.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformCtxInitialize(xmlSecTransformCtxPtr ctx) {
int ret;
xmlSecAssert2(ctx != NULL, -1);
memset(ctx, 0, sizeof(xmlSecTransformCtx));
ret = xmlSecPtrListInitialize(&(ctx->enabledTransforms), xmlSecTransformIdListId);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecPtrListInitialize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
ctx->enabledUris = xmlSecTransformUriTypeAny;
return(0);
}
/**
* xmlSecTransformCtxFinalize:
* @ctx: the pointer to transforms chain processing context.
*
* Cleans up @ctx object initialized with #xmlSecTransformCtxInitialize function.
*/
EXPORT_C
void
xmlSecTransformCtxFinalize(xmlSecTransformCtxPtr ctx) {
xmlSecAssert(ctx != NULL);
xmlSecTransformCtxReset(ctx);
xmlSecPtrListFinalize(&(ctx->enabledTransforms));
memset(ctx, 0, sizeof(xmlSecTransformCtx));
}
/**
* xmlSecTransformCtxReset:
* @ctx: the pointer to transforms chain processing context.
*
* Resets transfroms context for new processing.
*/
EXPORT_C
void
xmlSecTransformCtxReset(xmlSecTransformCtxPtr ctx) {
xmlSecTransformPtr transform, tmp;
xmlSecAssert(ctx != NULL);
ctx->result = NULL;
ctx->status = xmlSecTransformStatusNone;
/* destroy uri */
if(ctx->uri != NULL) {
xmlFree(ctx->uri);
ctx->uri = NULL;
}
if(ctx->xptrExpr != NULL) {
xmlFree(ctx->xptrExpr);
ctx->xptrExpr = NULL;
}
/* destroy transforms chain */
for(transform = ctx->first; transform != NULL; transform = tmp) {
tmp = transform->next;
xmlSecTransformDestroy(transform);
}
ctx->first = ctx->last = NULL;
}
/**
* xmlSecTransformCtxCopyUserPref:
* @dst: the pointer to destination transforms chain processing context.
* @src: the pointer to source transforms chain processing context.
*
* Copies user settings from @src context to @dst.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxCopyUserPref(xmlSecTransformCtxPtr dst, xmlSecTransformCtxPtr src) {
int ret;
xmlSecAssert2(dst != NULL, -1);
xmlSecAssert2(src != NULL, -1);
dst->userData = src->userData;
dst->flags = src->flags;
dst->flags2 = src->flags2;
dst->enabledUris = src->enabledUris;
dst->preExecCallback = src->preExecCallback;
ret = xmlSecPtrListCopy(&(dst->enabledTransforms), &(src->enabledTransforms));
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecPtrListCopy",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
/**
* xmlSecTransformCtxAppend:
* @ctx: the pointer to transforms chain processing context.
* @transform: the pointer to new transform.
*
* Connects the @transform to the end of the chain of transforms in the @ctx
* (see #xmlSecTransformConnect function for details).
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxAppend(xmlSecTransformCtxPtr ctx, xmlSecTransformPtr transform) {
int ret;
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
if(ctx->last != NULL) {
ret = xmlSecTransformConnect(ctx->last, transform, ctx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformConnect",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)));
return(-1);
}
} else {
xmlSecAssert2(ctx->first == NULL, -1);
ctx->first = transform;
}
ctx->last = transform;
return(0);
}
/**
* xmlSecTransformCtxPrepend:
* @ctx: the pointer to transforms chain processing context.
* @transform: the pointer to new transform.
*
* Connects the @transform to the beggining of the chain of transforms in the @ctx
* (see #xmlSecTransformConnect function for details).
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxPrepend(xmlSecTransformCtxPtr ctx, xmlSecTransformPtr transform) {
int ret;
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
if(ctx->first != NULL) {
ret = xmlSecTransformConnect(transform, ctx->first, ctx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformConnect",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)));
return(-1);
}
} else {
xmlSecAssert2(ctx->last == NULL, -1);
ctx->last = transform;
}
ctx->first = transform;
return(0);
}
/**
* xmlSecTransformCtxCreateAndAppend:
* @ctx: the pointer to transforms chain processing context.
* @id: the new transform klass.
*
* Creaeates new transform and connects it to the end of the chain of
* transforms in the @ctx (see #xmlSecTransformConnect function for details).
*
* Returns pointer to newly created transform or NULL if an error occurs.
*/
EXPORT_C
xmlSecTransformPtr
xmlSecTransformCtxCreateAndAppend(xmlSecTransformCtxPtr ctx, xmlSecTransformId id) {
xmlSecTransformPtr transform;
int ret;
xmlSecAssert2(ctx != NULL, NULL);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, NULL);
xmlSecAssert2(id != xmlSecTransformIdUnknown, NULL);
transform = xmlSecTransformCreate(id);
if(!xmlSecTransformIsValid(transform)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id)));
return(NULL);
}
ret = xmlSecTransformCtxAppend(ctx, transform);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxAppend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)));
xmlSecTransformDestroy(transform);
return(NULL);
}
return(transform);
}
/**
* xmlSecTransformCtxCreateAndPrepend:
* @ctx: the pointer to transforms chain processing context.
* @id: the new transform klass.
*
* Creaeates new transform and connects it to the end of the chain of
* transforms in the @ctx (see #xmlSecTransformConnect function for details).
*
* Returns pointer to newly created transform or NULL if an error occurs.
*/
EXPORT_C
xmlSecTransformPtr
xmlSecTransformCtxCreateAndPrepend(xmlSecTransformCtxPtr ctx, xmlSecTransformId id) {
xmlSecTransformPtr transform;
int ret;
xmlSecAssert2(ctx != NULL, NULL);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, NULL);
xmlSecAssert2(id != xmlSecTransformIdUnknown, NULL);
transform = xmlSecTransformCreate(id);
if(!xmlSecTransformIsValid(transform)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id)));
return(NULL);
}
ret = xmlSecTransformCtxPrepend(ctx, transform);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxPrepend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)));
xmlSecTransformDestroy(transform);
return(NULL);
}
return(transform);
}
/**
* xmlSecTransformCtxNodeRead:
* @ctx: the pointer to transforms chain processing context.
* @node: the pointer to transform's node.
* @usage: the transform's usage (signature, encryption, etc.).
*
* Reads the transform from the @node and appends it to the current chain
* of transforms in @ctx.
*
* Returns pointer to newly created transform or NULL if an error occurs.
*/
EXPORT_C
xmlSecTransformPtr
xmlSecTransformCtxNodeRead(xmlSecTransformCtxPtr ctx, xmlNodePtr node,
xmlSecTransformUsage usage) {
xmlSecTransformPtr transform;
int ret;
xmlSecAssert2(ctx != NULL, NULL);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, NULL);
xmlSecAssert2(node != NULL, NULL);
transform = xmlSecTransformNodeRead(node, usage, ctx);
if(transform == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformNodeRead",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecNodeGetName(node)));
return(NULL);
}
ret = xmlSecTransformCtxAppend(ctx, transform);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxAppend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)));
xmlSecTransformDestroy(transform);
return(NULL);
}
return(transform);
}
/**
* xmlSecTransformCtxNodesListRead:
* @ctx: the pointer to transforms chain processing context.
* @node: the pointer to <dsig:Transform/> nodes parent node.
* @usage: the transform's usage (signature, encryption, etc.).
*
* Reads transforms from the <dsig:Transform/> children of the @node and
* appends them to the current transforms chain in @ctx object.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxNodesListRead(xmlSecTransformCtxPtr ctx, xmlNodePtr node, xmlSecTransformUsage usage) {
xmlSecTransformPtr transform;
xmlNodePtr cur;
int ret;
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
xmlSecAssert2(node != NULL, -1);
cur = xmlSecGetNextElementNode(node->children);
while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeTransform, xmlSecDSigNs)) {
transform = xmlSecTransformNodeRead(cur, usage, ctx);
if(transform == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformNodeRead",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
return(-1);
}
ret = xmlSecTransformCtxAppend(ctx, transform);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxAppend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
xmlSecTransformDestroy(transform);
return(-1);
}
cur = xmlSecGetNextElementNode(cur->next);
}
if(cur != NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
XMLSEC_ERRORS_R_UNEXPECTED_NODE,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(0);
}
/**
* xmlSecTransformCtxSetUri:
* @ctx: the pointer to transforms chain processing context.
* @uri: the URI.
* @hereNode: the pointer to "here" node required by some
* XML transforms (may be NULL).
*
* Parses uri and adds xpointer transforms if required.
*
* The following examples demonstrate what the URI attribute identifies and
* how it is dereferenced
* (http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel):
*
* - URI="http://example.com/bar.xml"
* identifies the octets that represent the external resource
* 'http://example.com/bar.xml', that is probably an XML document given
* its file extension.
*
* - URI="http://example.com/bar.xml#chapter1"
* identifies the element with ID attribute value 'chapter1' of the
* external XML resource 'http://example.com/bar.xml', provided as an
* octet stream. Again, for the sake of interoperability, the element
* identified as 'chapter1' should be obtained using an XPath transform
* rather than a URI fragment (barename XPointer resolution in external
* resources is not REQUIRED in this specification).
*
* - URI=""
* identifies the node-set (minus any comment nodes) of the XML resource
* containing the signature
*
* - URI="#chapter1"
* identifies a node-set containing the element with ID attribute value
* 'chapter1' of the XML resource containing the signature. XML Signature
* (and its applications) modify this node-set to include the element plus
* all descendents including namespaces and attributes -- but not comments.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxSetUri(xmlSecTransformCtxPtr ctx, const xmlChar* uri, xmlNodePtr hereNode) {
xmlSecNodeSetType nodeSetType = xmlSecNodeSetTree;
const xmlChar* xptr;
xmlChar* buf = NULL;
int useVisa3DHack = 0;
int ret;
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->uri == NULL, -1);
xmlSecAssert2(ctx->xptrExpr == NULL, -1);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
xmlSecAssert2(hereNode != NULL, -1);
/* check uri */
if(xmlSecTransformUriTypeCheck(ctx->enabledUris, uri) != 1) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_INVALID_URI_TYPE,
"uri=%s",
xmlSecErrorsSafeString(uri));
return(-1);
}
/* is it an empty uri? */
if((uri == NULL) || (xmlStrlen(uri) == 0)) {
return(0);
}
/* do we have barename or full xpointer? */
xptr = xmlStrchr(uri, '#');
if(xptr == NULL){
ctx->uri = xmlStrdup(uri);
if(ctx->uri == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_STRDUP_FAILED,
"size=%d", xmlStrlen(uri));
return(-1);
}
/* we are done */
return(0);
} else if(xmlStrcmp(uri, BAD_CAST "#xpointer(/)") == 0) {
ctx->xptrExpr = xmlStrdup(uri);
if(ctx->xptrExpr == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_STRDUP_FAILED,
"size=%d", xmlStrlen(uri));
return(-1);
}
/* we are done */
return(0);
}
ctx->uri = xmlStrndup(uri, xptr - uri);
if(ctx->uri == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_STRDUP_FAILED,
"size=%d", xptr - uri);
return(-1);
}
ctx->xptrExpr = xmlStrdup(xptr);
if(ctx->xptrExpr == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_STRDUP_FAILED,
"size=%d", xmlStrlen(xptr));
return(-1);
}
/* do we have barename or full xpointer? */
xmlSecAssert2(xptr != NULL, -1);
if((xmlStrncmp(xptr, BAD_CAST "#xpointer(", 10) == 0) || (xmlStrncmp(xptr, BAD_CAST "#xmlns(", 7) == 0)) {
++xptr;
nodeSetType = xmlSecNodeSetTree;
} else if((ctx->flags & XMLSEC_TRANSFORMCTX_FLAGS_USE_VISA3D_HACK) != 0) {
++xptr;
nodeSetType = xmlSecNodeSetTreeWithoutComments;
useVisa3DHack = 1;
} else {
static const char tmpl[] = "xpointer(id(\'%s\'))";
xmlSecSize size;
/* we need to add "xpointer(id('..')) because otherwise we have
* problems with numeric ("111" and so on) and other "strange" ids */
size = xmlStrlen(BAD_CAST tmpl) + xmlStrlen(xptr) + 2;
buf = (xmlChar*)xmlMalloc(size * sizeof(xmlChar));
if(buf == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_MALLOC_FAILED,
"size=%d", size);
return(-1);
}
sprintf((char*)buf, tmpl, xptr + 1);
xptr = buf;
nodeSetType = xmlSecNodeSetTreeWithoutComments;
}
if(useVisa3DHack == 0) {
xmlSecTransformPtr transform;
/* we need to create XPonter transform to execute expr */
transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformXPointerId);
if(!xmlSecTransformIsValid(transform)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxCreateAndPrepend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXPointerId)));
xmlFree( buf ); //buf == xptr
return(-1);
}
ret = xmlSecTransformXPointerSetExpr(transform, xptr, nodeSetType, hereNode);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformXPointerSetExpr",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)));
if( buf != NULL) {
xmlFree( buf ); //buf == xptr
}
return(-1);
}
} else {
/* Visa3D protocol doesn't follow XML/XPointer/XMLDSig specs
* and allows something like "#12345" in the URI attribute.
*/
xmlSecTransformPtr transform;
transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformVisa3DHackId);
if(!xmlSecTransformIsValid(transform)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxCreateAndPrepend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformVisa3DHackId)));
return(-1);
}
ret = xmlSecTransformVisa3DHackSetID(transform, xptr);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformVisa3DHackSetID",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"name=%s",
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)));
if(buf != NULL) {
xmlFree(buf);
}
return(-1);
}
}
if(buf != NULL) {
xmlFree(buf);
}
return(0);
}
/**
* xmlSecTransformCtxPrepare:
* @ctx: the pointer to transforms chain processing context.
* @inputDataType: the expected input type.
*
* Prepares the transform context for processing data of @inputDataType.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxPrepare(xmlSecTransformCtxPtr ctx, xmlSecTransformDataType inputDataType) {
xmlSecTransformDataType firstType;
xmlSecTransformPtr transform;
int ret;
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->result == NULL, -1);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
/* add binary buffer to store result */
transform = xmlSecTransformCtxCreateAndAppend(ctx, xmlSecTransformMemBufId);
if(!xmlSecTransformIsValid(transform)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformMemBufId)));
return(-1);
}
ctx->result = xmlSecTransformMemBufGetBuffer(transform);
if(ctx->result == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformMemBufGetBuffer",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformMemBufId)));
return(-1);
}
firstType = xmlSecTransformGetDataType(ctx->first, xmlSecTransformModePush, ctx);
if(((firstType & xmlSecTransformDataTypeBin) == 0) &&
((inputDataType & xmlSecTransformDataTypeBin) != 0)) {
/* need to add parser transform */
transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformXmlParserId);
if(transform == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxCreateAndPrepend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXmlParserId)));
return(-1);
}
} else if(((firstType & xmlSecTransformDataTypeXml) == 0) &&
((inputDataType & xmlSecTransformDataTypeXml) != 0)) {
/* need to add c14n transform */
transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformInclC14NId);
if(transform == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxCreateAndPrepend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInclC14NId)));
return(-1);
}
}
/* finally let application a chance to verify that it's ok to execte
* this transforms chain */
if(ctx->preExecCallback != NULL) {
ret = (ctx->preExecCallback)(ctx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"ctx->preExecCallback",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
}
ctx->status = xmlSecTransformStatusWorking;
return(0);
}
/**
* xmlSecTransformCtxBinaryExecute:
* @ctx: the pointer to transforms chain processing context.
* @data: the input binary data buffer.
* @dataSize: the input data size.
*
* Processes binary data using transforms chain in the @ctx.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxBinaryExecute(xmlSecTransformCtxPtr ctx,
const xmlSecByte* data, xmlSecSize dataSize) {
int ret;
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->result == NULL, -1);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
xmlSecAssert2(data != NULL, -1);
xmlSecAssert2(dataSize > 0, -1);
/* we should not have uri stored in ctx */
xmlSecAssert2(ctx->uri == NULL, -1);
ret = xmlSecTransformCtxPrepare(ctx, xmlSecTransformDataTypeBin);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxPrepare",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"type=bin");
return(-1);
}
ret = xmlSecTransformPushBin(ctx->first, data, dataSize, 1, ctx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxPushBin",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"dataSize=%d", dataSize);
return(-1);
}
ctx->status = xmlSecTransformStatusFinished;
return(0);
}
/**
* xmlSecTransformCtxUriExecute:
* @ctx: the pointer to transforms chain processing context.
* @uri: the URI.
*
* Process binary data from the URI using transforms chain in @ctx.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxUriExecute(xmlSecTransformCtxPtr ctx, const xmlChar* uri) {
xmlSecTransformPtr uriTransform;
int ret;
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
xmlSecAssert2(uri != NULL, -1);
/* we should not execute transform for a different uri */
xmlSecAssert2((ctx->uri == NULL) || (uri == ctx->uri) || xmlStrEqual(uri, ctx->uri), -1);
uriTransform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformInputURIId);
if(uriTransform == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxCreateAndPrepend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInputURIId)));
return(-1);
}
ret = xmlSecTransformInputURIOpen(uriTransform, uri);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformInputURIOpen",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"uri=%s",
xmlSecErrorsSafeString(uri));
return(-1);
}
/* we do not need to do something special for this transform */
ret = xmlSecTransformCtxPrepare(ctx, xmlSecTransformDataTypeUnknown);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxPrepare",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"type=bin");
return(-1);
}
/* Now we have a choice: we either can push from first transform or pop
* from last. Our C14N transforms prefers push, so push data!
*/
ret = xmlSecTransformPump(uriTransform, uriTransform->next, ctx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformPump",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"uri=%s",
xmlSecErrorsSafeString(uri));
return(-1);
}
ctx->status = xmlSecTransformStatusFinished;
return(0);
}
/**
* xmlSecTransformCtxXmlExecute:
* @ctx: the pointer to transforms chain processing context.
* @nodes: the input node set.
*
* Process @nodes using transforms in the transforms chain in @ctx.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxXmlExecute(xmlSecTransformCtxPtr ctx, xmlSecNodeSetPtr nodes) {
int ret;
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->result == NULL, -1);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
xmlSecAssert2(nodes != NULL, -1);
xmlSecAssert2((ctx->uri == NULL) || (xmlStrlen(ctx->uri) == 0), -1);
ret = xmlSecTransformCtxPrepare(ctx, xmlSecTransformDataTypeXml);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxPrepare",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"type=xml");
return(-1);
}
/* it's better to do push than pop because all XML transform
* just don't care and c14n likes push more than pop */
ret = xmlSecTransformPushXml(ctx->first, nodes, ctx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformPushXml",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformGetName(ctx->first)));
return(-1);
}
ctx->status = xmlSecTransformStatusFinished;
return(0);
}
/**
* xmlSecTransformCtxExecute:
* @ctx: the pointer to transforms chain processing context.
* @doc: the pointer to input document.
*
* Executes transforms chain in @ctx.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformCtxExecute(xmlSecTransformCtxPtr ctx, xmlDocPtr doc) {
int ret;
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->result == NULL, -1);
xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1);
xmlSecAssert2(doc != NULL, -1);
if((ctx->uri == NULL) || (xmlStrlen(ctx->uri) == 0)) {
xmlSecNodeSetPtr nodes;
if((ctx->xptrExpr != NULL) && (xmlStrlen(ctx->xptrExpr) > 0)){
/* our xpointer transform takes care of providing correct nodes set */
nodes = xmlSecNodeSetCreate(doc, NULL, xmlSecNodeSetNormal);
if(nodes == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecNodeSetCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
} else {
/* we do not want to have comments for empty URI */
nodes = xmlSecNodeSetGetChildren(doc, NULL, 0, 0);
if(nodes == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecNodeSetGetChildren",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
}
ret = xmlSecTransformCtxXmlExecute(ctx, nodes);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxXmlExecute",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecNodeSetDestroy(nodes);
return(-1);
}
xmlSecNodeSetDestroy(nodes);
} else {
ret = xmlSecTransformCtxUriExecute(ctx, ctx->uri);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCtxUriExecute",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
}
return(0);
}
/**
* xmlSecTransformCtxDebugDump:
* @ctx: the pointer to transforms chain processing context.
* @output: the pointer to output FILE.
*
* Prints transforms context debug information to @output.
*/
EXPORT_C
void
xmlSecTransformCtxDebugDump(xmlSecTransformCtxPtr ctx, FILE* output) {
xmlSecTransformPtr transform;
xmlSecAssert(ctx != NULL);
xmlSecAssert(output != NULL);
fprintf(output, "== TRANSFORMS CTX (status=%d)\n", ctx->status);
fprintf(output, "== flags: 0x%08x\n", ctx->flags);
fprintf(output, "== flags2: 0x%08x\n", ctx->flags2);
if(xmlSecPtrListGetSize(&(ctx->enabledTransforms)) > 0) {
fprintf(output, "== enabled transforms: ");
xmlSecTransformIdListDebugDump(&(ctx->enabledTransforms), output);
} else {
fprintf(output, "== enabled transforms: all\n");
}
fprintf(output, "=== uri: %s\n",
(ctx->uri != NULL) ? ctx->uri : BAD_CAST "NULL");
fprintf(output, "=== uri xpointer expr: %s\n",
(ctx->xptrExpr != NULL) ? ctx->xptrExpr : BAD_CAST "NULL");
for(transform = ctx->first; transform != NULL; transform = transform->next) {
xmlSecTransformDebugDump(transform, output);
}
}
/**
* xmlSecTransformCtxDebugXmlDump:
* @ctx: the pointer to transforms chain processing context.
* @output: the pointer to output FILE.
*
* Prints transforms context debug information to @output in XML format.
*/
EXPORT_C
void
xmlSecTransformCtxDebugXmlDump(xmlSecTransformCtxPtr ctx, FILE* output) {
xmlSecTransformPtr transform;
xmlSecAssert(ctx != NULL);
xmlSecAssert(output != NULL);
fprintf(output, "<TransformCtx status=\"%d\">\n", ctx->status);
fprintf(output, "<Flags>%08x</Flags>\n", ctx->flags);
fprintf(output, "<Flags2>%08x</Flags2>\n", ctx->flags2);
if(xmlSecPtrListGetSize(&(ctx->enabledTransforms)) > 0) {
fprintf(output, "<EnabledTransforms>\n");
xmlSecTransformIdListDebugXmlDump(&(ctx->enabledTransforms), output);
fprintf(output, "</EnabledTransforms>\n");
} else {
fprintf(output, "<EnabledTransforms>all</EnabledTransforms>\n");
}
fprintf(output, "<Uri>%s</Uri>\n",
(ctx->uri != NULL) ? ctx->uri : BAD_CAST "NULL");
fprintf(output, "<UriXPointer>%s</UriXPointer>\n",
(ctx->xptrExpr != NULL) ? ctx->xptrExpr : BAD_CAST "NULL");
for(transform = ctx->first; transform != NULL; transform = transform->next) {
xmlSecTransformDebugXmlDump(transform, output);
}
fprintf(output, "</TransformCtx>\n");
}
/**************************************************************************
*
* xmlSecTransform
*
*************************************************************************/
/**
* xmlSecTransformCreate:
* @id: the transform id to create.
*
* Creates new transform of the @id klass. The caller is responsible for
* destroying returned tansform using #xmlSecTransformDestroy function.
*
* Returns pointer to newly created transform or NULL if an error occurs.
*/
EXPORT_C
xmlSecTransformPtr
xmlSecTransformCreate(xmlSecTransformId id) {
xmlSecTransformPtr transform;
int ret;
xmlSecAssert2(id != NULL, NULL);
xmlSecAssert2(id->klassSize >= sizeof(xmlSecTransformKlass), NULL);
xmlSecAssert2(id->objSize >= sizeof(xmlSecTransform), NULL);
xmlSecAssert2(id->name != NULL, NULL);
/* Allocate a new xmlSecTransform and fill the fields. */
transform = (xmlSecTransformPtr)xmlMalloc(id->objSize);
if(transform == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_MALLOC_FAILED,
"size=%d", id->objSize);
return(NULL);
}
memset(transform, 0, id->objSize);
transform->id = id;
if(id->initialize != NULL) {
ret = (id->initialize)(transform);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"id->initialize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecTransformDestroy(transform);
return(NULL);
}
}
ret = xmlSecBufferInitialize(&(transform->inBuf), 0);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecBufferInitialize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"size=%d", 0);
xmlSecTransformDestroy(transform);
return(NULL);
}
ret = xmlSecBufferInitialize(&(transform->outBuf), 0);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecBufferInitialize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"size=%d", 0);
xmlSecTransformDestroy(transform);
return(NULL);
}
return(transform);
}
/**
* xmlSecTransformDestroy:
* @transform: the pointer to transform.
*
* Destroys transform created with #xmlSecTransformCreate function.
*/
EXPORT_C
void
xmlSecTransformDestroy(xmlSecTransformPtr transform) {
xmlSecAssert(xmlSecTransformIsValid(transform));
xmlSecAssert(transform->id->objSize > 0);
/* first need to remove ourselves from chain */
xmlSecTransformRemove(transform);
xmlSecBufferFinalize(&(transform->inBuf));
xmlSecBufferFinalize(&(transform->outBuf));
/* we never destroy input nodes, output nodes
* are destroyed if and only if they are different
* from input nodes
*/
if((transform->outNodes != NULL) && (transform->outNodes != transform->inNodes)) {
xmlSecNodeSetDestroy(transform->outNodes);
}
if(transform->id->finalize != NULL) {
(transform->id->finalize)(transform);
}
memset(transform, 0, transform->id->objSize);
xmlFree(transform);
}
/**
* xmlSecTransformNodeRead:
* @node: the pointer to the transform's node.
* @usage: the transform usage (signature, encryption, ...).
* @transformCtx: the transform's chaing processing context.
*
* Reads transform from the @node as follows:
*
* 1) reads "Algorithm" attribute;
*
* 2) checks the lists of known and allowed transforms;
*
* 3) calls transform's create method;
*
* 4) calls transform's read transform node method.
*
* Returns pointer to newly created transform or NULL if an error occurs.
*/
EXPORT_C
xmlSecTransformPtr
xmlSecTransformNodeRead(xmlNodePtr node, xmlSecTransformUsage usage, xmlSecTransformCtxPtr transformCtx) {
xmlSecTransformPtr transform;
xmlSecTransformId id;
xmlChar *href;
int ret;
xmlSecAssert2(node != NULL, NULL);
xmlSecAssert2(transformCtx != NULL, NULL);
href = xmlGetProp(node, xmlSecAttrAlgorithm);
if(href == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecAttrAlgorithm),
XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeGetName(node)));
return(NULL);
}
id = xmlSecTransformIdListFindByHref(xmlSecTransformIdsGet(), href, usage);
if(id == xmlSecTransformIdUnknown) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformIdsListFindByHref",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"href=%s",
xmlSecErrorsSafeString(href));
xmlFree(href);
return(NULL);
}
/* check with enabled transforms list */
if((xmlSecPtrListGetSize(&(transformCtx->enabledTransforms)) > 0) &&
(xmlSecTransformIdListFind(&(transformCtx->enabledTransforms), id) != 1)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id)),
XMLSEC_ERRORS_R_TRANSFORM_DISABLED,
"href=%s",
xmlSecErrorsSafeString(href));
xmlFree(href);
return(NULL);
}
transform = xmlSecTransformCreate(id);
if(!xmlSecTransformIsValid(transform)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecTransformCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id)));
xmlFree(href);
return(NULL);
}
if(transform->id->readNode != NULL) {
ret = transform->id->readNode(transform, node, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"id->readNode",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)));
xmlSecTransformDestroy(transform);
xmlFree(href);
return(NULL);
}
}
/* finally remember the transform node */
transform->hereNode = node;
xmlFree(href);
return(transform);
}
/**
* xmlSecTransformPump:
* @left: the source pumping transform.
* @right: the destination pumping transform.
* @transformCtx: the transform's chaing processing context.
*
* Pops data from @left transform and pushes to @right transform until
* no more data is available.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformPump(xmlSecTransformPtr left, xmlSecTransformPtr right, xmlSecTransformCtxPtr transformCtx) {
xmlSecTransformDataType leftType;
xmlSecTransformDataType rightType;
int ret;
xmlSecAssert2(xmlSecTransformIsValid(left), -1);
xmlSecAssert2(xmlSecTransformIsValid(right), -1);
xmlSecAssert2(transformCtx != NULL, -1);
leftType = xmlSecTransformGetDataType(left, xmlSecTransformModePop, transformCtx);
rightType = xmlSecTransformGetDataType(right, xmlSecTransformModePush, transformCtx);
if(((leftType & xmlSecTransformDataTypeXml) != 0) &&
((rightType & xmlSecTransformDataTypeXml) != 0)) {
xmlSecNodeSetPtr nodes = NULL;
ret = xmlSecTransformPopXml(left, &nodes, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(left)),
"xmlSecTransformPopXml",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
ret = xmlSecTransformPushXml(right, nodes, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(right)),
"xmlSecTransformPushXml",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
} else if(((leftType & xmlSecTransformDataTypeBin) != 0) &&
((rightType & xmlSecTransformDataTypeBin) != 0)) {
xmlSecByte buf[XMLSEC_TRANSFORM_BINARY_CHUNK];
xmlSecSize bufSize;
int final;
do {
ret = xmlSecTransformPopBin(left, buf, sizeof(buf), &bufSize, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(left)),
"xmlSecTransformPopBin",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
final = (bufSize == 0) ? 1 : 0;
ret = xmlSecTransformPushBin(right, buf, bufSize, final, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(right)),
"xmlSecTransformPushBin",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
} while(final == 0);
} else {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(left)),
xmlSecErrorsSafeString(xmlSecTransformGetName(right)),
XMLSEC_ERRORS_R_INVALID_TRANSFORM,
"transforms input/output data formats do not match");
}
return(0);
}
/**
* xmlSecTransformSetKey:
* @transform: the pointer to transform.
* @key: the pointer to key.
*
* Sets the transform's key.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(key != NULL, -1);
if(transform->id->setKey != NULL) {
return((transform->id->setKey)(transform, key));
}
return(0);
}
/**
* xmlSecTransformSetKeyReq:
* @transform: the pointer to transform.
* @keyReq: the pointer to keys requirements object.
*
* Sets the key requirements for @transform in the @keyReq.
*
* Returns 0 on success or a negative value otherwise.
*/
EXPORT_C
int
xmlSecTransformSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) {
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(keyReq != NULL, -1);
keyReq->keyId = xmlSecKeyDataIdUnknown;
keyReq->keyType = xmlSecKeyDataTypeUnknown;
keyReq->keyUsage = xmlSecKeyUsageAny;
keyReq->keyBitsSize = 0;
if(transform->id->setKeyReq != NULL) {
return((transform->id->setKeyReq)(transform, keyReq));
}
return(0);
}
/**
* xmlSecTransformVerify:
* @transform: the pointer to transform.
* @data: the binary data for verification.
* @dataSize: the data size.
* @transformCtx: the transform's chaing processing context.
*
* Verifies the data with transform's processing results
* (for digest, HMAC and signature transforms). The verification
* result is stored in the #status member of #xmlSecTransform object.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformVerify(xmlSecTransformPtr transform, const xmlSecByte* data,
xmlSecSize dataSize, xmlSecTransformCtxPtr transformCtx) {
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transform->id->verify != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
return((transform->id->verify)(transform, data, dataSize, transformCtx));
}
/**
* xmlSecTransformVerifyNodeContent:
* @transform: the pointer to transform.
* @node: the pointer to node.
* @transformCtx: the transform's chaing processing context.
*
* Gets the @node content, base64 decodes it and calls #xmlSecTransformVerify
* function to verify binary results.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformVerifyNodeContent(xmlSecTransformPtr transform, xmlNodePtr node,
xmlSecTransformCtxPtr transformCtx) {
xmlSecBuffer buffer;
int ret;
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(node != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
ret = xmlSecBufferInitialize(&buffer, 0);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecBufferInitialize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
ret = xmlSecBufferBase64NodeContentRead(&buffer, node);
if((ret < 0) || (xmlSecBufferGetData(&buffer) == NULL)) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecBufferBase64NodeContentRead",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecBufferFinalize(&buffer);
return(-1);
}
ret = xmlSecTransformVerify(transform, xmlSecBufferGetData(&buffer),
xmlSecBufferGetSize(&buffer), transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecTransformVerify",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecBufferFinalize(&buffer);
return(-1);
}
xmlSecBufferFinalize(&buffer);
return(0);
}
/**
* xmlSecTransformGetDataType:
* @transform: the pointer to transform.
* @mode: the data mode (push or pop).
* @transformCtx: the transform's chaing processing context.
*
* Gets transform input (@mode is "push") or output (@mode is "pop") data
* type (binary or XML).
*
* Returns the transform's data type for the @mode operation.
*/
EXPORT_C
xmlSecTransformDataType
xmlSecTransformGetDataType(xmlSecTransformPtr transform, xmlSecTransformMode mode,
xmlSecTransformCtxPtr transformCtx) {
xmlSecAssert2(xmlSecTransformIsValid(transform), xmlSecTransformDataTypeUnknown);
xmlSecAssert2(transform->id->getDataType != NULL, xmlSecTransformDataTypeUnknown);
return((transform->id->getDataType)(transform, mode, transformCtx));
}
/**
* xmlSecTransformPushBin:
* @transform: the pointer to transform object.
* @data: the input binary data,
* @dataSize: the input data size.
* @final: the flag: if set to 1 then it's the last
* data chunk.
* @transformCtx: the pointer to transform context object.
*
* Process binary @data and pushes results to next transform.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformPushBin(xmlSecTransformPtr transform, const xmlSecByte* data,
xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) {
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transform->id->pushBin != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
return((transform->id->pushBin)(transform, data, dataSize, final, transformCtx));
}
/**
* xmlSecTransformPopBin:
* @transform: the pointer to transform object.
* @data: the buffer to store result data.
* @maxDataSize: the size of the buffer #data.
* @dataSize: the pointer to returned data size.
* @transformCtx: the pointer to transform context object.
*
* Pops data from previous transform in the chain, processes data and
* returns result in the @data buffer. The size of returned data is
* placed in the @dataSize.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformPopBin(xmlSecTransformPtr transform, xmlSecByte* data,
xmlSecSize maxDataSize, xmlSecSize* dataSize, xmlSecTransformCtxPtr transformCtx) {
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transform->id->popBin != NULL, -1);
xmlSecAssert2(data != NULL, -1);
xmlSecAssert2(dataSize != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
return((transform->id->popBin)(transform, data, maxDataSize, dataSize, transformCtx));
}
/**
* xmlSecTransformPushXml:
* @transform: the pointer to transform object.
* @nodes: the input nodes.
* @transformCtx: the pointer to transform context object.
*
* Processes @nodes and pushes result to the next transform in the chain.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformPushXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr nodes,
xmlSecTransformCtxPtr transformCtx) {
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transform->id->pushXml != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
return((transform->id->pushXml)(transform, nodes, transformCtx));
}
/**
* xmlSecTransformPopXml:
* @transform: the pointer to transform object.
* @nodes: the pointer to store popinter to result nodes.
* @transformCtx: the pointer to transform context object.
*
* Pops data from previous transform in the chain, processes the data and
* returns result in @nodes.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformPopXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr* nodes,
xmlSecTransformCtxPtr transformCtx) {
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transform->id->popXml != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
return((transform->id->popXml)(transform, nodes, transformCtx));
}
/**
* xmlSecTransformExecute:
* @transform: the pointer to transform.
* @last: the flag: if set to 1 then it's the last data chunk.
* @transformCtx: the transform's chaing processing context.
*
* Executes transform (used by default popBin/pushBin/popXml/pushXml methods).
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transform->id->execute != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
return((transform->id->execute)(transform, last, transformCtx));
}
/**
* xmlSecTransformDebugDump:
* @transform: the pointer to transform.
* @output: the pointer to output FILE.
*
* Prints transform's debug information to @output.
*/
EXPORT_C
void
xmlSecTransformDebugDump(xmlSecTransformPtr transform, FILE* output) {
xmlSecAssert(xmlSecTransformIsValid(transform));
xmlSecAssert(output != NULL);
fprintf(output, "=== Transform: %s (href=%s)\n",
xmlSecErrorsSafeString(transform->id->name),
xmlSecErrorsSafeString(transform->id->href));
}
/**
* xmlSecTransformDebugXmlDump:
* @transform: the pointer to transform.
* @output: the pointer to output FILE.
*
* Prints transform's debug information to @output in XML format.
*/
EXPORT_C
void
xmlSecTransformDebugXmlDump(xmlSecTransformPtr transform, FILE* output) {
xmlSecAssert(xmlSecTransformIsValid(transform));
xmlSecAssert(output != NULL);
fprintf(output, "<Transform name=\"%s\" href=\"%s\" />\n",
xmlSecErrorsSafeString(transform->id->name),
xmlSecErrorsSafeString(transform->id->href));
}
/************************************************************************
*
* Operations on transforms chain
*
************************************************************************/
/**
* xmlSecTransformConnect:
* @left: the pointer to left (prev) transform.
* @right: the pointer to right (next) transform.
* @transformCtx: the transform's chaing processing context.
*
* If the data object is a node-set and the next transform requires octets,
* the signature application MUST attempt to convert the node-set to an octet
* stream using Canonical XML [XML-C14N].
*
* The story is different if the right transform is base64 decode
* (http://www.w3.org/TR/xmldsig-core/#sec-Base-64):
*
* This transform requires an octet stream for input. If an XPath node-set
* (or sufficiently functional alternative) is given as input, then it is
* converted to an octet stream by performing operations logically equivalent
* to 1) applying an XPath transform with expression self::text(), then 2)
* taking the string-value of the node-set. Thus, if an XML element is
* identified by a barename XPointer in the Reference URI, and its content
* consists solely of base64 encoded character data, then this transform
* automatically strips away the start and end tags of the identified element
* and any of its descendant elements as well as any descendant comments and
* processing instructions. The output of this transform is an octet stream.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformConnect(xmlSecTransformPtr left, xmlSecTransformPtr right,
xmlSecTransformCtxPtr transformCtx) {
xmlSecTransformDataType leftType;
xmlSecTransformDataType rightType;
xmlSecTransformId middleId;
xmlSecTransformPtr middle;
xmlSecAssert2(xmlSecTransformIsValid(left), -1);
xmlSecAssert2(xmlSecTransformIsValid(right), -1);
xmlSecAssert2(transformCtx != NULL, -1);
leftType = xmlSecTransformGetDataType(left, xmlSecTransformModePop, transformCtx);
rightType = xmlSecTransformGetDataType(right, xmlSecTransformModePush, transformCtx);
if((((leftType & xmlSecTransformDataTypeBin) != 0) &&
((rightType & xmlSecTransformDataTypeBin) != 0)) ||
(((leftType & xmlSecTransformDataTypeXml) != 0) &&
((rightType & xmlSecTransformDataTypeXml) != 0))) {
left->next = right;
right->prev = left;
return(0);
}
if(((leftType & xmlSecTransformDataTypeBin) != 0) &&
((rightType & xmlSecTransformDataTypeXml) != 0)) {
/* need to insert parser */
middleId = xmlSecTransformXmlParserId;
} else if(((leftType & xmlSecTransformDataTypeXml) != 0) &&
((rightType & xmlSecTransformDataTypeBin) != 0)) {
/* need to insert c14n or special pre-base64 transform */
if(xmlSecTransformCheckId(right, xmlSecTransformBase64Id)) {
middleId = xmlSecTransformRemoveXmlTagsC14NId;
} else {
middleId = xmlSecTransformInclC14NId;
}
} else {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(left)),
xmlSecErrorsSafeString(xmlSecTransformGetName(right)),
XMLSEC_ERRORS_R_INVALID_TRANSFORM,
"leftType=%d;rightType=%d",
leftType, rightType);
return(-1);
}
/* insert transform */
middle = xmlSecTransformCreate(middleId);
if(middle == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(left)),
"xmlSecTransformCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"transform=%s",
xmlSecErrorsSafeString(xmlSecTransformKlassGetName(middleId)));
return(-1);
}
left->next = middle;
middle->prev = left;
middle->next = right;
right->prev = middle;
return(0);
}
/**
* xmlSecTransformRemove:
* @transform: the pointer to #xmlSecTransform structure.
*
* Removes @transform from the chain.
*/
EXPORT_C
void
xmlSecTransformRemove(xmlSecTransformPtr transform) {
xmlSecAssert(xmlSecTransformIsValid(transform));
if(transform->next != NULL) {
transform->next->prev = transform->prev;
}
if(transform->prev != NULL) {
transform->prev->next = transform->next;
}
transform->next = transform->prev = NULL;
}
/************************************************************************
*
* Default callbacks, most of the transforms can use them
*
************************************************************************/
/**
* xmlSecTransformDefaultGetDataType:
* @transform: the pointer to transform.
* @mode: the data mode (push or pop).
* @transformCtx: the transform's chaing processing context.
*
* Gets transform input (@mode is "push") or output (@mode is "pop") data
* type (binary or XML) by analyzing available pushBin/popBin/pushXml/popXml
* methods.
*
* Returns the transform's data type for the @mode operation.
*/
EXPORT_C
xmlSecTransformDataType
xmlSecTransformDefaultGetDataType(xmlSecTransformPtr transform, xmlSecTransformMode mode,
xmlSecTransformCtxPtr transformCtx) {
xmlSecTransformDataType type = xmlSecTransformDataTypeUnknown;
xmlSecAssert2(xmlSecTransformIsValid(transform), xmlSecTransformDataTypeUnknown);
xmlSecAssert2(transformCtx != NULL, xmlSecTransformDataTypeUnknown);
/* we'll try to guess the data type based on the handlers we have */
switch(mode) {
case xmlSecTransformModePush:
if(transform->id->pushBin != NULL) {
type |= xmlSecTransformDataTypeBin;
}
if(transform->id->pushXml != NULL) {
type |= xmlSecTransformDataTypeXml;
}
break;
case xmlSecTransformModePop:
if(transform->id->popBin != NULL) {
type |= xmlSecTransformDataTypeBin;
}
if(transform->id->popXml != NULL) {
type |= xmlSecTransformDataTypeXml;
}
break;
default:
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
NULL,
XMLSEC_ERRORS_R_INVALID_DATA,
"mode=%d", mode);
return(xmlSecTransformDataTypeUnknown);
}
return(type);
}
/**
* xmlSecTransformDefaultPushBin:
* @transform: the pointer to transform object.
* @data: the input binary data,
* @dataSize: the input data size.
* @final: the flag: if set to 1 then it's the last
* data chunk.
* @transformCtx: the pointer to transform context object.
*
* Process binary @data by calling transform's execute method and pushes
* results to next transform.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformDefaultPushBin(xmlSecTransformPtr transform, const xmlSecByte* data,
xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) {
xmlSecSize inSize = 0;
xmlSecSize outSize = 0;
int finalData = 0;
int ret;
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transformCtx != NULL, -1);
do {
/* append data to input buffer */
if(dataSize > 0) {
xmlSecSize chunkSize;
xmlSecAssert2(data != NULL, -1);
chunkSize = dataSize;
if(chunkSize > XMLSEC_TRANSFORM_BINARY_CHUNK) {
chunkSize = XMLSEC_TRANSFORM_BINARY_CHUNK;
}
ret = xmlSecBufferAppend(&(transform->inBuf), data, chunkSize);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecBufferAppend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"size=%d", chunkSize);
return(-1);
}
dataSize -= chunkSize;
data += chunkSize;
}
/* process data */
inSize = xmlSecBufferGetSize(&(transform->inBuf));
outSize = xmlSecBufferGetSize(&(transform->outBuf));
finalData = (((dataSize == 0) && (final != 0)) ? 1 : 0);
ret = xmlSecTransformExecute(transform, finalData, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecTransformExecute",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"final=%d", final);
return(-1);
}
/* push data to the next transform */
inSize = xmlSecBufferGetSize(&(transform->inBuf));
outSize = xmlSecBufferGetSize(&(transform->outBuf));
if(inSize > 0) {
finalData = 0;
}
/* we don't want to puch too much */
if(outSize > XMLSEC_TRANSFORM_BINARY_CHUNK) {
outSize = XMLSEC_TRANSFORM_BINARY_CHUNK;
finalData = 0;
}
if((transform->next != NULL) && ((outSize > 0) || (finalData != 0))) {
ret = xmlSecTransformPushBin(transform->next,
xmlSecBufferGetData(&(transform->outBuf)),
outSize,
finalData,
transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform->next)),
"xmlSecTransformPushBin",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"final=%d;outSize=%d", final, outSize);
return(-1);
}
}
/* remove data anyway */
if(outSize > 0) {
ret = xmlSecBufferRemoveHead(&(transform->outBuf), outSize);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecBufferAppend",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"size=%d", outSize);
return(-1);
}
}
} while((dataSize > 0) || (outSize > 0));
return(0);
}
/**
* xmlSecTransformDefaultPopBin:
* @transform: the pointer to transform object.
* @data: the buffer to store result data.
* @maxDataSize: the size of the buffer #data.
* @dataSize: the pointer to returned data size.
* @transformCtx: the pointer to transform context object.
*
* Pops data from previous transform in the chain, processes data by calling
* transform's execute method and returns result in the @data buffer. The
* size of returned data is placed in the @dataSize.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformDefaultPopBin(xmlSecTransformPtr transform, xmlSecByte* data,
xmlSecSize maxDataSize, xmlSecSize* dataSize, xmlSecTransformCtxPtr transformCtx) {
xmlSecSize outSize;
int final = 0;
int ret;
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(data != NULL, -1);
xmlSecAssert2(dataSize != NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
while((xmlSecBufferGetSize(&(transform->outBuf)) == 0) && (final == 0)) {
/* read data from previous transform if exist */
if(transform->prev != NULL) {
xmlSecSize inSize, chunkSize;
inSize = xmlSecBufferGetSize(&(transform->inBuf));
chunkSize = XMLSEC_TRANSFORM_BINARY_CHUNK;
/* ensure that we have space for at least one data chunk */
ret = xmlSecBufferSetMaxSize(&(transform->inBuf), inSize + chunkSize);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecBufferSetMaxSize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"size=%d", inSize + chunkSize);
return(-1);
}
/* get data from previous transform */
ret = xmlSecTransformPopBin(transform->prev,
xmlSecBufferGetData(&(transform->inBuf)) + inSize,
chunkSize, &chunkSize, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform->prev)),
"xmlSecTransformPopBin",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
/* adjust our size if needed */
if(chunkSize > 0) {
ret = xmlSecBufferSetSize(&(transform->inBuf), inSize + chunkSize);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecBufferSetSize",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"size=%d", inSize + chunkSize);
return(-1);
}
final = 0; /* the previous transform returned some data..*/
} else {
final = 1; /* no data returned from previous transform, we are done */
}
} else {
final = 1; /* no previous transform, we are "permanently final" */
}
/* execute our transform */
ret = xmlSecTransformExecute(transform, final, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecTransformExecute",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
}
/* copy result (if any) */
outSize = xmlSecBufferGetSize(&(transform->outBuf));
if(outSize > maxDataSize) {
outSize = maxDataSize;
}
/* we don't want to put too much */
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);
}
}
/* set the result size */
(*dataSize) = outSize;
return(0);
}
/**
* xmlSecTransformDefaultPushXml:
* @transform: the pointer to transform object.
* @nodes: the input nodes.
* @transformCtx: the pointer to transform context object.
*
* Processes @nodes by calling transform's execute method and pushes
* result to the next transform in the chain.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformDefaultPushXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr nodes,
xmlSecTransformCtxPtr transformCtx) {
int ret;
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transform->inNodes == NULL, -1);
xmlSecAssert2(transform->outNodes == NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
/* execute our transform */
transform->inNodes = nodes;
ret = xmlSecTransformExecute(transform, 1, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecTransformExecute",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
/* push result to the next transform (if exist) */
if(transform->next != NULL) {
ret = xmlSecTransformPushXml(transform->next, transform->outNodes, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecTransformPushXml",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
}
return(0);
}
/**
* xmlSecTransformDefaultPopXml:
* @transform: the pointer to transform object.
* @nodes: the pointer to store popinter to result nodes.
* @transformCtx: the pointer to transform context object.
*
* Pops data from previous transform in the chain, processes the data
* by calling transform's execute method and returns result in @nodes.
*
* Returns 0 on success or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformDefaultPopXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr* nodes,
xmlSecTransformCtxPtr transformCtx) {
int ret;
xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transform->inNodes == NULL, -1);
xmlSecAssert2(transform->outNodes == NULL, -1);
xmlSecAssert2(transformCtx != NULL, -1);
/* pop result from the prev transform (if exist) */
if(transform->prev != NULL) {
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);
}
}
/* execute our transform */
ret = xmlSecTransformExecute(transform, 1, transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecTransformExecute",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
/* return result if requested */
if(nodes != NULL) {
(*nodes) = transform->outNodes;
}
return(0);
}
/***********************************************************************
*
* Transform Ids list
*
**********************************************************************/
static xmlSecPtrListKlass xmlSecTransformIdListKlass = {
BAD_CAST "transform-ids-list",
NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */
NULL, /* xmlSecPtrDestroyItemMethod destroyItem; */
NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
NULL, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
};
/**
* xmlSecTransformIdListGetKlass:
*
* The transform id list klass.
*
* Returns pointer to the transform id list klass.
*/
EXPORT_C
xmlSecPtrListId
xmlSecTransformIdListGetKlass(void) {
return(&xmlSecTransformIdListKlass);
}
/**
* xmlSecTransformIdListFind:
* @list: the pointer to transform ids list.
* @transformId: the transform klass.
*
* Lookups @dataId in @list.
*
* Returns 1 if @dataId is found in the @list, 0 if not and a negative
* value if an error occurs.
*/
EXPORT_C
int
xmlSecTransformIdListFind(xmlSecPtrListPtr list, xmlSecTransformId transformId) {
xmlSecSize i, size;
xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecTransformIdListId), -1);
xmlSecAssert2(transformId != NULL, -1);
size = xmlSecPtrListGetSize(list);
for(i = 0; i < size; ++i) {
if((xmlSecTransformId)xmlSecPtrListGetItem(list, i) == transformId) {
return(1);
}
}
return(0);
}
/**
* xmlSecTransformIdListFindByHref:
* @list: the pointer to transform ids list.
* @href: the desired transform klass href.
* @usage: the desired transform usage.
*
* Lookups data klass in the list with given @href and @usage in @list.
*
* Returns transform klass is found and NULL otherwise.
*/
EXPORT_C
xmlSecTransformId
xmlSecTransformIdListFindByHref(xmlSecPtrListPtr list, const xmlChar* href,
xmlSecTransformUsage usage) {
xmlSecTransformId transformId;
xmlSecSize i, size;
xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecTransformIdListId), xmlSecTransformIdUnknown);
xmlSecAssert2(href != NULL, xmlSecTransformIdUnknown);
size = xmlSecPtrListGetSize(list);
for(i = 0; i < size; ++i) {
transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i);
xmlSecAssert2(transformId != xmlSecTransformIdUnknown, xmlSecTransformIdUnknown);
if(((usage & transformId->usage) != 0) && (transformId->href != NULL) &&
xmlStrEqual(href, transformId->href)) {
return(transformId);
}
}
return(xmlSecTransformIdUnknown);
}
/**
* xmlSecTransformIdListFindByName:
* @list: the pointer to transform ids list.
* @name: the desired transform klass name.
* @usage: the desired transform usage.
*
* Lookups data klass in the list with given @name and @usage in @list.
*
* Returns transform klass is found and NULL otherwise.
*/
EXPORT_C
xmlSecTransformId
xmlSecTransformIdListFindByName(xmlSecPtrListPtr list, const xmlChar* name,
xmlSecTransformUsage usage) {
xmlSecTransformId transformId;
xmlSecSize i, size;
xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecTransformIdListId), xmlSecTransformIdUnknown);
xmlSecAssert2(name != NULL, xmlSecTransformIdUnknown);
size = xmlSecPtrListGetSize(list);
for(i = 0; i < size; ++i) {
transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i);
xmlSecAssert2(transformId != xmlSecTransformIdUnknown, xmlSecTransformIdUnknown);
if(((usage & transformId->usage) != 0) && (transformId->name != NULL) &&
xmlStrEqual(name, BAD_CAST transformId->name)) {
return(transformId);
}
}
return(xmlSecTransformIdUnknown);
}
/**
* xmlSecTransformIdListDebugDump:
* @list: the pointer to transform ids list.
* @output: the pointer to output FILE.
*
* Prints binary transform debug information to @output.
*/
EXPORT_C
void
xmlSecTransformIdListDebugDump(xmlSecPtrListPtr list, FILE* output) {
xmlSecTransformId transformId;
xmlSecSize i, size;
xmlSecAssert(xmlSecPtrListCheckId(list, xmlSecTransformIdListId));
xmlSecAssert(output != NULL);
size = xmlSecPtrListGetSize(list);
for(i = 0; i < size; ++i) {
transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i);
xmlSecAssert(transformId != NULL);
xmlSecAssert(transformId->name != NULL);
if(i > 0) {
fprintf(output, ",\"%s\"", transformId->name);
} else {
fprintf(output, "\"%s\"", transformId->name);
}
}
fprintf(output, "\n");
}
/**
* xmlSecTransformIdListDebugXmlDump:
* @list: the pointer to transform ids list.
* @output: the pointer to output FILE.
*
* Prints binary transform debug information to @output in XML format.
*/
EXPORT_C
void
xmlSecTransformIdListDebugXmlDump(xmlSecPtrListPtr list, FILE* output) {
xmlSecTransformId transformId;
xmlSecSize i, size;
xmlSecAssert(xmlSecPtrListCheckId(list, xmlSecTransformIdListId));
xmlSecAssert(output != NULL);
fprintf(output, "<TransformIdsList>\n");
size = xmlSecPtrListGetSize(list);
for(i = 0; i < size; ++i) {
transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i);
xmlSecAssert(transformId != NULL);
xmlSecAssert(transformId->name != NULL);
fprintf(output, "<TransformId name=\"%s\" />", transformId->name);
}
fprintf(output, "</TransformIdsList>\n");
}
/************************************************************************
*
* IO buffers for transforms
*
************************************************************************/
typedef struct _xmlSecTransformIOBuffer xmlSecTransformIOBuffer,
*xmlSecTransformIOBufferPtr;
typedef enum {
xmlSecTransformIOBufferModeRead,
xmlSecTransformIOBufferModeWrite
} xmlSecTransformIOBufferMode;
struct _xmlSecTransformIOBuffer {
xmlSecTransformIOBufferMode mode;
xmlSecTransformPtr transform;
xmlSecTransformCtxPtr transformCtx;
};
static xmlSecTransformIOBufferPtr xmlSecTransformIOBufferCreate (xmlSecTransformIOBufferMode mode,
xmlSecTransformPtr transform,
xmlSecTransformCtxPtr transformCtx);
static void xmlSecTransformIOBufferDestroy (xmlSecTransformIOBufferPtr buffer);
static int xmlSecTransformIOBufferRead (xmlSecTransformIOBufferPtr buffer,
xmlSecByte *buf,
xmlSecSize size);
static int xmlSecTransformIOBufferWrite (xmlSecTransformIOBufferPtr buffer,
const xmlSecByte *buf,
xmlSecSize size);
static int xmlSecTransformIOBufferClose (xmlSecTransformIOBufferPtr buffer);
/**
* xmlSecTransformCreateOutputBuffer:
* @transform: the pointer to transform.
* @transformCtx: the pointer to transform context object.
*
* Creates output buffer to write data to @transform.
*
* Returns pointer to new output buffer or NULL if an error occurs.
*/
EXPORT_C
xmlOutputBufferPtr
xmlSecTransformCreateOutputBuffer(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) {
xmlSecTransformIOBufferPtr buffer;
xmlSecTransformDataType type;
xmlOutputBufferPtr output;
xmlSecAssert2(xmlSecTransformIsValid(transform), NULL);
xmlSecAssert2(transformCtx != NULL, NULL);
/* check that we have binary push method for this transform */
type = xmlSecTransformDefaultGetDataType(transform, xmlSecTransformModePush, transformCtx);
if((type & xmlSecTransformDataTypeBin) == 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
NULL,
XMLSEC_ERRORS_R_INVALID_TRANSFORM,
"push binary data not supported");
return(NULL);
}
buffer = xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferModeWrite, transform, transformCtx);
if(buffer == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecTransformIOBufferCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
output = xmlOutputBufferCreateIO((xmlOutputWriteCallback)xmlSecTransformIOBufferWrite,
(xmlOutputCloseCallback)xmlSecTransformIOBufferClose,
buffer,
NULL);
if(output == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlOutputBufferCreateIO",
XMLSEC_ERRORS_R_XML_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecTransformIOBufferDestroy(buffer);
return(NULL);
}
return(output);
}
/**
* xmlSecTransformCreateInputBuffer:
* @transform: the pointer to transform.
* @transformCtx: the pointer to transform context object.
*
* Creates input buffer to read data from @transform.
*
* Returns pointer to new input buffer or NULL if an error occurs.
*/
EXPORT_C
xmlParserInputBufferPtr
xmlSecTransformCreateInputBuffer(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) {
xmlSecTransformIOBufferPtr buffer;
xmlSecTransformDataType type;
xmlParserInputBufferPtr input;
xmlSecAssert2(xmlSecTransformIsValid(transform), NULL);
xmlSecAssert2(transformCtx != NULL, NULL);
/* check that we have binary pop method for this transform */
type = xmlSecTransformDefaultGetDataType(transform, xmlSecTransformModePop, transformCtx);
if((type & xmlSecTransformDataTypeBin) == 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
NULL,
XMLSEC_ERRORS_R_INVALID_TRANSFORM,
"pop binary data not supported");
return(NULL);
}
buffer = xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferModeRead, transform, transformCtx);
if(buffer == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlSecTransformIOBufferCreate",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
input = xmlParserInputBufferCreateIO((xmlInputReadCallback)xmlSecTransformIOBufferRead,
(xmlInputCloseCallback)xmlSecTransformIOBufferClose,
buffer,
XML_CHAR_ENCODING_NONE);
if(input == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
"xmlParserInputBufferCreateIO",
XMLSEC_ERRORS_R_XML_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecTransformIOBufferDestroy(buffer);
return(NULL);
}
return(input);
}
static xmlSecTransformIOBufferPtr
xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferMode mode, xmlSecTransformPtr transform,
xmlSecTransformCtxPtr transformCtx) {
xmlSecTransformIOBufferPtr buffer;
xmlSecAssert2(xmlSecTransformIsValid(transform), NULL);
xmlSecAssert2(transformCtx != NULL, NULL);
buffer = (xmlSecTransformIOBufferPtr)xmlMalloc(sizeof(xmlSecTransformIOBuffer));
if(buffer == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_MALLOC_FAILED,
"size=%d", sizeof(xmlSecTransformIOBuffer));
return(NULL);
}
memset(buffer, 0, sizeof(xmlSecTransformIOBuffer));
buffer->mode = mode;
buffer->transform = transform;
buffer->transformCtx = transformCtx;
return(buffer);
}
static void
xmlSecTransformIOBufferDestroy(xmlSecTransformIOBufferPtr buffer) {
xmlSecAssert(buffer != NULL);
memset(buffer, 0, sizeof(xmlSecTransformIOBuffer));
xmlFree(buffer);
}
static int
xmlSecTransformIOBufferRead(xmlSecTransformIOBufferPtr buffer,
xmlSecByte *buf, xmlSecSize size) {
int ret;
xmlSecAssert2(buffer != NULL, -1);
xmlSecAssert2(buffer->mode == xmlSecTransformIOBufferModeRead, -1);
xmlSecAssert2(xmlSecTransformIsValid(buffer->transform), -1);
xmlSecAssert2(buffer->transformCtx != NULL, -1);
xmlSecAssert2(buf != NULL, -1);
ret = xmlSecTransformPopBin(buffer->transform, buf, size, &size, buffer->transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(buffer->transform)),
"xmlSecTransformPopBin",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(size);
}
static int
xmlSecTransformIOBufferWrite(xmlSecTransformIOBufferPtr buffer,
const xmlSecByte *buf, xmlSecSize size) {
int ret;
xmlSecAssert2(buffer != NULL, -1);
xmlSecAssert2(buffer->mode == xmlSecTransformIOBufferModeWrite, -1);
xmlSecAssert2(xmlSecTransformIsValid(buffer->transform), -1);
xmlSecAssert2(buffer->transformCtx != NULL, -1);
xmlSecAssert2(buf != NULL, -1);
ret = xmlSecTransformPushBin(buffer->transform, buf, size, 0, buffer->transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(buffer->transform)),
"xmlSecTransformPushBin",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(-1);
}
return(size);
}
static int
xmlSecTransformIOBufferClose(xmlSecTransformIOBufferPtr buffer) {
int ret;
xmlSecAssert2(buffer != NULL, -1);
xmlSecAssert2(xmlSecTransformIsValid(buffer->transform), -1);
xmlSecAssert2(buffer->transformCtx != NULL, -1);
/* need to flush write buffer before destroing */
if(buffer->mode == xmlSecTransformIOBufferModeWrite) {
ret = xmlSecTransformPushBin(buffer->transform, NULL, 0, 1, buffer->transformCtx);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
xmlSecErrorsSafeString(xmlSecTransformGetName(buffer->transform)),
"xmlSecTransformPushBin",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
xmlSecTransformIOBufferDestroy(buffer);
return(-1);
}
}
xmlSecTransformIOBufferDestroy(buffer);
return(0);
}