/** 
 * XML Security Library (http://www.aleksey.com/xmlsec).
 *
 * "XML Digital Signature" implementation
 *  http://www.w3.org/TR/xmldsig-core/
 *  http://www.w3.org/Signature/Overview.html
 * 
 * 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_config.h"
#ifndef XMLSEC_NO_XMLDSIG
#include "xmlsec_globals.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <libxml2_tree.h>
#include <libxml2_parser.h>
#include <libxml2_globals.h>

#include "xmlsec_xmlsec.h"
#include "xmlsec_buffer.h"
#include "xmlsec_xmltree.h"
#include "xmlsec_keys.h"
#include "xmlsec_keysmngr.h"
#include "xmlsec_transforms.h"
#include "xmlsec_membuf.h"
#include "xmlsec_xmldsig.h"
#include "xmlsec_errors.h"

/**************************************************************************
 *
 * xmlSecDSigCtx
 *
 *************************************************************************/
static int	xmlSecDSigCtxProcessSignatureNode	(xmlSecDSigCtxPtr dsigCtx, 
							 xmlNodePtr node);
static int	xmlSecDSigCtxProcessSignedInfoNode	(xmlSecDSigCtxPtr dsigCtx, 
							 xmlNodePtr node);
static int	xmlSecDSigCtxProcessKeyInfoNode		(xmlSecDSigCtxPtr dsigCtx, 
							 xmlNodePtr node);
static int	xmlSecDSigCtxProcessObjectNode		(xmlSecDSigCtxPtr dsigCtx, 
							 xmlNodePtr node);
static int	xmlSecDSigCtxProcessManifestNode	(xmlSecDSigCtxPtr dsigCtx, 
							 xmlNodePtr node);

/* The ID attribute in XMLDSig is 'Id' */
static const xmlChar*		xmlSecDSigIds[] = { xmlSecAttrId, NULL };

/**
 * xmlSecDSigCtxCreate:
 * @keysMngr: 		the pointer to keys manager.
 *
 * Creates <dsig:Signature/> element processing context.
 * The caller is responsible for destroying returend object by calling 
 * #xmlSecDSigCtxDestroy function.
 *
 * Returns pointer to newly allocated context object or NULL if an error
 * occurs.
 */
EXPORT_C
xmlSecDSigCtxPtr	
xmlSecDSigCtxCreate(xmlSecKeysMngrPtr keysMngr) {
    xmlSecDSigCtxPtr dsigCtx;
    int ret;
    
    dsigCtx = (xmlSecDSigCtxPtr) xmlMalloc(sizeof(xmlSecDSigCtx));
    if(dsigCtx == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_MALLOC_FAILED,
		    "sizeof(xmlSecDSigCtx)=%d", 
		    sizeof(xmlSecDSigCtx));
	return(NULL);
    }
    
    ret = xmlSecDSigCtxInitialize(dsigCtx, keysMngr);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecDSigCtxInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecDSigCtxDestroy(dsigCtx);
	return(NULL);   
    }
    return(dsigCtx);    
}

/**
 * xmlSecDSigCtxDestroy:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 *
 * Destroy context object created with #xmlSecDSigCtxCreate function.
 */
EXPORT_C
void  
xmlSecDSigCtxDestroy(xmlSecDSigCtxPtr dsigCtx) {
    xmlSecAssert(dsigCtx != NULL);
    
    xmlSecDSigCtxFinalize(dsigCtx);
    xmlFree(dsigCtx);
}

/**
 * xmlSecDSigCtxInitialize:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 * @keysMngr: 		the pointer to keys manager.
 *
 * Initializes <dsig:Signature/> element processing context.
 * The caller is responsible for cleaing up returend object by calling 
 * #xmlSecDSigCtxFinalize function.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecDSigCtxInitialize(xmlSecDSigCtxPtr dsigCtx, xmlSecKeysMngrPtr keysMngr) {
    int ret,ret1;
    
    xmlSecAssert2(dsigCtx != NULL, -1);
    
    memset(dsigCtx, 0, sizeof(xmlSecDSigCtx));

    /* initialize key info */
    ret = xmlSecKeyInfoCtxInitialize(&(dsigCtx->keyInfoReadCtx), keysMngr);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyInfoCtxInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);   
    }
    dsigCtx->keyInfoReadCtx.mode = xmlSecKeyInfoModeRead;
    
    ret = xmlSecKeyInfoCtxInitialize(&(dsigCtx->keyInfoWriteCtx), keysMngr);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyInfoCtxInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);   
    }
    dsigCtx->keyInfoWriteCtx.mode = xmlSecKeyInfoModeWrite;
    /* it's not wise to write private key :) */
    dsigCtx->keyInfoWriteCtx.keyReq.keyType = xmlSecKeyDataTypePublic;

    /* initializes transforms dsigCtx */
    ret = xmlSecTransformCtxInitialize(&(dsigCtx->transformCtx));
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecTransformCtxInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);   
    }

    /* references lists from SignedInfo and Manifest elements */
    ret=xmlSecPtrListInitialize(&(dsigCtx->signedInfoReferences), 
			    xmlSecDSigReferenceCtxListId);
    ret1=xmlSecPtrListInitialize(&(dsigCtx->manifestReferences), 
			    xmlSecDSigReferenceCtxListId);    
    if(ret<0 ||ret1<0)
        {
        xmlSecError(XMLSEC_ERRORS_HERE,
                NULL,
                "xmlSecTransformCtxInitialize",
                XMLSEC_ERRORS_R_XMLSEC_FAILED,
                XMLSEC_ERRORS_NO_MESSAGE);
        return(-1);   
        }

    dsigCtx->enabledReferenceUris = xmlSecTransformUriTypeAny;
    return(0);
}

/**
 * xmlSecDSigCtxFinalize:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 *
 * Cleans up @dsigCtx object initialized with #xmlSecDSigCtxInitialize function.
 */
EXPORT_C
void 
xmlSecDSigCtxFinalize(xmlSecDSigCtxPtr dsigCtx) {
    xmlSecAssert(dsigCtx != NULL);

    xmlSecTransformCtxFinalize(&(dsigCtx->transformCtx));
    xmlSecKeyInfoCtxFinalize(&(dsigCtx->keyInfoReadCtx));
    xmlSecKeyInfoCtxFinalize(&(dsigCtx->keyInfoWriteCtx));
    xmlSecPtrListFinalize(&(dsigCtx->signedInfoReferences));
    xmlSecPtrListFinalize(&(dsigCtx->manifestReferences));

    if(dsigCtx->enabledReferenceTransforms != NULL) {
	xmlSecPtrListDestroy(dsigCtx->enabledReferenceTransforms);	
    }
    if(dsigCtx->signKey != NULL) {
	xmlSecKeyDestroy(dsigCtx->signKey);
    }
    if(dsigCtx->id != NULL) {
	xmlFree(dsigCtx->id);
    }	
    memset(dsigCtx, 0, sizeof(xmlSecDSigCtx));
}

