diff options
Diffstat (limited to 'src/xslt.c')
-rw-r--r-- | src/xslt.c | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/src/xslt.c b/src/xslt.c new file mode 100644 index 00000000..0353a251 --- /dev/null +++ b/src/xslt.c @@ -0,0 +1,617 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * XSLT Transform (http://www.w3.org/TR/xmldsig-core/#sec-XSLT) + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_XSLT + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/keys.h> +#include <xmlsec/parser.h> +#include <xmlsec/errors.h> +#include <xmlsec/private/xslt.h> + +/************************************************************************** + * + * Internal xslt ctx + * + *****************************************************************************/ +typedef struct _xmlSecXsltCtx xmlSecXsltCtx, *xmlSecXsltCtxPtr; +struct _xmlSecXsltCtx { + xsltStylesheetPtr xslt; + xmlParserCtxtPtr parserCtx; +}; + +/**************************************************************************** + * + * XSLT transform + * + * xmlSecXsltCtx is located after xmlSecTransform + * + ***************************************************************************/ +#define xmlSecXsltSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecXsltCtx)) +#define xmlSecXsltGetCtx(transform) \ + ((xmlSecXsltCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecXsltInitialize (xmlSecTransformPtr transform); +static void xmlSecXsltFinalize (xmlSecTransformPtr transform); +static int xmlSecXsltReadNode (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecXsltPushBin (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + int final, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecXsltExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecXslProcess (xmlSecXsltCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out); +static xmlDocPtr xmlSecXsApplyStylesheet (xmlSecXsltCtxPtr ctx, + xmlDocPtr doc); + +static xmlSecTransformKlass xmlSecXsltKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecXsltSize, /* xmlSecSize objSize */ + + xmlSecNameXslt, /* const xmlChar* name; */ + xmlSecHrefXslt, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecAlgorithmUsage usage; */ + + xmlSecXsltInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecXsltFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecXsltReadNode, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecXsltPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecXsltExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + + +#define XMLSEC_XSLT_COPY_SEC_PREF(src, dst, pref) \ + xsltSetSecurityPrefs((dst), (pref), xsltGetSecurityPrefs((src), (pref))) + +static xsltSecurityPrefsPtr g_xslt_default_security_prefs = NULL; + +void xmlSecTransformXsltInitialize(void) { + xmlSecAssert(g_xslt_default_security_prefs == NULL); + + g_xslt_default_security_prefs = xsltNewSecurityPrefs(); + xmlSecAssert(g_xslt_default_security_prefs != NULL); + xsltSetSecurityPrefs(g_xslt_default_security_prefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid); + xsltSetSecurityPrefs(g_xslt_default_security_prefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid); + xsltSetSecurityPrefs(g_xslt_default_security_prefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid); + xsltSetSecurityPrefs(g_xslt_default_security_prefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid); + xsltSetSecurityPrefs(g_xslt_default_security_prefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid); +} + +void xmlSecTransformXsltShutdown(void) { + if(g_xslt_default_security_prefs != NULL) { + xsltFreeSecurityPrefs(g_xslt_default_security_prefs); + g_xslt_default_security_prefs = NULL; + } +} + +/** + * xmlSecTransformXsltSetDefaultSecurityPrefs: + * @sec: the new security preferences + * + * Sets the new default security preferences. The xmlsec default security policy is + * to disable everything. + */ +XMLSEC_EXPORT void +xmlSecTransformXsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec) { + xmlSecAssert(sec != NULL); + xmlSecAssert(g_xslt_default_security_prefs != NULL); + + /* copy prefs */ + XMLSEC_XSLT_COPY_SEC_PREF(sec, g_xslt_default_security_prefs, XSLT_SECPREF_READ_FILE); + XMLSEC_XSLT_COPY_SEC_PREF(sec, g_xslt_default_security_prefs, XSLT_SECPREF_WRITE_FILE); + XMLSEC_XSLT_COPY_SEC_PREF(sec, g_xslt_default_security_prefs, XSLT_SECPREF_CREATE_DIRECTORY); + XMLSEC_XSLT_COPY_SEC_PREF(sec, g_xslt_default_security_prefs, XSLT_SECPREF_READ_NETWORK); + XMLSEC_XSLT_COPY_SEC_PREF(sec, g_xslt_default_security_prefs, XSLT_SECPREF_WRITE_NETWORK); +} + +/** + * xmlSecTransformXsltGetKlass: + * + * XSLT transform klass (http://www.w3.org/TR/xmldsig-core/#sec-XSLT): + * + * The normative specification for XSL Transformations is [XSLT]. + * Specification of a namespace-qualified stylesheet element, which MUST be + * the sole child of the Transform element, indicates that the specified style + * sheet should be used. Whether this instantiates in-line processing of local + * XSLT declarations within the resource is determined by the XSLT processing + * model; the ordered application of multiple stylesheet may require multiple + * Transforms. No special provision is made for the identification of a remote + * stylesheet at a given URI because it can be communicated via an xsl:include + * or xsl:import within the stylesheet child of the Transform. + * + * This transform requires an octet stream as input. If the actual input is an + * XPath node-set, then the signature application should attempt to convert it + * to octets (apply Canonical XML]) as described in the Reference Processing + * Model (section 4.3.3.2).] + * + * The output of this transform is an octet stream. The processing rules for + * the XSL style sheet or transform element are stated in the XSLT specification + * [XSLT]. We RECOMMEND that XSLT transform authors use an output method of xml + * for XML and HTML. As XSLT implementations do not produce consistent + * serializations of their output, we further RECOMMEND inserting a transform + * after the XSLT transform to canonicalize the output. These steps will help + * to ensure interoperability of the resulting signatures among applications + * that support the XSLT transform. Note that if the output is actually HTML, + * then the result of these steps is logically equivalent [XHTML]. + * + * Returns: pointer to XSLT transform klass. + */ +xmlSecTransformId +xmlSecTransformXsltGetKlass(void) { + return(&xmlSecXsltKlass); +} + +static int +xmlSecXsltInitialize(xmlSecTransformPtr transform) { + xmlSecXsltCtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXsltId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecXsltSize), -1); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecXsltCtx)); + + /* done */ + return(0); +} + +static void +xmlSecXsltFinalize(xmlSecTransformPtr transform) { + xmlSecXsltCtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformXsltId)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecXsltSize)); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->xslt != NULL) { + xsltFreeStylesheet(ctx->xslt); + } + if(ctx->parserCtx != NULL) { + xmlFreeParserCtxt(ctx->parserCtx); + } + memset(ctx, 0, sizeof(xmlSecXsltCtx)); +} + +static int +xmlSecXsltReadNode(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecXsltCtxPtr ctx; + xmlBufferPtr buffer; + xmlDocPtr doc; + xmlNodePtr cur; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXsltId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecXsltSize), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->xslt == NULL, -1); + + /* read content in the buffer */ + buffer = xmlBufferCreate(); + if(buffer == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlBufferCreate", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + cur = node->children; + while(cur != NULL) { + xmlNodeDump(buffer, cur->doc, cur, 0, 0); + cur = cur->next; + } + + /* parse the buffer */ + doc = xmlSecParseMemory(xmlBufferContent(buffer), + xmlBufferLength(buffer), 1); + if(doc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecParseMemory", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlBufferFree(buffer); + return(-1); + } + + /* pre-process stylesheet */ + ctx->xslt = xsltParseStylesheetDoc(doc); + if(ctx->xslt == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xsltParseStylesheetDoc", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + /* after parsing stylesheet doc is assigned + * to it and will be freed by xsltFreeStylesheet() */ + xmlFreeDoc(doc); + xmlBufferFree(buffer); + return(-1); + } + + xmlBufferFree(buffer); + return(0); +} + +static int +xmlSecXsltPushBin(xmlSecTransformPtr transform, const xmlSecByte* data, + xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) { + xmlSecXsltCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXsltId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecXsltSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->xslt != NULL, -1); + + /* check/update current transform status */ + if(transform->status == xmlSecTransformStatusNone) { + xmlSecAssert2(ctx->parserCtx == NULL, -1); + + ctx->parserCtx = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); + if(ctx->parserCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlCreatePushParserCtxt", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* required for c14n! */ + ctx->parserCtx->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + ctx->parserCtx->replaceEntities = 1; + + transform->status = xmlSecTransformStatusWorking; + } else if(transform->status == xmlSecTransformStatusFinished) { + return(0); + } else if(transform->status != xmlSecTransformStatusWorking) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + xmlSecAssert2(transform->status == xmlSecTransformStatusWorking, -1); + xmlSecAssert2(ctx->parserCtx != NULL, -1); + + /* push data to the input buffer */ + if((data != NULL) && (dataSize > 0)) { + ret = xmlParseChunk(ctx->parserCtx, (const char*)data, dataSize, 0); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + "size=%d", dataSize); + return(-1); + } + } + + /* finish parsing, apply xslt transforms and push to next in the chain */ + if(final != 0) { + xmlDocPtr docIn; + xmlDocPtr docOut; + xmlOutputBufferPtr output; + + /* finalize */ + ret = xmlParseChunk(ctx->parserCtx, NULL, 0, 1); + if((ret != 0) || (ctx->parserCtx->myDoc == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* todo: check that document is well formed? */ + docIn = ctx->parserCtx->myDoc; + ctx->parserCtx->myDoc = NULL; + + docOut = xmlSecXsApplyStylesheet(ctx, docIn); + if(docOut == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXsApplyStylesheet", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(docIn); + return(-1); + } + xmlFreeDoc(docIn); + + if(transform->next != NULL) { + output = xmlSecTransformCreateOutputBuffer(transform->next, transformCtx); + if(output == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(docOut); + return(-1); + } + } else { + output = xmlSecBufferCreateOutputBuffer(&(transform->outBuf)); + if(output == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(docOut); + return(-1); + } + } + + ret = xsltSaveResultTo(output, docOut, ctx->xslt); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xsltSaveResultTo", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlOutputBufferClose(output); + xmlFreeDoc(docOut); + return(-1); + } + ret = xmlOutputBufferClose(output); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferClose", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(docOut); + return(-1); + } + xmlFreeDoc(docOut); + + transform->status = xmlSecTransformStatusFinished; + } + + return(0); +} + +static int +xmlSecXsltExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecXsltCtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXsltId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecXsltSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->xslt != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) { + /* just do nothing */ + xmlSecAssert2(outSize == 0, -1); + + } else if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { + xmlSecAssert2(outSize == 0, -1); + + ret = xmlSecXslProcess(ctx, in, out); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXslProcess", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + + transform->status = xmlSecTransformStatusFinished; + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(inSize == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + return(0); +} + +/* TODO: create PopBin method instead */ +static int +xmlSecXslProcess(xmlSecXsltCtxPtr ctx, xmlSecBufferPtr in, xmlSecBufferPtr out) { + xmlDocPtr docIn = NULL; + xmlDocPtr docOut = NULL; + xmlOutputBufferPtr output = NULL; + int res = -1; + int ret; + + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(ctx != NULL, -1); + + docIn = xmlSecParseMemory(xmlSecBufferGetData(in), xmlSecBufferGetSize(in), 1); + if(docIn == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecParseMemory", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + docOut = xmlSecXsApplyStylesheet(ctx, docIn); + if(docOut == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXsApplyStylesheet", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + output = xmlSecBufferCreateOutputBuffer(out); + if(output == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xsltSaveResultTo(output, docOut, ctx->xslt); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xsltSaveResultTo", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlOutputBufferClose(output); + output = NULL; + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlOutputBufferClose", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + res = 0; + +done: + if(output != NULL) xmlOutputBufferClose(output); + if(docIn != NULL) xmlFreeDoc(docIn); + if(docOut != NULL) xmlFreeDoc(docOut); + return(res); +} + + +static xmlDocPtr +xmlSecXsApplyStylesheet(xmlSecXsltCtxPtr ctx, xmlDocPtr doc) { + xsltTransformContextPtr xsltCtx = NULL; + xmlDocPtr res = NULL; + int ret; + + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->xslt != NULL, NULL); + xmlSecAssert2(doc != NULL, NULL); + + xsltCtx = xsltNewTransformContext(ctx->xslt, doc); + if(xsltCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xsltNewTransformContext", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* set security prefs */ + ret = xsltSetCtxtSecurityPrefs(g_xslt_default_security_prefs, xsltCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xsltSetCtxtSecurityPrefs", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + res = xsltApplyStylesheetUser(ctx->xslt, doc, NULL, NULL, NULL, xsltCtx); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xsltApplyStylesheetUser", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + +done: + if(xsltCtx != NULL) xsltFreeTransformContext(xsltCtx); + return res; +} + + +#endif /* XMLSEC_NO_XSLT */ + |