/**
 * xmlSecDSigCtxEnableReferenceTransform:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 * @transformId:	the transform klass.
 *
 * Enables @transformId for <dsig:Reference/> elements processing.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecDSigCtxEnableReferenceTransform(xmlSecDSigCtxPtr dsigCtx, xmlSecTransformId transformId) {
    int ret;
    
    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2(dsigCtx->result == NULL, -1);
    xmlSecAssert2(transformId != xmlSecTransformIdUnknown, -1);

    if(dsigCtx->enabledReferenceTransforms == NULL) {
	dsigCtx->enabledReferenceTransforms = xmlSecPtrListCreate(xmlSecTransformIdListId);
	if(dsigCtx->enabledReferenceTransforms == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecPtrListCreate",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);   
	}
    }	
	
    ret = xmlSecPtrListAdd(dsigCtx->enabledReferenceTransforms, (void*)transformId);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListAdd",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);   
    }
    return(0);
}

/**
 * xmlSecDSigCtxEnableSignatureTransform:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 * @transformId:	the transform klass.
 *
 * Enables @transformId for <dsig:SignedInfo/> element processing.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecDSigCtxEnableSignatureTransform(xmlSecDSigCtxPtr dsigCtx, xmlSecTransformId transformId) {
    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2(dsigCtx->result == NULL, -1);
    xmlSecAssert2(transformId != xmlSecTransformIdUnknown, -1);

    return(xmlSecPtrListAdd(&(dsigCtx->transformCtx.enabledTransforms), (void*)transformId));
}

/**
 * xmlSecDSigCtxGetPreSignBuffer:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 * 
 * Gets pointer to the buffer with serialized <dsig:SignedInfo/> element
 * just before signature claculation (valid if and only if 
 * #XMLSEC_DSIG_FLAGS_STORE_SIGNATURE context flag is set.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
xmlSecBufferPtr 
xmlSecDSigCtxGetPreSignBuffer(xmlSecDSigCtxPtr dsigCtx) {
    xmlSecAssert2(dsigCtx != NULL, NULL);
    
    return((dsigCtx->preSignMemBufMethod != NULL) ? 
	    xmlSecTransformMemBufGetBuffer(dsigCtx->preSignMemBufMethod) : NULL);
}

/**
 * xmlSecDSigCtxSign:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 * @tmpl:		the pointer to <dsig:Signature/> node with signature template.
 *
 * Signs the data as described in @tmpl node.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecDSigCtxSign(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr tmpl) {
    int ret;
    
    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2(dsigCtx->result == NULL, -1);
    xmlSecAssert2(tmpl != NULL, -1);
    xmlSecAssert2(tmpl->doc != NULL, -1);

    /* add ids for Signature nodes */
    dsigCtx->operation 	= xmlSecTransformOperationSign;
    dsigCtx->status 	= xmlSecDSigStatusUnknown;
    xmlSecAddIDs(tmpl->doc, tmpl, xmlSecDSigIds);

    /* read signature template */
    ret = xmlSecDSigCtxProcessSignatureNode(dsigCtx, tmpl);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecDSigCtxSigantureProcessNode",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    xmlSecAssert2(dsigCtx->signMethod != NULL, -1);
    xmlSecAssert2(dsigCtx->signValueNode != NULL, -1);

    /* references processing might change the status */
    if(dsigCtx->status != xmlSecDSigStatusUnknown) {
	return(0);
    }

    /* check what we've got */
    dsigCtx->result = dsigCtx->transformCtx.result;
    if((dsigCtx->result == NULL) || (xmlSecBufferGetData(dsigCtx->result) == NULL)) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_INVALID_RESULT,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* write signed data to xml */
    xmlNodeSetContentLen(dsigCtx->signValueNode,
			    xmlSecBufferGetData(dsigCtx->result),
			    xmlSecBufferGetSize(dsigCtx->result));
    if ( OOM_FLAG )
        {
        return(-1);
        }
    
    /* set success status and we are done */
    dsigCtx->status = xmlSecDSigStatusSucceeded;
    return(0);    
}

/**
 * xmlSecDSigCtxVerify:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 * @node:		the pointer with <dsig:Signature/> node.
 * 
 * Vaidates signature in the @node. The verification result is returned
 * in #status member of the @dsigCtx object.
 *
 * Returns 0 on success (check #status member of @dsigCtx to get 
 * signature verification result) or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecDSigCtxVerify(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) {
    int ret;
    
    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    xmlSecAssert2(node->doc != NULL, -1);

    /* add ids for Signature nodes */
    dsigCtx->operation 	= xmlSecTransformOperationVerify;
    dsigCtx->status 	= xmlSecDSigStatusUnknown;
    xmlSecAddIDs(node->doc, node, xmlSecDSigIds);
    
    /* read siganture info */
    ret = xmlSecDSigCtxProcessSignatureNode(dsigCtx, node);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecDSigCtxSigantureProcessNode",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    xmlSecAssert2(dsigCtx->signMethod != NULL, -1);
    xmlSecAssert2(dsigCtx->signValueNode != NULL, -1);

    /* references processing might change the status */
    if(dsigCtx->status != xmlSecDSigStatusUnknown) {
	return(0);
    }

    /* verify SignatureValue node content */
    ret = xmlSecTransformVerifyNodeContent(dsigCtx->signMethod, dsigCtx->signValueNode,
					   &(dsigCtx->transformCtx));
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecTransformVerifyNodeContent",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    /* set status and we are done */
    if(dsigCtx->signMethod->status == xmlSecTransformStatusOk) {
        dsigCtx->status = xmlSecDSigStatusSucceeded;
    } else {
        dsigCtx->status = xmlSecDSigStatusInvalid;
    }
    return(0);
}

/**
 * xmlSecDSigCtxProcessSignatureNode:
 *
 * The Signature  element (http://www.w3.org/TR/xmldsig-core/#sec-Signature)
 *
 * The Signature element is the root element of an XML Signature. 
 * Implementation MUST generate laxly schema valid [XML-schema] Signature 
 * elements as specified by the following schema:
 * The way in which the SignedInfo element is presented to the 
 * canonicalization method is dependent on that method. The following 
 * applies to algorithms which process XML as nodes or characters:
 *
 *  - XML based canonicalization implementations MUST be provided with 
 *  a [XPath] node-set originally formed from the document containing 
 *  the SignedInfo and currently indicating the SignedInfo, its descendants,
 *  and the attribute and namespace nodes of SignedInfo and its descendant 
 *  elements.
 *
 *  - Text based canonicalization algorithms (such as CRLF and charset 
 *  normalization) should be provided with the UTF-8 octets that represent 
 *  the well-formed SignedInfo element, from the first character to the 
 *  last character of the XML representation, inclusive. This includes 
 *  the entire text of the start and end tags of the SignedInfo element 
 *  as well as all descendant markup and character data (i.e., the text) 
 *  between those tags. Use of text based canonicalization of SignedInfo 
 *  is NOT RECOMMENDED.   	     
 *
 *  =================================
 *  we do not support any non XML based C14N 
 *
 * Schema Definition:
 *
 *  <element name="Signature" type="ds:SignatureType"/>
 *  <complexType name="SignatureType">
 *  <sequence> 
 *     <element ref="ds:SignedInfo"/> 
 *     <element ref="ds:SignatureValue"/> 
 *     <element ref="ds:KeyInfo" minOccurs="0"/> 
 *     <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/> 
 *     </sequence> <attribute name="Id" type="ID" use="optional"/>
 *  </complexType>
 *    
 * DTD:
 *    
 *  <!ELEMENT Signature (SignedInfo, SignatureValue, KeyInfo?, Object*)  >
 *  <!ATTLIST Signature  
 *      xmlns   CDATA   #FIXED 'http://www.w3.org/2000/09/xmldsig#'
 *      Id      ID  #IMPLIED >
 *
 */
static int
xmlSecDSigCtxProcessSignatureNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) {
    xmlSecTransformDataType firstType;
    xmlNodePtr signedInfoNode = NULL;
    xmlNodePtr keyInfoNode = NULL;
    xmlNodePtr cur;
    int ret;
    
    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2((dsigCtx->operation == xmlSecTransformOperationSign) || (dsigCtx->operation == xmlSecTransformOperationVerify), -1);
    xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1);
    xmlSecAssert2(dsigCtx->signValueNode == NULL, -1);
    xmlSecAssert2(dsigCtx->signMethod == NULL, -1);
    xmlSecAssert2(dsigCtx->c14nMethod == NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    if(!xmlSecCheckNodeName(node, xmlSecNodeSignature, xmlSecDSigNs)) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
		    XMLSEC_ERRORS_R_INVALID_NODE,
		    "expected=%s",
		    xmlSecErrorsSafeString(xmlSecNodeSignature));
	return(-1);	    
    }

    /* read node data */
    xmlSecAssert2(dsigCtx->id == NULL, -1);
    dsigCtx->id = xmlGetProp(node, xmlSecAttrId);

    /* first node is required SignedInfo */
    cur = xmlSecGetNextElementNode(node->children);    
    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeSignedInfo, xmlSecDSigNs))) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_INVALID_NODE,
		    "expected=%s",
		    xmlSecErrorsSafeString(xmlSecNodeSignedInfo));
        return(-1);
    }
    signedInfoNode = cur;
    cur = xmlSecGetNextElementNode(cur->next);

    /* next node is required SignatureValue */
    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeSignatureValue, xmlSecDSigNs))) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_INVALID_NODE,
		    "expected=%s",
		    xmlSecErrorsSafeString(xmlSecNodeSignatureValue));
	return(-1);
    }
    dsigCtx->signValueNode = cur;
    cur = xmlSecGetNextElementNode(cur->next);

    /* next node is optional KeyInfo */
    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs))) {
	keyInfoNode = cur;
	cur = xmlSecGetNextElementNode(cur->next);
    } else {
	keyInfoNode = NULL;
    }
    
    /* next nodes are optional Object nodes */
    while((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeObject, xmlSecDSigNs))) {
	/* read manifests from objects */
	if((dsigCtx->flags & XMLSEC_DSIG_FLAGS_IGNORE_MANIFESTS) == 0) {
	    ret = xmlSecDSigCtxProcessObjectNode(dsigCtx, cur);
	    if(ret < 0) {
    		xmlSecError(XMLSEC_ERRORS_HERE,
			    NULL,
			    "xmlSecDSigCtxProcessObjectNode",
			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
			    XMLSEC_ERRORS_NO_MESSAGE);
		return(-1);	    	    
	    }
	}
	cur = xmlSecGetNextElementNode(cur->next);
    }
    
    /* if there is something left than it's an error */
    if(cur != NULL) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* now validated all the references and prepare transform */
    ret = xmlSecDSigCtxProcessSignedInfoNode(dsigCtx, signedInfoNode);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecDSigCtxProcessSignedInfoNode",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);	
    }				
    /* references processing might change the status */
    if(dsigCtx->status != xmlSecDSigStatusUnknown) {
	return(0);
    }
    
    /* as the result, we should have sign and c14n methods set */    
    xmlSecAssert2(dsigCtx->signMethod != NULL, -1);
    xmlSecAssert2(dsigCtx->c14nMethod != NULL, -1);

    ret = xmlSecDSigCtxProcessKeyInfoNode(dsigCtx, keyInfoNode);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecDSigCtxProcessKeyInfoNode",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);	
    }				
    /* as the result, we should have a key */
    xmlSecAssert2(dsigCtx->signKey != NULL, -1);

    /* if we need to write result to xml node then we need base64 encode result */
    if(dsigCtx->operation == xmlSecTransformOperationSign) {	
	xmlSecTransformPtr base64Encode;
	
	/* we need to add base64 encode transform */
	base64Encode = xmlSecTransformCtxCreateAndAppend(&(dsigCtx->transformCtx), 
							 xmlSecTransformBase64Id);
    	if(base64Encode == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxCreateAndAppend",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	base64Encode->operation = xmlSecTransformOperationEncode;
    }

    firstType = xmlSecTransformGetDataType(dsigCtx->transformCtx.first, 
					   xmlSecTransformModePush, 
					   &(dsigCtx->transformCtx));
    if((firstType & xmlSecTransformDataTypeXml) != 0) {
	xmlSecNodeSetPtr nodeset = NULL;

	xmlSecAssert2(signedInfoNode != NULL, -1);
        nodeset = xmlSecNodeSetGetChildren(signedInfoNode->doc, signedInfoNode, 1, 0);
	if(nodeset == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecNodeSetGetChildren",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"node=%s",
		        xmlSecErrorsSafeString(xmlSecNodeGetName(signedInfoNode)));
	    return(-1);
	}

	/* calculate the signature */
	ret = xmlSecTransformCtxXmlExecute(&(dsigCtx->transformCtx), nodeset);
	if(ret < 0) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
			"xmlSecTransformCtxXmlExecute",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecNodeSetDestroy(nodeset);
	    return(-1);
	}
	xmlSecNodeSetDestroy(nodeset);
    } else {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "the binary c14n transforms are not supported yet",
		    XMLSEC_ERRORS_R_NOT_IMPLEMENTED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    return(0);
}

/** 
 * xmlSecDSigCtxProcessSignedInfoNode:
 *
 * The SignedInfo Element (http://www.w3.org/TR/xmldsig-core/#sec-SignedInfo)
 * 
 * The structure of SignedInfo includes the canonicalization algorithm, 
 * a result algorithm, and one or more references. The SignedInfo element 
 * may contain an optional ID attribute that will allow it to be referenced by 
 * other signatures and objects.
 *
 * SignedInfo does not include explicit result or digest properties (such as
 * calculation time, cryptographic device serial number, etc.). If an 
 * application needs to associate properties with the result or digest, 
 * it may include such information in a SignatureProperties element within 
 * an Object element.
 *
 * Schema Definition:
 *
 *  <element name="SignedInfo" type="ds:SignedInfoType"/> 
 *  <complexType name="SignedInfoType">
 *    <sequence> 
 *      <element ref="ds:CanonicalizationMethod"/>
 *      <element ref="ds:SignatureMethod"/> 
 *      <element ref="ds:Reference" maxOccurs="unbounded"/> 
 *    </sequence> 
 *    <attribute name="Id" type="ID" use="optional"/> 
 *  </complexType>
 *    
 * DTD:
 *    
 *  <!ELEMENT SignedInfo (CanonicalizationMethod, SignatureMethod,  Reference+) >
 *  <!ATTLIST SignedInfo  Id   ID      #IMPLIED>
 * 
 */
static int 
xmlSecDSigCtxProcessSignedInfoNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) {
    xmlSecDSigReferenceCtxPtr dsigRefCtx;
    xmlNodePtr cur;
    int ret;
    
    xmlSecAssert2(dsigCtx != NULL, -1);	
    xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1);
    xmlSecAssert2(dsigCtx->signMethod == NULL, -1);
    xmlSecAssert2(dsigCtx->c14nMethod == NULL, -1);
    xmlSecAssert2((dsigCtx->operation == xmlSecTransformOperationSign) || (dsigCtx->operation == xmlSecTransformOperationVerify), -1);
    xmlSecAssert2(xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)) == 0, -1);
    xmlSecAssert2(node != NULL, -1);
    
    /* first node is required CanonicalizationMethod. */
    cur = xmlSecGetNextElementNode(node->children);
    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCanonicalizationMethod, xmlSecDSigNs))) {
	dsigCtx->c14nMethod = xmlSecTransformCtxNodeRead(&(dsigCtx->transformCtx), 
					cur, xmlSecTransformUsageC14NMethod);
	if(dsigCtx->c14nMethod == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxNodeRead",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"node=%s",
			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
	    return(-1);	
	}	
    } else if(dsigCtx->defC14NMethodId != xmlSecTransformIdUnknown) {
	/* the dsig spec does require CanonicalizationMethod node
	 * to be present but in some case it application might decide to
	 * minimize traffic */
	dsigCtx->c14nMethod = xmlSecTransformCtxCreateAndAppend(&(dsigCtx->transformCtx), 
							      dsigCtx->defC14NMethodId);
	if(dsigCtx->c14nMethod == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxAppend",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    } else {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_INVALID_NODE,
		    "expected=%s",
		    xmlSecErrorsSafeString(xmlSecNodeCanonicalizationMethod));
	return(-1);
    }	
    
    /* insert membuf if requested */
    if((dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_SIGNATURE) != 0) {
	xmlSecAssert2(dsigCtx->preSignMemBufMethod == NULL, -1);
	dsigCtx->preSignMemBufMethod = xmlSecTransformCtxCreateAndAppend(&(dsigCtx->transformCtx), 
						xmlSecTransformMemBufId);
	if(dsigCtx->preSignMemBufMethod == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxCreateAndAppend",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"transform=%s",
			xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformMemBufId)));
	}
    }
        
    /* next node is required SignatureMethod. */
	if (cur != NULL){
		cur = xmlSecGetNextElementNode(cur->next);
	}
    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeSignatureMethod, xmlSecDSigNs))) {
	dsigCtx->signMethod = xmlSecTransformCtxNodeRead(&(dsigCtx->transformCtx), 
					cur, xmlSecTransformUsageSignatureMethod);
	if(dsigCtx->signMethod == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxNodeRead",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"node=%s",
			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
	    return(-1);	
	}	
    } else if(dsigCtx->defSignMethodId != xmlSecTransformIdUnknown) {
	/* the dsig spec does require SignatureMethod node
	 * to be present but in some case it application might decide to
	 * minimize traffic */
	dsigCtx->signMethod = xmlSecTransformCtxCreateAndAppend(&(dsigCtx->transformCtx), 
							      dsigCtx->defSignMethodId);
	if(dsigCtx->signMethod == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxAppend",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    } else {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_INVALID_NODE,
		    "expected=%s",
		    xmlSecErrorsSafeString(xmlSecNodeSignatureMethod));
	return(-1);
    }	
    dsigCtx->signMethod->operation = dsigCtx->operation;
    
    /* calculate references */
	if (cur != NULL) {
		cur = xmlSecGetNextElementNode(cur->next);
	}
    while((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeReference, xmlSecDSigNs))) {
        /* create reference */
	dsigRefCtx = xmlSecDSigReferenceCtxCreate(dsigCtx, xmlSecDSigReferenceOriginSignedInfo);
	if(dsigRefCtx == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
		        "xmlSecDSigReferenceCtxCreate",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);	    
	}

	/* add to the list */
	ret = xmlSecPtrListAdd(&(dsigCtx->signedInfoReferences), dsigRefCtx);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecPtrListAdd",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecDSigReferenceCtxDestroy(dsigRefCtx);
	    return(-1);	    
	}

	/* process */
	ret = xmlSecDSigReferenceCtxProcessNode(dsigRefCtx, cur);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecDSigReferenceCtxProcessNode",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"node=%s",
			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
	    return(-1);	    
	}

	/* bail out if next Reference processing failed */
	if(dsigRefCtx->status != xmlSecDSigStatusSucceeded) {
	    dsigCtx->status = xmlSecDSigStatusInvalid;
	    return(0); 
	}
	cur = xmlSecGetNextElementNode(cur->next);
    }

    /* check that we have at least one Reference */
    if(xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)) == 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_DSIG_NO_REFERENCES,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* if there is something left than it's an error */
    if(cur != NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    return(0);
}

static int 
xmlSecDSigCtxProcessKeyInfoNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) {
    int ret;
    
    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2(dsigCtx->signMethod != NULL, -1);

    /* set key requirements */
    ret = xmlSecTransformSetKeyReq(dsigCtx->signMethod, &(dsigCtx->keyInfoReadCtx.keyReq));
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecTransformSetKeyReq",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "transform=%s",
		    xmlSecErrorsSafeString(xmlSecTransformGetName(dsigCtx->signMethod)));
	return(-1);
    }	
    
    /* ignore <dsig:KeyInfo /> if there is the key is already set */
    if((dsigCtx->signKey == NULL) && (dsigCtx->keyInfoReadCtx.keysMngr != NULL) 
			&& (dsigCtx->keyInfoReadCtx.keysMngr->getKey != NULL)) {	
	dsigCtx->signKey = (dsigCtx->keyInfoReadCtx.keysMngr->getKey)(node, &(dsigCtx->keyInfoReadCtx));
    }
    
    /* check that we have exactly what we want */
    if((dsigCtx->signKey == NULL) || (!xmlSecKeyMatch(dsigCtx->signKey, NULL, &(dsigCtx->keyInfoReadCtx.keyReq)))) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_KEY_NOT_FOUND,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    /* set the key to the transform */
    ret = xmlSecTransformSetKey(dsigCtx->signMethod, dsigCtx->signKey);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecTransformSetKey",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "transform=%s",
		    xmlSecErrorsSafeString(xmlSecTransformGetName(dsigCtx->signMethod)));
	return(-1);
    }

    /* if we are signing document, update <dsig:KeyInfo/> node */
    if((node != NULL) && (dsigCtx->operation == xmlSecTransformOperationSign)) {	
	ret = xmlSecKeyInfoNodeWrite(node, dsigCtx->signKey, &(dsigCtx->keyInfoWriteCtx));
	if(ret < 0) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecKeyInfoNodeWrite",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}	
    }
    
    return(0);
}

/**
 * xmlSecDSigCtxProcessObjectNode:
 * 	
 * The Object Element (http://www.w3.org/TR/xmldsig-core/#sec-Object)
 * 
 * Object is an optional element that may occur one or more times. When 
 * present, this element may contain any data. The Object element may include 
 * optional MIME type, ID, and encoding attributes.
 *     
 * Schema Definition:
 *     
 * <element name="Object" type="ds:ObjectType"/> 
 * <complexType name="ObjectType" mixed="true">
 *   <sequence minOccurs="0" maxOccurs="unbounded">
 *     <any namespace="##any" processContents="lax"/>
 *   </sequence>
 *   <attribute name="Id" type="ID" use="optional"/> 
 *   <attribute name="MimeType" type="string" use="optional"/>
 *   <attribute name="Encoding" type="anyURI" use="optional"/> 
 * </complexType>
 *	
 * DTD:
 *	
 * <!ELEMENT Object (#PCDATA|Signature|SignatureProperties|Manifest %Object.ANY;)* >
 * <!ATTLIST Object  Id  ID  #IMPLIED 
 *                   MimeType    CDATA   #IMPLIED 
 *                   Encoding    CDATA   #IMPLIED >
 */
static int
xmlSecDSigCtxProcessObjectNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) {
    xmlNodePtr cur;
    int ret;

    xmlSecAssert2(dsigCtx != NULL, -1);	
    xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1);
    xmlSecAssert2(node != NULL, -1);
    
    /* we care about Manifest nodes only; ignore everything else */
    cur = xmlSecGetNextElementNode(node->children);
    while(cur != NULL) {
	if(xmlSecCheckNodeName(cur, xmlSecNodeManifest, xmlSecDSigNs)) {
	    ret = xmlSecDSigCtxProcessManifestNode(dsigCtx, cur);
	    if(ret < 0){
    		xmlSecError(XMLSEC_ERRORS_HERE,
			    NULL,
			    "xmlSecDSigCtxProcessManifestNode",
			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
			    XMLSEC_ERRORS_NO_MESSAGE);
		return(-1);	    
	    }
	}
	cur = xmlSecGetNextElementNode(cur->next);
    }
    return(0);
}

/**
 * xmlSecDSigCtxProcessManifestNode: 
 *
 * The Manifest  Element (http://www.w3.org/TR/xmldsig-core/#sec-Manifest)
 *
 * The Manifest element provides a list of References. The difference from 
 * the list in SignedInfo is that it is application defined which, if any, of 
 * the digests are actually checked against the objects referenced and what to 
 * do if the object is inaccessible or the digest compare fails. If a Manifest 
 * is pointed to from SignedInfo, the digest over the Manifest itself will be 
 * checked by the core result validation behavior. The digests within such 
 * a Manifest are checked at the application's discretion. If a Manifest is 
 * referenced from another Manifest, even the overall digest of this two level 
 * deep Manifest might not be checked.
 *     
 * Schema Definition:
 *     
 * <element name="Manifest" type="ds:ManifestType"/> 
 * <complexType name="ManifestType">
 *   <sequence>
 *     <element ref="ds:Reference" maxOccurs="unbounded"/> 
 *   </sequence> 
 *   <attribute name="Id" type="ID" use="optional"/> 
 *  </complexType>
 *	
 * DTD:
 *
 * <!ELEMENT Manifest (Reference+)  >
 * <!ATTLIST Manifest Id ID  #IMPLIED >
 */
static int
xmlSecDSigCtxProcessManifestNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) {
    xmlSecDSigReferenceCtxPtr dsigRefCtx;
    xmlNodePtr cur;
    int ret;

    xmlSecAssert2(dsigCtx != NULL, -1);	
    xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1);
    xmlSecAssert2(node != NULL, -1);

    /* calculate references */
    cur = xmlSecGetNextElementNode(node->children);
    while((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeReference, xmlSecDSigNs))) {
        /* create reference */
	dsigRefCtx = xmlSecDSigReferenceCtxCreate(dsigCtx, xmlSecDSigReferenceOriginManifest);
	if(dsigRefCtx == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
		        "xmlSecDSigReferenceCtxCreate",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);	    
	}

	/* add to the list */
	ret = xmlSecPtrListAdd(&(dsigCtx->manifestReferences), dsigRefCtx);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecPtrListAdd",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecDSigReferenceCtxDestroy(dsigRefCtx);
	    return(-1);	    
	}

	/* process */
	ret = xmlSecDSigReferenceCtxProcessNode(dsigRefCtx, cur);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecDSigReferenceCtxProcessNode",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"node=%s",
			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
	    return(-1);	    
	}

	/* we don;t care if Reference processing failed because
	 * it's Manifest node */
	cur = xmlSecGetNextElementNode(cur->next);
    }

    /* we should have nothing else here */
    if(cur != NULL) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }    
    return(0);
}

/**
 * xmlSecDSigCtxDebugDump:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 * @output:		the pointer to output FILE.
 *
 * Prints the debug information about @dsigCtx to @output.
 */
EXPORT_C
void 
xmlSecDSigCtxDebugDump(xmlSecDSigCtxPtr dsigCtx, FILE* output) {
    xmlSecAssert(dsigCtx != NULL);
    xmlSecAssert(output != NULL);

    if(dsigCtx->operation == xmlSecTransformOperationSign) {    
	fprintf(output, "= SIGNATURE CONTEXT\n");
    } else {
	fprintf(output, "= VERIFICATION CONTEXT\n");
    }
    switch(dsigCtx->status) {
	case xmlSecDSigStatusUnknown:
	    fprintf(output, "== Status: unknown\n");
	    break;
	case xmlSecDSigStatusSucceeded:
	    fprintf(output, "== Status: succeeded\n");
	    break;
	case xmlSecDSigStatusInvalid:
	    fprintf(output, "== Status: invalid\n");
	    break;
    }
    fprintf(output, "== flags: 0x%08x\n", dsigCtx->flags);
    fprintf(output, "== flags2: 0x%08x\n", dsigCtx->flags2);

    if(dsigCtx->id != NULL) {
	fprintf(output, "== Id: \"%s\"\n", dsigCtx->id);
    }
    
    fprintf(output, "== Key Info Read Ctx:\n");
    xmlSecKeyInfoCtxDebugDump(&(dsigCtx->keyInfoReadCtx), output);
    fprintf(output, "== Key Info Write Ctx:\n");
    xmlSecKeyInfoCtxDebugDump(&(dsigCtx->keyInfoWriteCtx), output);

    fprintf(output, "== Signature Transform Ctx:\n");
    xmlSecTransformCtxDebugDump(&(dsigCtx->transformCtx), output);

    if(dsigCtx->signMethod != NULL) {
        fprintf(output, "== Signature Method:\n");
	xmlSecTransformDebugDump(dsigCtx->signMethod, output);
    }

    if(dsigCtx->signKey != NULL) {
        fprintf(output, "== Signature Key:\n");
	xmlSecKeyDebugDump(dsigCtx->signKey, output);
    }
    
    fprintf(output, "== SignedInfo References List:\n");
    xmlSecPtrListDebugDump(&(dsigCtx->signedInfoReferences), output);

    fprintf(output, "== Manifest References List:\n");
    xmlSecPtrListDebugDump(&(dsigCtx->manifestReferences), output);
    
    if((dsigCtx->result != NULL) && 
       (xmlSecBufferGetData(dsigCtx->result) != NULL)) {

	fprintf(output, "== Result - start buffer:\n");
	fwrite(xmlSecBufferGetData(dsigCtx->result), 
	       xmlSecBufferGetSize(dsigCtx->result), 
	       1, output);
	fprintf(output, "\n== Result - end buffer\n");
    }
    if(((dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_SIGNATURE) != 0) &&
       (xmlSecDSigCtxGetPreSignBuffer(dsigCtx) != NULL) &&
       (xmlSecBufferGetData(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)) != NULL)) {
       
	fprintf(output, "== PreSigned data - start buffer:\n");
	fwrite(xmlSecBufferGetData(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)), 
	       xmlSecBufferGetSize(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)), 
	       1, output);
	fprintf(output, "\n== PreSigned data - end buffer\n");       
    }
}

/**
 * xmlSecDSigCtxDebugXmlDump:
 * @dsigCtx:		the pointer to <dsig:Signature/> processing context.
 * @output:		the pointer to output FILE.
 *
 * Prints the debug information about @dsigCtx to @output in XML format.
 */
EXPORT_C
void 
xmlSecDSigCtxDebugXmlDump(xmlSecDSigCtxPtr dsigCtx, FILE* output) {
    xmlSecAssert(dsigCtx != NULL);
    xmlSecAssert(output != NULL);

    if(dsigCtx->operation == xmlSecTransformOperationSign) {    
	fprintf(output, "<SignatureContext \n");
    } else {
	fprintf(output, "<VerificationContext \n");
    }
    switch(dsigCtx->status) {
	case xmlSecDSigStatusUnknown:
	    fprintf(output, "status=\"unknown\" >\n");
	    break;
	case xmlSecDSigStatusSucceeded:
	    fprintf(output, "status=\"succeeded\" >\n");
	    break;
	case xmlSecDSigStatusInvalid:
	    fprintf(output, "status=\"invalid\" >\n");
	    break;
    }

    fprintf(output, "<Flags>%08x</Flags>\n", dsigCtx->flags);
    fprintf(output, "<Flags2>%08x</Flags2>\n", dsigCtx->flags2);

    if(dsigCtx->id != NULL) {
	fprintf(output, "<Id>%s</Id>\n", dsigCtx->id);
    }

    fprintf(output, "<KeyInfoReadCtx>\n");
    xmlSecKeyInfoCtxDebugXmlDump(&(dsigCtx->keyInfoReadCtx), output);
    fprintf(output, "</KeyInfoReadCtx>\n");

    fprintf(output, "<KeyInfoWriteCtx>\n");
    xmlSecKeyInfoCtxDebugXmlDump(&(dsigCtx->keyInfoWriteCtx), output);
    fprintf(output, "</KeyInfoWriteCtx>\n");

    fprintf(output, "<SignatureTransformCtx>\n");
    xmlSecTransformCtxDebugXmlDump(&(dsigCtx->transformCtx), output);
    fprintf(output, "</SignatureTransformCtx>\n");

    if(dsigCtx->signMethod != NULL) {
        fprintf(output, "<SignatureMethod>\n");
	xmlSecTransformDebugXmlDump(dsigCtx->signMethod, output);
        fprintf(output, "</SignatureMethod>\n");
    }

    if(dsigCtx->signKey != NULL) {
        fprintf(output, "<SignatureKey>\n");
	xmlSecKeyDebugXmlDump(dsigCtx->signKey, output);
        fprintf(output, "</SignatureKey>\n");
    }

    fprintf(output, "<SignedInfoReferences>\n");
    xmlSecPtrListDebugXmlDump(&(dsigCtx->signedInfoReferences), output);
    fprintf(output, "</SignedInfoReferences>\n");

    fprintf(output, "<ManifestReferences>\n");
    xmlSecPtrListDebugXmlDump(&(dsigCtx->manifestReferences), output);
    fprintf(output, "</ManifestReferences>\n");

    if((dsigCtx->result != NULL) && 
       (xmlSecBufferGetData(dsigCtx->result) != NULL)) {

	fprintf(output, "<Result>");
	fwrite(xmlSecBufferGetData(dsigCtx->result), 
	       xmlSecBufferGetSize(dsigCtx->result), 
	       1, output);
	fprintf(output, "</Result>\n");
    }
    if(((dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_SIGNATURE) != 0) &&
       (xmlSecDSigCtxGetPreSignBuffer(dsigCtx) != NULL) &&
       (xmlSecBufferGetData(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)) != NULL)) {
       
	fprintf(output, "<PreSignedData>");
	fwrite(xmlSecBufferGetData(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)), 
	       xmlSecBufferGetSize(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)), 
	       1, output);
	fprintf(output, "</PreSignedData>\n");       
    }

    if(dsigCtx->operation == xmlSecTransformOperationSign) {    
	fprintf(output, "</SignatureContext>\n");
    } else {
	fprintf(output, "</VerificationContext>\n");
    }
}

/**************************************************************************
 *
 * xmlSecDSigReferenceCtx
 *
 *************************************************************************/
/**
 * xmlSecDSigReferenceCtxCreate:
 * @dsigCtx:		the pointer to parent <dsig:Signature/> node processing context.
 * @origin:		the reference origin (<dsig:SignedInfo/> or <dsig:Manifest/> node).
 *
 * Creates new <dsig:Reference/> element processing context. Caller is responsible
 * for destroying the returned context by calling #xmlSecDSigReferenceCtxDestroy
 * function.
 *
 * Returns pointer to newly created context or NULL if an error occurs.
 */
EXPORT_C
xmlSecDSigReferenceCtxPtr	
xmlSecDSigReferenceCtxCreate(xmlSecDSigCtxPtr dsigCtx, xmlSecDSigReferenceOrigin origin) {
    xmlSecDSigReferenceCtxPtr dsigRefCtx;
    int ret;
    
    xmlSecAssert2(dsigCtx != NULL, NULL);
    
    dsigRefCtx = (xmlSecDSigReferenceCtxPtr) xmlMalloc(sizeof(xmlSecDSigReferenceCtx));
    if(dsigRefCtx == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_MALLOC_FAILED,
		    "sizeof(xmlSecDSigReferenceCtx)=%d", 
		    sizeof(xmlSecDSigReferenceCtx));
	return(NULL);
    }
    
    ret = xmlSecDSigReferenceCtxInitialize(dsigRefCtx, dsigCtx, origin);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecDSigReferenceCtxInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecDSigReferenceCtxDestroy(dsigRefCtx);
	return(NULL);   
    }
    return(dsigRefCtx);    
}

/** 
 * xmlSecDSigReferenceCtxDestroy:
 * @dsigRefCtx:		the pointer to <dsig:Reference/> element processing context.
 *
 * Destroy context object created with #xmlSecDSigReferenceCtxCreate function.
 */
EXPORT_C
void  
xmlSecDSigReferenceCtxDestroy(xmlSecDSigReferenceCtxPtr dsigRefCtx) {
    xmlSecAssert(dsigRefCtx != NULL);
    
    xmlSecDSigReferenceCtxFinalize(dsigRefCtx);
    xmlFree(dsigRefCtx);
}

/**
 * xmlSecDSigReferenceCtxInitialize:
 * @dsigRefCtx:		the pointer to <dsig:Reference/> element processing context.
 * @dsigCtx:		the pointer to parent <dsig:Signature/> node processing context.
 * @origin:		the reference origin (<dsig:SignedInfo/> or <dsig:Manifest/> node).
 *
 * Initializes new <dsig:Reference/> element processing context. Caller is responsible
 * for cleaning up the returned context by calling #xmlSecDSigReferenceCtxFinalize
 * function.
 *
 * Returns 0 on succes or aa negative value otherwise.
 */
EXPORT_C
int 
xmlSecDSigReferenceCtxInitialize(xmlSecDSigReferenceCtxPtr dsigRefCtx, xmlSecDSigCtxPtr dsigCtx,
				xmlSecDSigReferenceOrigin origin) {
    int ret;
    
    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2(dsigRefCtx != NULL, -1);
    
    memset(dsigRefCtx, 0, sizeof(xmlSecDSigReferenceCtx));
    
    dsigRefCtx->dsigCtx = dsigCtx;
    dsigRefCtx->origin = origin;
    
    /* initializes transforms dsigRefCtx */
    ret = xmlSecTransformCtxInitialize(&(dsigRefCtx->transformCtx));
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecTransformCtxInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);   
    }
    
    /* copy enabled transforms */
    if(dsigCtx->enabledReferenceTransforms != NULL) {
	ret = xmlSecPtrListCopy(&(dsigRefCtx->transformCtx.enabledTransforms), 
				     dsigCtx->enabledReferenceTransforms);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecPtrListCopy",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);   
	}
    }    
    dsigRefCtx->transformCtx.preExecCallback = dsigCtx->referencePreExecuteCallback;
    dsigRefCtx->transformCtx.enabledUris = dsigCtx->enabledReferenceUris;

    if((dsigCtx->flags & XMLSEC_DSIG_FLAGS_USE_VISA3D_HACK) != 0) {
	dsigRefCtx->transformCtx.flags |= XMLSEC_TRANSFORMCTX_FLAGS_USE_VISA3D_HACK;
    }
    return(0);
}

/** 
 * xmlSecDSigReferenceCtxFinalize:
 * @dsigRefCtx:		the pointer to <dsig:Reference/> element processing context.
 *
 * Cleans up context object created with #xmlSecDSigReferenceCtxInitialize function.
 */
EXPORT_C
void 
xmlSecDSigReferenceCtxFinalize(xmlSecDSigReferenceCtxPtr dsigRefCtx) {
    xmlSecAssert(dsigRefCtx != NULL);

    xmlSecTransformCtxFinalize(&(dsigRefCtx->transformCtx));
    if(dsigRefCtx->id != NULL) {
	xmlFree(dsigRefCtx->id);
    }	
    if(dsigRefCtx->uri != NULL) {
	xmlFree(dsigRefCtx->uri);
    }	
    if(dsigRefCtx->type != NULL) {
	xmlFree(dsigRefCtx->type);
    }	
    memset(dsigRefCtx, 0, sizeof(xmlSecDSigReferenceCtx));
}

/**
 * xmlSecDSigReferenceCtxGetPreDigestBuffer:
 * @dsigRefCtx:		the pointer to <dsig:Reference/> element processing context.
 * 
 * Gets the results of <dsig:Reference/> node processing just before digesting
 * (valid only if #XMLSEC_DSIG_FLAGS_STORE_SIGNEDINFO_REFERENCES or
 * #XMLSEC_DSIG_FLAGS_STORE_MANIFEST_REFERENCES flas of signature context
 * is set).
 *
 * Returns pointer to the buffer or NULL if an error occurs.
 */
EXPORT_C
xmlSecBufferPtr 
xmlSecDSigReferenceCtxGetPreDigestBuffer(xmlSecDSigReferenceCtxPtr dsigRefCtx) {
    xmlSecAssert2(dsigRefCtx != NULL, NULL);
    
    return((dsigRefCtx->preDigestMemBufMethod != NULL) ? 
	    xmlSecTransformMemBufGetBuffer(dsigRefCtx->preDigestMemBufMethod) : NULL);
}

/**
 * xmlSecDSigReferenceCtxProcessNode:
 * @dsigRefCtx:		the pointer to <dsig:Reference/> element processing context.
 * @node:		the pointer to <dsig:Reference/> node.

 * The Reference Element (http://www.w3.org/TR/xmldsig-core/#sec-Reference)
 * 
 * Reference is an element that may occur one or more times. It specifies 
 * a digest algorithm and digest value, and optionally an identifier of the 
 * object being signed, the type of the object, and/or a list of transforms 
 * to be applied prior to digesting. The identification (URI) and transforms 
 * describe how the digested content (i.e., the input to the digest method) 
 * was created. The Type attribute facilitates the processing of referenced 
 * data. For example, while this specification makes no requirements over 
 * external data, an application may wish to signal that the referent is a 
 * Manifest. An optional ID attribute permits a Reference to be referenced 
 * from elsewhere.
 *
 * Returns 0 on succes or aa negative value otherwise.
 */
EXPORT_C
int 
xmlSecDSigReferenceCtxProcessNode(xmlSecDSigReferenceCtxPtr dsigRefCtx, xmlNodePtr node) {
    xmlSecTransformCtxPtr transformCtx;
    xmlNodePtr digestValueNode;
    xmlNodePtr cur;
    int ret;
    
    xmlSecAssert2(dsigRefCtx != NULL, -1);
    xmlSecAssert2(dsigRefCtx->dsigCtx != NULL, -1);
    xmlSecAssert2(dsigRefCtx->digestMethod == NULL, -1);
    xmlSecAssert2(dsigRefCtx->digestMethod == NULL, -1);
    xmlSecAssert2(dsigRefCtx->preDigestMemBufMethod == NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    xmlSecAssert2(node->doc != NULL, -1);

    transformCtx = &(dsigRefCtx->transformCtx);

    /* read attributes first */
    dsigRefCtx->uri = xmlGetProp(node, xmlSecAttrURI);
    dsigRefCtx->id  = xmlGetProp(node, xmlSecAttrId);
    dsigRefCtx->type= xmlGetProp(node, xmlSecAttrType);

    /* set start URI (and check that it is enabled!) */
    ret = xmlSecTransformCtxSetUri(transformCtx, dsigRefCtx->uri, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecTransformCtxSetUri",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "uri=%s",
		    xmlSecErrorsSafeString(dsigRefCtx->uri));
	return(-1);
    }

    /* first is optional Transforms node */
    cur = xmlSecGetNextElementNode(node->children);
    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeTransforms, xmlSecDSigNs))) {
	ret = xmlSecTransformCtxNodesListRead(transformCtx, 
					cur, xmlSecTransformUsageDSigTransform);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxNodesListRead",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"node=%s",
			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
	    return(-1);
	}	
        cur = xmlSecGetNextElementNode(cur->next);
    }

    /* insert membuf if requested */
    if(((dsigRefCtx->origin == xmlSecDSigReferenceOriginSignedInfo) &&
	((dsigRefCtx->dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_SIGNEDINFO_REFERENCES) != 0)) ||
       ((dsigRefCtx->origin == xmlSecDSigReferenceOriginManifest) &&
	((dsigRefCtx->dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_MANIFEST_REFERENCES) != 0))) {

	xmlSecAssert2(dsigRefCtx->preDigestMemBufMethod == NULL, -1);
	dsigRefCtx->preDigestMemBufMethod = xmlSecTransformCtxCreateAndAppend(
						transformCtx, 
						xmlSecTransformMemBufId);
	if(dsigRefCtx->preDigestMemBufMethod == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxCreateAndAppend",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"transform=%s",
			xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformMemBufId)));
	    return(-1);
	}
    }
        
    /* next node is required DigestMethod. */
    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDigestMethod, xmlSecDSigNs))) {
	dsigRefCtx->digestMethod = xmlSecTransformCtxNodeRead(&(dsigRefCtx->transformCtx), 
					cur, xmlSecTransformUsageDigestMethod);
	if(dsigRefCtx->digestMethod == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxNodeRead",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"node=%s",
			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
	    return(-1);	
	}	
    } else if(dsigRefCtx->dsigCtx->defSignMethodId != xmlSecTransformIdUnknown) {
	/* the dsig spec does require DigestMethod node
	 * to be present but in some case it application might decide to
	 * minimize traffic */
	dsigRefCtx->digestMethod = xmlSecTransformCtxCreateAndAppend(&(dsigRefCtx->transformCtx), 
							      dsigRefCtx->dsigCtx->defSignMethodId);
	if(dsigRefCtx->digestMethod == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxAppend",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    } else {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_INVALID_NODE,
		    "expected=%s",
		    xmlSecErrorsSafeString(xmlSecNodeDigestMethod));
	return(-1);
    }	
    dsigRefCtx->digestMethod->operation = dsigRefCtx->dsigCtx->operation;

    /* last node is required DigestValue */
	if (cur != NULL) {
		cur = xmlSecGetNextElementNode(cur->next);     
	}
    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDigestValue, xmlSecDSigNs))) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "node=%s",
		    xmlSecErrorsSafeString(xmlSecNodeDigestValue));
	return(-1);
    }
    digestValueNode = cur;
    cur = xmlSecGetNextElementNode(cur->next);     

    /* if we have something else then it's an error */
    if(cur != NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* if we need to write result to xml node then we need base64 encode result */
    if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) {	
	xmlSecTransformPtr base64Encode;
	
	/* we need to add base64 encode transform */
	base64Encode = xmlSecTransformCtxCreateAndAppend(transformCtx, xmlSecTransformBase64Id);
    	if(base64Encode == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxCreateAndAppend",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	base64Encode->operation = xmlSecTransformOperationEncode;
    }

    /* finally get transforms results */
    ret = xmlSecTransformCtxExecute(transformCtx, node->doc);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecTransformCtxExecute",
	    	    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }    
    dsigRefCtx->result = transformCtx->result;

    if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) {	
	if((dsigRefCtx->result == NULL) || (xmlSecBufferGetData(dsigRefCtx->result) == NULL)) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformCtxExecute",
	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	
	/* write signed data to xml */
	xmlNodeSetContentLen(digestValueNode,
			    xmlSecBufferGetData(dsigRefCtx->result),
			    xmlSecBufferGetSize(dsigRefCtx->result));
    if ( OOM_FLAG )
        {
        return(-1);
        }
    
	/* set success status and we are done */
	dsigRefCtx->status = xmlSecDSigStatusSucceeded;
    } else {
	/* verify SignatureValue node content */
	ret = xmlSecTransformVerifyNodeContent(dsigRefCtx->digestMethod, 
			    digestValueNode, transformCtx);
	if(ret < 0) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecTransformVerifyNodeContent",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    
        /* set status and we are done */
	if(dsigRefCtx->digestMethod->status == xmlSecTransformStatusOk) {
	    dsigRefCtx->status = xmlSecDSigStatusSucceeded;
	} else {
    	    dsigRefCtx->status = xmlSecDSigStatusInvalid;
	}
    }

    return(0);
}

/**
 * xmlSecDSigReferenceCtxDebugDump:
 * @dsigRefCtx:		the pointer to <dsig:Reference/> element processing context.
 * @output:		the pointer to output FILE.
 *
 * Prints debug information about @dsigRefCtx to @output.
 */
EXPORT_C
void 
xmlSecDSigReferenceCtxDebugDump(xmlSecDSigReferenceCtxPtr dsigRefCtx, FILE* output) {
    xmlSecAssert(dsigRefCtx != NULL);
    xmlSecAssert(dsigRefCtx->dsigCtx != NULL);
    xmlSecAssert(output != NULL);

    if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) {    
	fprintf(output, "= REFERENCE CALCULATION CONTEXT\n");
    } else {
	fprintf(output, "= REFERENCE VERIFICATION CONTEXT\n");
    }
    switch(dsigRefCtx->status) {
	case xmlSecDSigStatusUnknown:
	    fprintf(output, "== Status: unknown\n");
	    break;
	case xmlSecDSigStatusSucceeded:
	    fprintf(output, "== Status: succeeded\n");
	    break;
	case xmlSecDSigStatusInvalid:
	    fprintf(output, "== Status: invalid\n");
	    break;
    }
    if(dsigRefCtx->id != NULL) {
	fprintf(output, "== Id: \"%s\"\n", dsigRefCtx->id);
    }
    if(dsigRefCtx->uri != NULL) {
	fprintf(output, "== URI: \"%s\"\n", dsigRefCtx->uri);
    }
    if(dsigRefCtx->type != NULL) {
	fprintf(output, "== Type: \"%s\"\n", dsigRefCtx->type);
    }

    fprintf(output, "== Reference Transform Ctx:\n");
    xmlSecTransformCtxDebugDump(&(dsigRefCtx->transformCtx), output);

    if(dsigRefCtx->digestMethod != NULL) {
        fprintf(output, "== Digest Method:\n");
	xmlSecTransformDebugDump(dsigRefCtx->digestMethod, output);
    }

    if((xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx) != NULL) &&
       (xmlSecBufferGetData(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)) != NULL)) {
       
	fprintf(output, "== PreDigest data - start buffer:\n");
	fwrite(xmlSecBufferGetData(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)), 
	       xmlSecBufferGetSize(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)), 
	       1, output);
	fprintf(output, "\n== PreDigest data - end buffer\n");       
    }

    if((dsigRefCtx->result != NULL) && 
       (xmlSecBufferGetData(dsigRefCtx->result) != NULL)) {

	fprintf(output, "== Result - start buffer:\n");
	fwrite(xmlSecBufferGetData(dsigRefCtx->result), 
	       xmlSecBufferGetSize(dsigRefCtx->result), 1,
	       output);
	fprintf(output, "\n== Result - end buffer\n");
    }
}

/**
 * xmlSecDSigReferenceCtxDebugXmlDump:
 * @dsigRefCtx:		the pointer to <dsig:Reference/> element processing context.
 * @output:		the pointer to output FILE.
 *
 * Prints debug information about @dsigRefCtx to @output in output format.
 */
EXPORT_C
void 
xmlSecDSigReferenceCtxDebugXmlDump(xmlSecDSigReferenceCtxPtr dsigRefCtx, FILE* output) {
    xmlSecAssert(dsigRefCtx != NULL);
    xmlSecAssert(dsigRefCtx->dsigCtx != NULL);
    xmlSecAssert(output != NULL);

    if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) {    
	fprintf(output, "<ReferenceCalculationContext ");
    } else {
	fprintf(output, "<ReferenceVerificationContext ");
    }
    switch(dsigRefCtx->status) {
	case xmlSecDSigStatusUnknown:
	    fprintf(output, "status=\"unknown\" >\n");
	    break;
	case xmlSecDSigStatusSucceeded:
	    fprintf(output, "status=\"succeeded\" >\n");
	    break;
	case xmlSecDSigStatusInvalid:
	    fprintf(output, "status=\"invalid\" >\n");
	    break;
    }

    if(dsigRefCtx->id != NULL) {
	fprintf(output, "<Id>%s</Id>\n", dsigRefCtx->id);
    }
    if(dsigRefCtx->uri != NULL) {
	fprintf(output, "<URI>%s</URI>\n", dsigRefCtx->uri);
    }
    if(dsigRefCtx->type != NULL) {
	fprintf(output, "<Type>%s</Type>\n", dsigRefCtx->type);
    }

    fprintf(output, "<ReferenceTransformCtx>\n");
    xmlSecTransformCtxDebugXmlDump(&(dsigRefCtx->transformCtx), output);
    fprintf(output, "</ReferenceTransformCtx>\n");

    if(dsigRefCtx->digestMethod != NULL) {
        fprintf(output, "<DigestMethod>\n");
	xmlSecTransformDebugXmlDump(dsigRefCtx->digestMethod, output);
        fprintf(output, "</DigestMethod>\n");
    }

    if((dsigRefCtx->result != NULL) && 
       (xmlSecBufferGetData(dsigRefCtx->result) != NULL)) {

	fprintf(output, "<Result>");
	fwrite(xmlSecBufferGetData(dsigRefCtx->result), 
	       xmlSecBufferGetSize(dsigRefCtx->result), 1,
	       output);
	fprintf(output, "</Result>\n");
    }

    if((xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx) != NULL) &&
       (xmlSecBufferGetData(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)) != NULL)) {
       
	fprintf(output, "<PreDigestData>");
	fwrite(xmlSecBufferGetData(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)), 
	       xmlSecBufferGetSize(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)), 
	       1, output);
	fprintf(output, "</PreDigestData>\n");       
    }
    if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) {    
	fprintf(output, "</ReferenceCalculationContext>\n");
    } else {
	fprintf(output, "</ReferenceVerificationContext>\n");
    }
}


/**************************************************************************
 *
 * xmlSecDSigReferenceCtxListKlass
 *
 *************************************************************************/
static xmlSecPtrListKlass xmlSecDSigReferenceCtxListKlass = {
    BAD_CAST "dsig-reference-list",
    NULL,								/* xmlSecPtrDuplicateItemMethod duplicateItem; */
    (xmlSecPtrDestroyItemMethod)xmlSecDSigReferenceCtxDestroy,		/* xmlSecPtrDestroyItemMethod destroyItem; */
    (xmlSecPtrDebugDumpItemMethod)xmlSecDSigReferenceCtxDebugDump,	/* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
    (xmlSecPtrDebugDumpItemMethod)xmlSecDSigReferenceCtxDebugXmlDump,	/* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
};

/**
 * xmlSecDSigReferenceCtxListGetKlass:
 *
 * The <dsig:Reference/> element processing contexts list klass.
 *
 * Returns <dsig:Reference/> element processing context list klass.
 */
EXPORT_C
xmlSecPtrListId 
xmlSecDSigReferenceCtxListGetKlass(void) {
    return(&xmlSecDSigReferenceCtxListKlass);
}

#endif /* XMLSEC_NO_XMLDSIG */


