xmlsecurityengine/xmlsec/src/xmlsec_templates.c
changeset 0 e35f40988205
child 24 74f0b3eb154c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xmlsecurityengine/xmlsec/src/xmlsec_templates.c	Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,2184 @@
+/** 
+ * XML Security Library (http://www.aleksey.com/xmlsec).
+ *
+ * Creating signature and encryption templates.
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ * 
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
+ * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
+ */
+#include "xmlsec_globals.h"
+
+#include <stdlib.h>
+#include <string.h>
+ 
+#include <libxml2_tree.h>
+#include <libxml2_globals.h>
+
+#include "xmlsec_xmlsec.h"
+#include "xmlsec_xmltree.h"
+#include "xmlsec_transforms.h"
+#include "xmlsec_strings.h"
+#include "xmlsec_base64.h"
+#include "xmlsec_templates.h"
+#include "xmlsec_errors.h"
+
+//added for symbian port
+#include <libxml2_parser.h>
+
+static int useNewLine = 1;
+
+static unsigned char* dsPref = NULL;
+
+static xmlNodePtr 	xmlSecTmplAddReference		(xmlNodePtr parentNode, 
+							 xmlSecTransformId digestMethodId,
+							 const xmlChar *id, 
+							 const xmlChar *uri, 
+							 const xmlChar *type);
+static int	 	xmlSecTmplPrepareEncData	(xmlNodePtr parentNode, 
+							 xmlSecTransformId encMethodId);
+static int 		xmlSecTmplNodeWriteNsList	(xmlNodePtr parentNode, 
+							 const xmlChar** namespaces);
+EXPORT_C
+							 
+							 
+void xmlSetNewLineFlag(int aNewLine)
+    {
+    useNewLine = aNewLine;
+    }
+
+int xmlGetNewLineFlag()
+    {
+    return useNewLine;
+    }
+EXPORT_C
+
+void xmlSetPrefix(unsigned char* aPref)
+    {
+    dsPref = aPref;
+    }
+
+unsigned char* xmlGetPrefix()
+    {
+    return dsPref;
+    }
+
+/**************************************************************************
+ *
+ * <dsig:Signature/> node
+ *
+ **************************************************************************/
+/**
+ * xmlSecTmplSignatureCreate:
+ * @doc: 		the pointer to signature document or NULL; in the 
+ *			second case, application must later call @xmlSetTreeDoc
+ *			to ensure that all the children nodes have correct 
+ *			pointer to XML document.
+ * @c14nMethodId: 	the signature canonicalization method.
+ * @signMethodId: 	the signature  method.
+ * @id: 		the node id (may be NULL).
+ *
+ * Creates new <dsig:Signature/> node with the mandatory <dsig:SignedInfo/>, 
+ * <dsig:CanonicalizationMethod/>, <dsig:SignatureMethod/> and 
+ * <dsig:SignatureValue/> children and sub-children. 
+ * The application is responsible for inserting the returned node
+ * in the XML document. 
+ *
+ * Returns the pointer to newly created <dsig:Signature/> node or NULL if an 
+ * error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplSignatureCreate(xmlDocPtr doc, xmlSecTransformId c14nMethodId,
+		      xmlSecTransformId signMethodId, const xmlChar *id) {
+    xmlNodePtr signNode;
+    xmlNodePtr signedInfoNode;
+    xmlNodePtr cur;
+    xmlNsPtr ns;
+    
+    xmlSecAssert2(c14nMethodId != NULL, NULL);
+    xmlSecAssert2(c14nMethodId->href != NULL, NULL);
+    xmlSecAssert2(signMethodId != NULL, NULL);
+    xmlSecAssert2(signMethodId->href != NULL, NULL);
+    
+    /* create Signature node itself */
+    signNode = xmlNewDocNode(doc, NULL, xmlSecNodeSignature, NULL);
+    if(signNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlNewDocNode",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeSignature));
+	return(NULL);	            
+    }
+    
+    ns = xmlNewNs(signNode, xmlSecDSigNs, dsPref);
+    if(ns == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlNewNs",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "ns=%s",
+		    xmlSecErrorsSafeString(xmlSecDSigNs));
+	xmlFreeNode(signNode);
+	return(NULL);	        	
+    }
+    xmlSetNs(signNode, ns);
+    
+    if(id != NULL) {
+	    xmlAttrPtr ptr = xmlSetProp(signNode, BAD_CAST "Id", id);
+	    if ( !ptr && OOM_FLAG ) 
+	        {
+	        xmlFreeNode(signNode);
+	        return(NULL);
+	        }
+    }
+
+    /* add SignedInfo node */    
+    signedInfoNode = xmlSecAddChild(signNode, xmlSecNodeSignedInfo, xmlSecDSigNs);
+    if(signedInfoNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeSignedInfo));
+	xmlFreeNode(signNode);
+	return(NULL);	        	
+    }
+
+    /* add SignatureValue node */    
+    cur = xmlSecAddChild(signNode, xmlSecNodeSignatureValue, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeSignatureValue));
+	xmlFreeNode(signNode);
+	return(NULL);	        	
+    }
+
+    /* add CanonicaizationMethod node to SignedInfo */
+    cur = xmlSecAddChild(signedInfoNode, xmlSecNodeCanonicalizationMethod, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeCanonicalizationMethod));
+	xmlFreeNode(signNode);
+	return(NULL);	        	
+    }
+    if(xmlSetNsProp(cur, ns, xmlSecAttrAlgorithm, c14nMethodId->href) == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSetProp",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "name=%s,value=%s",
+		    xmlSecErrorsSafeString(xmlSecAttrAlgorithm),
+		    xmlSecErrorsSafeString(c14nMethodId->href));
+	xmlFreeNode(signNode);
+	return(NULL);	        	
+    }
+
+    /* add SignatureMethod node to SignedInfo */
+    cur = xmlSecAddChild(signedInfoNode, xmlSecNodeSignatureMethod, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeSignatureMethod));
+	xmlFreeNode(signNode);
+	return(NULL);	        	
+    }
+    if(xmlSetNsProp(cur, ns, xmlSecAttrAlgorithm, signMethodId->href) == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSetProp",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "name=%s,value=%s",
+		    xmlSecErrorsSafeString(xmlSecAttrAlgorithm),
+		    xmlSecErrorsSafeString(signMethodId->href));
+	xmlFreeNode(signNode);
+	return(NULL);	        	
+    }
+        
+    return(signNode);
+}
+
+/**
+ * xmlSecTmplSignatureEnsureKeyInfo:
+ * @signNode: 		the  pointer to <dsig:Signature/> node.
+ * @id: 		the node id (may be NULL).
+ *
+ * Adds (if necessary) <dsig:KeyInfo/> node to the <dsig:Signature/> 
+ * node @signNode. 
+ *
+ * Returns the pointer to newly created <dsig:KeyInfo/> node or NULL if an 
+ * error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplSignatureEnsureKeyInfo(xmlNodePtr signNode, const xmlChar *id) {
+    xmlNodePtr res;
+    int created = 0;
+    
+    xmlSecAssert2(signNode != NULL, NULL);
+
+    res = xmlSecFindChild(signNode, xmlSecNodeKeyInfo, xmlSecDSigNs);
+    if(res == NULL) {
+	xmlNodePtr signValueNode;
+    
+        signValueNode = xmlSecFindChild(signNode, xmlSecNodeSignatureValue, xmlSecDSigNs);
+	if(signValueNode == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+			xmlSecErrorsSafeString(xmlSecNodeSignatureValue),
+		        XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(NULL);	
+	}
+
+	res = xmlSecAddNextSibling(signValueNode, xmlSecNodeKeyInfo, xmlSecDSigNs);
+	if(res == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+			"xmlSecAddNextSibling",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeKeyInfo));
+	    return(NULL);	        	
+	}
+	created = 1;
+    }
+    if(id != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrId, id);
+        if (!ptr && OOM_FLAG) 
+            {
+            if (created) 
+                {
+                xmlUnlinkNode(res);
+    	        xmlFreeNode(res);
+                }
+            return(NULL);
+            }
+    }
+    return(res);        
+}         
+
+/**
+ * xmlSecTmplSignatureAddReference:
+ * @signNode: 		the pointer to <dsig:Signature/> node.
+ * @digestMethodId:	the reference digest method.
+ * @id: 		the node id (may be NULL).
+ * @uri: 		the reference node uri (may be NULL).
+ * @type: 		the reference node type (may be NULL).
+ *
+ * Adds <dsig:Reference/> node with given URI (@uri), Id (@id) and 
+ * Type (@type) attributes and the required children <dsig:DigestMethod/> and
+ * <dsig:DigestValue/> to the <dsig:SignedInfo/> child of @signNode. 
+ *
+ * Returns the pointer to newly created <dsig:Reference/> node or NULL 
+ * if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr	
+xmlSecTmplSignatureAddReference(xmlNodePtr signNode, xmlSecTransformId digestMethodId,
+		    const xmlChar *id, const xmlChar *uri, const xmlChar *type) {
+    xmlNodePtr signedInfoNode;
+    
+    xmlSecAssert2(signNode != NULL, NULL);
+    xmlSecAssert2(digestMethodId != NULL, NULL);
+    xmlSecAssert2(digestMethodId->href != NULL, NULL);
+
+    signedInfoNode = xmlSecFindChild(signNode, xmlSecNodeSignedInfo, xmlSecDSigNs);
+    if(signedInfoNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeSignedInfo),
+		    XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);	
+    }
+    
+    return(xmlSecTmplAddReference(signedInfoNode, digestMethodId, id, uri, type));
+}
+
+static xmlNodePtr 
+xmlSecTmplAddReference(xmlNodePtr parentNode, xmlSecTransformId digestMethodId,
+		    const xmlChar *id, const xmlChar *uri, const xmlChar *type) {    
+    xmlNodePtr res;
+    xmlNodePtr cur;
+    int error = 0;
+    
+    xmlSecAssert2(parentNode != NULL, NULL);
+    xmlSecAssert2(digestMethodId != NULL, NULL);
+    xmlSecAssert2(digestMethodId->href != NULL, NULL);
+
+    /* add Reference node */
+    res = xmlSecAddChild(parentNode, xmlSecNodeReference, xmlSecDSigNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeReference));
+	return(NULL);
+    }
+
+    /* set Reference node attributes */
+    if(id != NULL) {
+	xmlAttrPtr ptr = xmlSetNsProp(res, res->ns, xmlSecAttrId, id);
+    error = error || !ptr;
+    }
+    if(type != NULL) {
+	xmlAttrPtr ptr = xmlSetNsProp(res, res->ns, xmlSecAttrType, type);
+    error = error || !ptr;
+    }
+    if(uri != NULL) {
+	xmlAttrPtr ptr = xmlSetNsProp(res, res->ns, xmlSecAttrURI, uri);
+    error = error || !ptr;
+    }
+    if (error && OOM_FLAG) 
+        {
+ 	    xmlUnlinkNode(res);
+	    xmlFreeNode(res); 
+	    return(NULL);      
+        }
+
+    /* add DigestMethod node and set algorithm */    
+    cur = xmlSecAddChild(res, xmlSecNodeDigestMethod, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeDigestMethod));
+	xmlUnlinkNode(res);
+	xmlFreeNode(res);
+	return(NULL);	        	
+    }
+    if(xmlSetNsProp(cur, cur->ns, xmlSecAttrAlgorithm, digestMethodId->href) == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSetProp",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "name=%s,value=%s",
+		    xmlSecErrorsSafeString(xmlSecAttrAlgorithm),
+		    xmlSecErrorsSafeString(digestMethodId->href));
+	xmlUnlinkNode(res);
+	xmlFreeNode(res);
+	return(NULL);	        	
+    }
+
+    /* add DigestValue node */    
+    cur = xmlSecAddChild(res, xmlSecNodeDigestValue, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeDigestValue));
+	xmlUnlinkNode(res);
+	xmlFreeNode(res);
+	return(NULL);	        	
+    }
+    
+    return(res);    
+}
+
+/**
+ * xmlSecTmplSignatureAddObject:
+ * @signNode: 		the pointer to <dsig:Signature/> node.
+ * @id: 		the node id (may be NULL).
+ * @mimeType: 		the object mime type (may be NULL).
+ * @encoding: 		the object encoding (may be NULL).
+ *
+ * Adds <dsig:Object/> node to the <dsig:Signature/> node @signNode. 
+ *
+ * Returns the pointer to newly created <dsig:Object/> node or NULL 
+ * if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplSignatureAddObject(xmlNodePtr signNode, const xmlChar *id, 
+			 const xmlChar *mimeType, const xmlChar *encoding) {
+    xmlNodePtr res;
+    int error = 0;
+
+    xmlSecAssert2(signNode != NULL, NULL);
+    
+    res = xmlSecAddChild(signNode, xmlSecNodeObject, xmlSecDSigNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeObject));
+	return(NULL);	        	
+    }
+    if(id != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrId, id);
+    error = error || !ptr;
+    }
+    if(mimeType != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrMimeType, mimeType);
+    error = error || !ptr;
+    }
+    if(encoding != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrEncoding, encoding);
+    error = error || !ptr;
+    }
+    if (error && OOM_FLAG) 
+        {
+        xmlUnlinkNode(res);
+	    xmlFreeNode(res);
+	    return(NULL);
+        }
+    
+    return(res);        
+}
+
+/** 
+ * xmlSecTmplSignatureGetSignMethodNode:
+ * @signNode:		the pointer to <dsig:Signature /> node.
+ *
+ * Gets pointer to <dsig:SignatureMethod/> child of <dsig:KeyInfo/> node.
+ *
+ * Returns pointer to <dsig:SignatureMethod /> node or NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr 
+xmlSecTmplSignatureGetSignMethodNode(xmlNodePtr signNode) {
+    xmlNodePtr signedInfoNode;
+    
+    xmlSecAssert2(signNode != NULL, NULL);
+    
+    signedInfoNode = xmlSecFindChild(signNode, xmlSecNodeSignedInfo, xmlSecDSigNs);
+    if(signedInfoNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeSignedInfo),
+		    XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);	
+    }
+    return(xmlSecFindChild(signedInfoNode, xmlSecNodeSignatureMethod, xmlSecDSigNs));
+}
+
+/** 
+ * xmlSecTmplSignatureGetC14NMethodNode:
+ * @signNode:		the pointer to <dsig:Signature /> node.
+ *
+ * Gets pointer to <dsig:CanonicalizationMethod/> child of <dsig:KeyInfo/> node.
+ *
+ * Returns pointer to <dsig:CanonicalizationMethod /> node or NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr 
+xmlSecTmplSignatureGetC14NMethodNode(xmlNodePtr signNode) {
+    xmlNodePtr signedInfoNode;
+    
+    xmlSecAssert2(signNode != NULL, NULL);
+    
+    signedInfoNode = xmlSecFindChild(signNode, xmlSecNodeSignedInfo, xmlSecDSigNs);
+    if(signedInfoNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeSignedInfo),
+		    XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);	
+    }
+    return(xmlSecFindChild(signedInfoNode, xmlSecNodeCanonicalizationMethod, xmlSecDSigNs));
+}
+
+/**
+ * xmlSecTmplReferenceAddTransform:
+ * @referenceNode: 		the pointer to <dsig:Reference/> node.
+ * @transformId: 		the transform method id.
+ *
+ * Adds <dsig:Transform/> node to the <dsig:Reference/> node @referenceNode.
+ * 
+ * Returns the pointer to newly created <dsig:Transform/> node or NULL if an 
+ * error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplReferenceAddTransform(xmlNodePtr referenceNode, xmlSecTransformId transformId) {
+    xmlNodePtr transformsNode;
+    xmlNodePtr res;
+    
+    xmlSecAssert2(referenceNode != NULL, NULL);
+    xmlSecAssert2(transformId != NULL, NULL);
+    xmlSecAssert2(transformId->href != NULL, NULL);
+
+    /* do we need to create Transforms node first */
+    transformsNode = xmlSecFindChild(referenceNode, xmlSecNodeTransforms, xmlSecDSigNs);
+    if(transformsNode == NULL) {
+	xmlNodePtr tmp;
+	
+	tmp = xmlSecGetNextElementNode(referenceNode->children);
+	if(tmp == NULL) {
+	    transformsNode = xmlSecAddChild(referenceNode, xmlSecNodeTransforms, xmlSecDSigNs);
+	} else {
+	    transformsNode = xmlSecAddPrevSibling(tmp, xmlSecNodeTransforms, xmlSecDSigNs);
+	}   
+	if(transformsNode == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecAddChild or xmlSecAddPrevSibling",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeTransforms));
+	    return(NULL);	        	
+	}
+    }
+
+    res = xmlSecAddChild(transformsNode, xmlSecNodeTransform, xmlSecDSigNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeTransform));
+	return(NULL);	        	
+    }
+
+    if(xmlSetNsProp(res, res->ns, xmlSecAttrAlgorithm, transformId->href) == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSetProp",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "name=%s,value=%s",
+		    xmlSecErrorsSafeString(xmlSecAttrAlgorithm),
+		    xmlSecErrorsSafeString(transformId->href));
+	xmlUnlinkNode(res);
+	xmlFreeNode(res);
+	return(NULL);	        	
+    }
+
+    return(res);    
+}
+
+/**
+ * xmlSecTmplObjectAddSignProperties:
+ * @objectNode: 	the  pointer to <dsig:Object/> node.
+ * @id: 		the node id (may be NULL).
+ * @target: 		the Target  (may be NULL).
+ *
+ * Adds <dsig:SignatureProperties/> node to the <dsig:Object/> node @objectNode.
+ *
+ * Returns the pointer to newly created <dsig:SignatureProperties/> node or NULL 
+ * if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr		
+xmlSecTmplObjectAddSignProperties(xmlNodePtr objectNode, const xmlChar *id, const xmlChar *target) {
+    xmlNodePtr res;
+    int error = 0;
+
+    xmlSecAssert2(objectNode != NULL, NULL);
+
+    res = xmlSecAddChild(objectNode, xmlSecNodeSignatureProperties, xmlSecDSigNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeSignatureProperties));
+	return(NULL);	        	
+    }
+    if(id != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrId, id);
+    error = error || !ptr;
+    }
+    if(target != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrTarget, target);
+    error = error || !ptr;
+    }
+    if (error && OOM_FLAG) 
+        {
+        xmlUnlinkNode(res);
+	    xmlFreeNode(res);
+	    return(NULL);
+        }
+    return(res);
+}
+
+/**
+ * xmlSecTmplObjectAddManifest:
+ * @objectNode: 	the  pointer to <dsig:Object/> node.
+ * @id: 		the node id (may be NULL).
+ *
+ * Adds <dsig:Manifest/> node to the <dsig:Object/> node @objectNode.
+ *
+ * Returns the pointer to newly created <dsig:Manifest/> node or NULL 
+ * if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplObjectAddManifest(xmlNodePtr objectNode,  const xmlChar *id) {
+    xmlNodePtr res;
+
+    xmlSecAssert2(objectNode != NULL, NULL);
+
+    res = xmlSecAddChild(objectNode, xmlSecNodeManifest, xmlSecDSigNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeManifest));
+	return(NULL);	        	
+    }
+    if(id != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrId, id);
+        if (!ptr && OOM_FLAG) 
+            {
+            xmlUnlinkNode(res);
+	        xmlFreeNode(res);
+	        return(NULL);
+            }
+    }
+    return(res);
+}
+
+/**
+ * xmlSecTmplManifestAddReference:
+ * @manifestNode: 	the pointer to <dsig:Manifest/> node.
+ * @digestMethodId:	the reference digest method.
+ * @id: 		the node id (may be NULL).
+ * @uri: 		the reference node uri (may be NULL).
+ * @type: 		the reference node type (may be NULL).
+ *
+ * Adds <dsig:Reference/> node with specified URI (@uri), Id (@id) and 
+ * Type (@type) attributes and the required children <dsig:DigestMethod/> and
+ * <dsig:DigestValue/> to the <dsig:Manifest/> node @manifestNode.
+ *
+ * Returns the pointer to newly created <dsig:Reference/> node or NULL 
+ * if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr 
+xmlSecTmplManifestAddReference(xmlNodePtr manifestNode, xmlSecTransformId digestMethodId,
+			      const xmlChar *id, const xmlChar *uri, const xmlChar *type) {
+    return(xmlSecTmplAddReference(manifestNode, digestMethodId, id, uri, type));
+}
+
+/**************************************************************************
+ *
+ * <enc:EncryptedData/> node
+ *
+ **************************************************************************/
+/** 
+ * xmlSecTmplEncDataCreate:
+ * @doc: 		the pointer to signature document or NULL; in the later
+ *			case, application must later call @xmlSetTreeDoc to ensure 
+ *			that all the children nodes have correct pointer to XML document.
+ * @encMethodId:	the encryption method (may be NULL).
+ * @id: 		the Id attribute (optional).
+ * @type: 		the Type attribute (optional)
+ * @mimeType: 		the MimeType attribute (optional)
+ * @encoding: 		the Encoding attribute (optional)
+ *
+ * Creates new <enc:EncryptedData /> node for encryption template. 
+ *
+ * Returns the pointer newly created  <enc:EncryptedData/> node or NULL 
+ * if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr		
+xmlSecTmplEncDataCreate(xmlDocPtr doc, xmlSecTransformId encMethodId,
+			    const xmlChar *id, const xmlChar *type,
+			    const xmlChar *mimeType, const xmlChar *encoding) {
+    xmlNodePtr encNode;
+    xmlNsPtr ns;
+    int error = 0;
+    
+    encNode = xmlNewDocNode(doc, NULL, xmlSecNodeEncryptedData, NULL);
+    if(encNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlNewDocNode",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeEncryptedData));
+	return(NULL);	        
+    }
+    
+    ns = xmlNewNs(encNode, xmlSecEncNs, NULL);
+    if(ns == NULL) {
+        xmlFreeNode(encNode);
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlNewNs",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "ns=%s",
+		    xmlSecErrorsSafeString(xmlSecEncNs));
+	return(NULL);	        	
+    }
+    xmlSetNs(encNode, ns);
+    
+    if(id != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(encNode, xmlSecAttrId, id);
+    error = error || !ptr;
+    }
+    if(type != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(encNode, xmlSecAttrType, type);
+    error = error || !ptr;
+    }
+    if(mimeType != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(encNode, xmlSecAttrMimeType, mimeType);
+    error = error || !ptr;
+    }
+    if(encoding != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(encNode, xmlSecAttrEncoding, encoding);
+    error = error || !ptr;
+    }
+    if (error && OOM_FLAG) 
+        {
+	    xmlFreeNode(encNode);
+	    return(NULL);
+        }
+    
+    if(xmlSecTmplPrepareEncData(encNode, encMethodId) < 0) {
+	xmlFreeNode(encNode);
+	return(NULL);
+    }
+    return(encNode);
+}
+
+static int  
+xmlSecTmplPrepareEncData(xmlNodePtr parentNode, xmlSecTransformId encMethodId) {
+    xmlNodePtr cur;
+    
+    xmlSecAssert2(parentNode != NULL, -1);
+    xmlSecAssert2((encMethodId == NULL) || (encMethodId->href != NULL), -1);
+    
+    /* add EncryptionMethod node if requested */
+    if(encMethodId != NULL) {
+	cur = xmlSecAddChild(parentNode, xmlSecNodeEncryptionMethod, xmlSecEncNs);
+	if(cur == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecAddChild",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeEncryptionMethod));
+	    return(-1);        	
+	}
+	if(xmlSetProp(cur, xmlSecAttrAlgorithm, encMethodId->href) == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+			"xmlSetProp",
+		        XMLSEC_ERRORS_R_XML_FAILED,
+			"name=%s,value=%s",
+		        xmlSecErrorsSafeString(xmlSecAttrAlgorithm),
+			xmlSecErrorsSafeString(encMethodId->href));
+	    return(-1); 	
+	}	
+    }
+        
+    /* and CipherData node */
+    cur = xmlSecAddChild(parentNode, xmlSecNodeCipherData, xmlSecEncNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeCipherData));
+	return(-1);	        	
+    }
+    
+    return(0);
+}
+
+
+/** 
+ * xmlSecTmplEncDataEnsureKeyInfo:
+ * @encNode: 		the pointer to <enc:EncryptedData/> node.
+ * @id:			the Id attrbibute (optional).
+ *
+ * Adds <dsig:KeyInfo/> to the  <enc:EncryptedData/> node @encNode.
+ *
+ * Returns the pointer to newly created <dsig:KeyInfo/> node or 
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplEncDataEnsureKeyInfo(xmlNodePtr encNode, const xmlChar* id) {
+    xmlNodePtr res;
+    
+    xmlSecAssert2(encNode != NULL, NULL);
+
+    res = xmlSecFindChild(encNode, xmlSecNodeKeyInfo, xmlSecDSigNs);
+    if(res == NULL) {
+	xmlNodePtr cipherDataNode;
+    
+        cipherDataNode = xmlSecFindChild(encNode, xmlSecNodeCipherData, xmlSecEncNs);
+	if(cipherDataNode == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+			xmlSecErrorsSafeString(xmlSecNodeCipherData),
+		        XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(NULL);	
+	}
+
+	res = xmlSecAddPrevSibling(cipherDataNode, xmlSecNodeKeyInfo, xmlSecDSigNs);
+	if(res == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+			"xmlSecAddPrevSibling",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeKeyInfo));
+	    return(NULL);	        	
+	}
+    }
+    if(id != NULL) {
+	    xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrId, id);
+        if (!ptr && OOM_FLAG) 
+            {
+            xmlUnlinkNode(res);
+    	    xmlFreeNode(res);
+    	    return(NULL);
+            }
+    }
+    return(res);        
+}
+
+/** 
+ * xmlSecTmplEncDataEnsureEncProperties:
+ * @encNode: 		the pointer to <enc:EncryptedData/> node.
+ * @id: 		the Id attribute (optional).
+ *
+ * Adds <enc:EncryptionProperties/> node to the <enc:EncryptedData/> 
+ * node @encNode.
+ *
+ * Returns the pointer to newly created <enc:EncryptionProperties/> node or 
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplEncDataEnsureEncProperties(xmlNodePtr encNode, const xmlChar *id) {
+    xmlNodePtr res;
+    int created = 0;
+
+    xmlSecAssert2(encNode != NULL, NULL);
+
+    res = xmlSecFindChild(encNode, xmlSecNodeEncryptionProperties, xmlSecEncNs);
+    if(res == NULL) {
+	res = xmlSecAddChild(encNode, xmlSecNodeEncryptionProperties, xmlSecEncNs);
+	if(res == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecAddChild",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeEncryptionProperties));
+	    return(NULL);	        	
+	}
+	created = 1;
+    }
+
+    if(id != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrId, id);
+        if (!ptr && OOM_FLAG) 
+            {
+            if (created) 
+                {
+                xmlUnlinkNode(res);
+        	    xmlFreeNode(res);
+                }
+            return(NULL);
+            }
+    }
+    
+    return(res);
+}
+
+/** 
+ * xmlSecTmplEncDataAddEncProperty:
+ * @encNode: 		the pointer to <enc:EncryptedData/> node.
+ * @id: 		the Id attribute (optional).
+ * @target: 		the Target attribute (optional).
+ *
+ * Adds <enc:EncryptionProperty/> node (and the parent 
+ * <enc:EncryptionProperties/> node if required) to the 
+ * <enc:EncryptedData/> node @encNode.
+ *
+ * Returns the pointer to newly created <enc:EncryptionProperty/> node or 
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr	
+xmlSecTmplEncDataAddEncProperty(xmlNodePtr encNode, const xmlChar *id, const xmlChar *target) {
+    xmlNodePtr encProps;
+    xmlNodePtr res;
+    int error = 0;
+        
+    xmlSecAssert2(encNode != NULL, NULL);
+
+    encProps = xmlSecTmplEncDataEnsureEncProperties(encNode, NULL);
+    if(encProps == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTmplEncDataEnsureEncProperties",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);	
+    }
+
+    res = xmlSecAddChild(encProps, xmlSecNodeEncryptionProperty, xmlSecEncNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeEncryptionProperty));
+	return(NULL);	
+    }
+    if(id != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrId, id);
+    error = error || !ptr;
+    }
+    if(target != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrTarget, target);
+    error = error || !ptr;
+    }
+    if (error && OOM_FLAG) 
+        {
+        xmlUnlinkNode(res);
+	    xmlFreeNode(res);
+	    return(NULL);
+        }
+    
+    return(res);
+}
+
+/** 
+ * xmlSecTmplEncDataEnsureCipherValue:
+ * @encNode: 		the pointer to <enc:EncryptedData/> node.
+ *
+ * Adds <enc:CipherValue/> to the <enc:EncryptedData/> node @encNode.
+ *
+ * Returns the pointer to newly created <enc:CipherValue/> node or 
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplEncDataEnsureCipherValue(xmlNodePtr encNode) {
+    xmlNodePtr cipherDataNode;
+    xmlNodePtr res, tmp;
+        
+    xmlSecAssert2(encNode != NULL, NULL);
+
+    cipherDataNode = xmlSecFindChild(encNode, xmlSecNodeCipherData, xmlSecEncNs);
+    if(cipherDataNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeCipherData),
+		    XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);	
+    }
+
+    /* check that we don;t have CipherReference node */
+    tmp = xmlSecFindChild(cipherDataNode, xmlSecNodeCipherReference, xmlSecEncNs);
+    if(tmp != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeCipherReference),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);	
+    }
+
+    res = xmlSecFindChild(cipherDataNode, xmlSecNodeCipherValue, xmlSecEncNs);
+    if(res == NULL) {
+	res = xmlSecAddChild(cipherDataNode, xmlSecNodeCipherValue, xmlSecEncNs);
+	if(res == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecAddChild",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeCipherValue));
+	    return(NULL);	        	
+	}
+    }
+        
+    return(res);
+}
+
+/** 
+ * xmlSecTmplEncDataEnsureCipherReference:
+ * @encNode: 		the pointer to <enc:EncryptedData/> node.
+ * @uri: 		the URI attribute (may be NULL).
+ *
+ * Adds <enc:CipherReference/> node with specified URI attribute @uri
+ * to the <enc:EncryptedData/> node @encNode.
+ *
+ * Returns the pointer to newly created <enc:CipherReference/> node or 
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplEncDataEnsureCipherReference(xmlNodePtr encNode, const xmlChar *uri) {
+    xmlNodePtr cipherDataNode;
+    xmlNodePtr res, tmp;
+    int created = 1;
+        
+    xmlSecAssert2(encNode != NULL, NULL);
+
+    cipherDataNode = xmlSecFindChild(encNode, xmlSecNodeCipherData, xmlSecEncNs);
+    if(cipherDataNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeCipherData),
+		    XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);	
+    }
+
+    /* check that we don;t have CipherValue node */
+    tmp = xmlSecFindChild(cipherDataNode, xmlSecNodeCipherValue, xmlSecEncNs);
+    if(tmp != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeCipherValue),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);	
+    }
+
+    res = xmlSecFindChild(cipherDataNode, xmlSecNodeCipherReference, xmlSecEncNs);
+    if(res == NULL) {
+	res = xmlSecAddChild(cipherDataNode, xmlSecNodeCipherReference, xmlSecEncNs);
+	if(res == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecAddChild",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeCipherReference));
+	    return(NULL);	        	
+	}
+	created = 1;
+    }
+    
+    if(uri != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrURI, uri);
+        if (!ptr && OOM_FLAG) 
+            {
+            if (created) 
+                {
+                xmlUnlinkNode(res);
+        	    xmlFreeNode(res);
+                }
+            return(NULL);
+            }
+    }
+    
+    return(res);
+}
+
+/** 
+ * xmlSecTmplEncDataGetEncMethodNode:
+ * @encNode:		the pointer to <enc:EcnryptedData /> node.
+ *
+ * Gets pointer to <enc:EncrytpionMethod/> node.
+ *
+ * Returns pointer to <enc:EncryptionMethod /> node or NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr 
+xmlSecTmplEncDataGetEncMethodNode(xmlNodePtr encNode) {
+    xmlSecAssert2(encNode != NULL, NULL);
+
+    return(xmlSecFindChild(encNode, xmlSecNodeEncryptionMethod, xmlSecEncNs));
+}
+
+/** 
+ * xmlSecTmplCipherReferenceAddTransform:
+ * @cipherReferenceNode: 	the pointer to <enc:CipherReference/> node.
+ * @transformId: 		the transform id.
+ *
+ * Adds <dsig:Transform/> node (and the parent <dsig:Transforms/> node)
+ * with specified transform methods @transform to the <enc:CipherReference/>
+ * child node of the <enc:EncryptedData/> node @encNode.
+ *
+ * Returns the pointer to newly created <dsig:Transform/> node or 
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplCipherReferenceAddTransform(xmlNodePtr cipherReferenceNode, 
+				  xmlSecTransformId transformId) {
+    xmlNodePtr transformsNode;
+    xmlNodePtr res;
+
+    xmlSecAssert2(cipherReferenceNode != NULL, NULL);
+    xmlSecAssert2(transformId != NULL, NULL);    
+    xmlSecAssert2(transformId->href != NULL, NULL);    
+
+    transformsNode = xmlSecFindChild(cipherReferenceNode, xmlSecNodeTransforms, xmlSecEncNs);
+    if(transformsNode == NULL) {
+	transformsNode = xmlSecAddChild(cipherReferenceNode, xmlSecNodeTransforms, xmlSecEncNs);
+	if(transformsNode == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecAddChild",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeTransforms));
+	    return(NULL);	
+	}
+    }
+    
+    res = xmlSecAddChild(transformsNode,  xmlSecNodeTransform, xmlSecDSigNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeTransform));
+	return(NULL);	
+    }
+    
+    if(xmlSetProp(res, xmlSecAttrAlgorithm, transformId->href) == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSetProp",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "name=%s,value=%s",
+		    xmlSecErrorsSafeString(xmlSecAttrAlgorithm),
+		    xmlSecErrorsSafeString(transformId->href));
+	xmlUnlinkNode(res);
+	xmlFreeNode(res);
+	return(NULL);	        	
+    }
+    
+    return(res);
+}
+
+
+/***********************************************************************
+ *
+ * <enc:EncryptedKey> node
+ *
+ **********************************************************************/ 
+
+/** 
+ * xmlSecTmplReferenceListAddDataReference:
+ * @encNode: 	                the pointer to <enc:EncryptedKey/> node.
+ * @uri:                        uri to reference (optional)
+ *
+ * Adds <enc:DataReference/> and the parent <enc:ReferenceList/> node (if needed).
+ *
+ * Returns the pointer to newly created <enc:DataReference/> node or 
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplReferenceListAddDataReference(xmlNodePtr encNode, const xmlChar *uri) {
+    xmlNodePtr refListNode, res;
+
+    xmlSecAssert2(encNode != NULL, NULL);
+    
+    refListNode = xmlSecFindChild(encNode, xmlSecNodeReferenceList, xmlSecEncNs);
+    if(refListNode == NULL) {
+	refListNode = xmlSecAddChild(encNode, xmlSecNodeReferenceList, xmlSecEncNs);
+	if(refListNode == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecAddChild",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeReferenceList));
+	    return(NULL);	
+	}
+    }
+    
+    res = xmlSecAddChild(refListNode,  xmlSecNodeDataReference, xmlSecEncNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeDataReference));
+	return(NULL);	
+    }
+ 
+    if(uri != NULL) {
+        if(xmlSetProp(res, xmlSecAttrURI, uri) == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+		        "xmlSetProp",
+		        XMLSEC_ERRORS_R_XML_FAILED,
+		        "name=%s,value=%s",
+		        xmlSecErrorsSafeString(xmlSecAttrURI),
+		        xmlSecErrorsSafeString(uri));
+	    xmlUnlinkNode(res);
+	    xmlFreeNode(res);
+	    return(NULL);	        	
+        }
+    }
+
+    return(res);
+}
+
+/** 
+ * xmlSecTmplReferenceListAddKeyReference:
+ * @encNode: 	                the pointer to <enc:EncryptedKey/> node.
+ * @uri:                        uri to reference (optional)
+ *
+ * Adds <enc:KeyReference/> and the parent <enc:ReferenceList/> node (if needed).
+ *
+ * Returns the pointer to newly created <enc:KeyReference/> node or 
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplReferenceListAddKeyReference(xmlNodePtr encNode, const xmlChar *uri) {
+    xmlNodePtr refListNode, res;
+
+    xmlSecAssert2(encNode != NULL, NULL);
+    
+    refListNode = xmlSecFindChild(encNode, xmlSecNodeReferenceList, xmlSecEncNs);
+    if(refListNode == NULL) {
+	refListNode = xmlSecAddChild(encNode, xmlSecNodeReferenceList, xmlSecEncNs);
+	if(refListNode == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecAddChild",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeReferenceList));
+	    return(NULL);	
+	}
+    }
+    
+    res = xmlSecAddChild(refListNode,  xmlSecNodeKeyReference, xmlSecEncNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeKeyReference));
+	return(NULL);	
+    }
+ 
+    if(uri != NULL) {
+        if(xmlSetProp(res, xmlSecAttrURI, uri) == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+		        "xmlSetProp",
+		        XMLSEC_ERRORS_R_XML_FAILED,
+		        "name=%s,value=%s",
+		        xmlSecErrorsSafeString(xmlSecAttrURI),
+		        xmlSecErrorsSafeString(uri));
+	    xmlUnlinkNode(res);
+	    xmlFreeNode(res);
+	    return(NULL);	        	
+        }
+    }
+
+    return(res);
+}
+
+
+/**************************************************************************
+ *
+ * <dsig:KeyInfo/> node
+ *
+ **************************************************************************/
+
+/**
+ * xmlSecTmplKeyInfoAddKeyName:
+ * @keyInfoNode: 	the pointer to <dsig:KeyInfo/> node.
+ * @name:		the key name (optional).	
+ *
+ * Adds <dsig:KeyName/> node to the <dsig:KeyInfo/> node @keyInfoNode.
+ *
+ * Returns the pointer to the newly created <dsig:KeyName/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr	
+xmlSecTmplKeyInfoAddKeyName(xmlNodePtr keyInfoNode, const xmlChar* name) {
+    xmlNodePtr res;
+
+    xmlSecAssert2(keyInfoNode != NULL, NULL);
+        
+    res = xmlSecAddChild(keyInfoNode, xmlSecNodeKeyName, xmlSecDSigNs); 
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeKeyName));
+	return(NULL);	
+    }
+    if(name != NULL) {
+	xmlNodeSetContent(res, name);
+    if ( OOM_FLAG ) 
+        {
+        xmlUnlinkNode(res);
+	    xmlFreeNode(res);        
+        return(NULL);
+        }
+    }
+    return(res);
+}
+
+/**
+ * xmlSecTmplKeyInfoAddKeyValue:
+ * @keyInfoNode: 	the pointer to <dsig:KeyInfo/> node.
+ *
+ * Adds <dsig:KeyValue/> node to the <dsig:KeyInfo/> node @keyInfoNode.
+ *
+ * Returns the pointer to the newly created <dsig:KeyValue/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplKeyInfoAddKeyValue(xmlNodePtr keyInfoNode) {
+    xmlNodePtr res;
+
+    xmlSecAssert2(keyInfoNode != NULL, NULL);
+        
+    res = xmlSecAddChild(keyInfoNode, xmlSecNodeKeyValue, xmlSecDSigNs); 
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeKeyValue));
+	return(NULL);	
+    }
+    
+    return(res);
+}
+
+/**
+ * xmlSecTmplKeyInfoAddX509Data:
+ * @keyInfoNode: 	the pointer to <dsig:KeyInfo/> node.
+ *
+ * Adds <dsig:X509Data/> node to the <dsig:KeyInfo/> node @keyInfoNode.
+ *
+ * Returns the pointer to the newly created <dsig:X509Data/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplKeyInfoAddX509Data(xmlNodePtr keyInfoNode) {
+    xmlNodePtr res;
+
+    xmlSecAssert2(keyInfoNode != NULL, NULL);
+        
+    res = xmlSecAddChild(keyInfoNode, xmlSecNodeX509Data, xmlSecDSigNs); 
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeX509Data));
+	return(NULL);	
+    }
+    
+    return(res);
+}
+
+/**
+ * xmlSecTmplKeyInfoAddRetrievalMethod:
+ * @keyInfoNode: 	the pointer to <dsig:KeyInfo/> node.
+ * @uri: 		the URI attribute (optional).
+ * @type: 		the Type attribute(optional).
+ *
+ * Adds <dsig:RetrievalMethod/> node to the <dsig:KeyInfo/> node @keyInfoNode.
+ *
+ * Returns the pointer to the newly created <dsig:RetrievalMethod/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplKeyInfoAddRetrievalMethod(xmlNodePtr keyInfoNode, const xmlChar *uri,
+			     const xmlChar *type) {
+    xmlNodePtr res;
+    int error = 0;
+
+    xmlSecAssert2(keyInfoNode != NULL, NULL);
+        
+    res = xmlSecAddChild(keyInfoNode, xmlSecNodeRetrievalMethod, xmlSecDSigNs); 
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeRetrievalMethod));
+	return(NULL);	
+    }
+    
+    if(uri != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrURI, uri);
+    error = error || !ptr;
+    }
+    if(type != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(res, xmlSecAttrType, type);
+    error = error || !ptr;
+    }
+    if (error && OOM_FLAG) 
+        {
+        xmlUnlinkNode(res);
+	    xmlFreeNode(res);
+	    return(NULL);
+        }
+    return(res);
+}
+
+/**
+ * xmlSecTmplRetrievalMethodAddTransform:
+ * @retrMethodNode: 	the pointer to <dsig:RetrievalMethod/> node.
+ * @transformId: 	the transform id.
+ * 
+ * Adds <dsig:Transform/> node (and the parent <dsig:Transforms/> node
+ * if required) to the <dsig:RetrievalMethod/> node @retrMethod.
+ *
+ * Returns the pointer to the newly created <dsig:Transforms/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr
+xmlSecTmplRetrievalMethodAddTransform(xmlNodePtr retrMethodNode, xmlSecTransformId transformId) {
+    xmlNodePtr transformsNode;
+    xmlNodePtr res;
+
+    xmlSecAssert2(retrMethodNode != NULL, NULL);
+    xmlSecAssert2(transformId != NULL, NULL);    
+    xmlSecAssert2(transformId->href != NULL, NULL);    
+
+    transformsNode = xmlSecFindChild(retrMethodNode, xmlSecNodeTransforms, xmlSecDSigNs);
+    if(transformsNode == NULL) {
+	transformsNode = xmlSecAddChild(retrMethodNode, xmlSecNodeTransforms, xmlSecDSigNs);
+	if(transformsNode == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecAddChild",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeTransforms));
+	    return(NULL);	
+	}
+    }
+    
+    res = xmlSecAddChild(transformsNode,  xmlSecNodeTransform, xmlSecDSigNs);
+    if(res == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeTransform));
+	return(NULL);	
+    }
+    
+    if(xmlSetProp(res, xmlSecAttrAlgorithm, transformId->href) == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSetProp",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "name=%s,value=%s",
+		    xmlSecErrorsSafeString(xmlSecAttrAlgorithm),
+		    xmlSecErrorsSafeString(transformId->href));
+	xmlUnlinkNode(res);
+	xmlFreeNode(res);
+	return(NULL);	        	
+    }
+    
+    return(res);
+}
+
+
+/**
+ * xmlSecTmplKeyInfoAddEncryptedKey:
+ * @keyInfoNode: 	the pointer to <dsig:KeyInfo/> node.
+ * @encMethodId:	the encryption method (optional).
+ * @id: 		the Id attribute (optional).
+ * @type: 		the Type attribute (optional). 
+ * @recipient: 		the Recipient attribute (optional). 
+ *
+ * Adds <enc:EncryptedKey/> node with given attributes to 
+ * the <dsig:KeyInfo/> node @keyInfoNode.
+ *
+ * Returns the pointer to the newly created <enc:EncryptedKey/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+xmlNodePtr 
+xmlSecTmplKeyInfoAddEncryptedKey(xmlNodePtr keyInfoNode, xmlSecTransformId encMethodId,
+			 const xmlChar* id, const xmlChar* type, const xmlChar* recipient) {
+    xmlNodePtr encKeyNode;
+    int error = 0;
+
+    xmlSecAssert2(keyInfoNode != NULL, NULL);
+
+    /* we allow multiple encrypted key elements */
+    encKeyNode = xmlSecAddChild(keyInfoNode, xmlSecNodeEncryptedKey, xmlSecEncNs); 
+    if(encKeyNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s", 
+		    xmlSecErrorsSafeString(xmlSecNodeEncryptedKey));
+	return(NULL);	
+    }
+    
+    if(id != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(encKeyNode, xmlSecAttrId, id);
+    error = error || !ptr;
+    }
+    if(type != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(encKeyNode, xmlSecAttrType, type);
+    error = error || !ptr;
+    }
+    if(recipient != NULL) {
+	xmlAttrPtr ptr = xmlSetProp(encKeyNode, xmlSecAttrRecipient, recipient);
+    error = error || !ptr;
+    }
+    if (error && OOM_FLAG) 
+        {
+        xmlUnlinkNode(encKeyNode);
+	    xmlFreeNode(encKeyNode);
+	    return(NULL);
+        }
+
+    if(xmlSecTmplPrepareEncData(encKeyNode, encMethodId) < 0) {
+	xmlUnlinkNode(encKeyNode);
+	xmlFreeNode(encKeyNode);
+	return(NULL);	        	
+    }    
+    return(encKeyNode);    
+}
+
+/***********************************************************************
+ *
+ * <dsig:X509Data> node
+ *
+ **********************************************************************/ 
+/**
+ * xmlSecTmplX509DataAddIssuerSerial:
+ * @x509DataNode: 	the pointer to <dsig:X509Data/> node.
+ * 
+ * Adds <dsig:X509IssuerSerial/> node to the given <dsig:X509Data/> node.
+ *
+ * Returns the pointer to the newly created <dsig:X509IssuerSerial/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+
+xmlNodePtr 
+xmlSecTmplX509DataAddIssuerSerial(xmlNodePtr x509DataNode) {
+    xmlNodePtr cur;
+
+    xmlSecAssert2(x509DataNode != NULL, NULL);
+
+    cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509IssuerSerial, xmlSecDSigNs);
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeX509IssuerSerial),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);
+    }
+    
+    cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509IssuerSerial, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s", 
+		    xmlSecErrorsSafeString(xmlSecNodeX509IssuerSerial));
+	return(NULL);
+    }    
+    
+    return (cur);
+}
+
+/**
+ * xmlSecTmplX509DataAddSubjectName:
+ * @x509DataNode: 	the pointer to <dsig:X509Data/> node.
+ * 
+ * Adds <dsig:X509SubjectName/> node to the given <dsig:X509Data/> node.
+ *
+ * Returns the pointer to the newly created <dsig:X509SubjectName/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+
+xmlNodePtr 
+xmlSecTmplX509DataAddSubjectName(xmlNodePtr x509DataNode) {
+    xmlNodePtr cur;
+
+    xmlSecAssert2(x509DataNode != NULL, NULL);
+
+    cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509SubjectName, xmlSecDSigNs);
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeX509SubjectName),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);
+    }
+    
+    cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509SubjectName, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s", 
+		    xmlSecErrorsSafeString(xmlSecNodeX509SubjectName));
+	return(NULL);
+    }    
+    
+    return (cur);
+}
+
+/**
+ * xmlSecTmplX509DataAddSKI:
+ * @x509DataNode: 	the pointer to <dsig:X509Data/> node.
+ * 
+ * Adds <dsig:X509SKI/> node to the given <dsig:X509Data/> node.
+ *
+ * Returns the pointer to the newly created <dsig:X509SKI/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+
+xmlNodePtr 
+xmlSecTmplX509DataAddSKI(xmlNodePtr x509DataNode) {
+    xmlNodePtr cur;
+
+    xmlSecAssert2(x509DataNode != NULL, NULL);
+
+    cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509SKI, xmlSecDSigNs);
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeX509SKI),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);
+    }
+    
+    cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509SKI, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s", 
+		    xmlSecErrorsSafeString(xmlSecNodeX509SKI));
+	return(NULL);
+    }    
+    
+    return (cur);
+}
+
+
+/**
+ * xmlSecTmplX509DataAddCertificate:
+ * @x509DataNode: 	the pointer to <dsig:X509Data/> node.
+ * 
+ * Adds <dsig:X509Certificate/> node to the given <dsig:X509Data/> node.
+ *
+ * Returns the pointer to the newly created <dsig:X509Certificate/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+
+xmlNodePtr 
+xmlSecTmplX509DataAddCertificate(xmlNodePtr x509DataNode) {
+    xmlNodePtr cur;
+
+    xmlSecAssert2(x509DataNode != NULL, NULL);
+
+    cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509Certificate, xmlSecDSigNs);
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeX509Certificate),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);
+    }
+    
+    cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509Certificate, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s", 
+		    xmlSecErrorsSafeString(xmlSecNodeX509Certificate));
+	return(NULL);
+    }    
+    
+    return (cur);
+}
+
+/**
+ * xmlSecTmplX509DataAddCRL:
+ * @x509DataNode: 	the pointer to <dsig:X509Data/> node.
+ * 
+ * Adds <dsig:X509CRL/> node to the given <dsig:X509Data/> node.
+ *
+ * Returns the pointer to the newly created <dsig:X509CRL/> node or
+ * NULL if an error occurs.
+ */
+EXPORT_C
+
+xmlNodePtr 
+xmlSecTmplX509DataAddCRL(xmlNodePtr x509DataNode) {
+    xmlNodePtr cur;
+
+    xmlSecAssert2(x509DataNode != NULL, NULL);
+
+    cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509CRL, xmlSecDSigNs);
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeX509CRL),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(NULL);
+    }
+    
+    cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509CRL, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s", 
+		    xmlSecErrorsSafeString(xmlSecNodeX509CRL));
+	return(NULL);
+    }    
+    
+    return (cur);
+}
+
+/*************************************************************************
+ *
+ * <dsig:Transform/> node
+ *
+ ************************************************************************/
+
+/**
+ * xmlSecTmplTransformAddHmacOutputLength:
+ * @transformNode: 	the pointer to <dsig:Transform/> node
+ * @bitsLen: 		the required length in bits
+ *
+ * Creates <dsig:HMACOutputLength/> child for the HMAC transform 
+ * node @node.
+ *
+ * Returns 0 on success and a negatie value otherwise.
+ */
+EXPORT_C
+int
+xmlSecTmplTransformAddHmacOutputLength(xmlNodePtr transformNode, xmlSecSize bitsLen) {
+    xmlNodePtr cur;
+    char buf[32];
+
+    xmlSecAssert2(transformNode != NULL, -1);
+    xmlSecAssert2(bitsLen > 0, -1);
+
+    cur = xmlSecFindChild(transformNode, xmlSecNodeHMACOutputLength, xmlSecDSigNs);
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeHMACOutputLength),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    cur = xmlSecAddChild(transformNode, xmlSecNodeHMACOutputLength, xmlSecDSigNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s", 
+		    xmlSecErrorsSafeString(xmlSecNodeHMACOutputLength));
+	return(-1);
+    }    
+    
+    sprintf(buf, "%u", bitsLen);
+    xmlNodeSetContent(cur, BAD_CAST buf);
+    return(0);
+}
+
+/**
+ * xmlSecTmplTransformAddRsaOaepParam:
+ * @transformNode: 	the pointer to <dsig:Transform/> node.
+ * @buf: 		the OAEP param buffer.
+ * @size: 		the OAEP param buffer size.
+ * 
+ * Creates <enc:OAEPParam/> child node in the @node.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int  	
+xmlSecTmplTransformAddRsaOaepParam(xmlNodePtr transformNode, 
+			const xmlSecByte *buf, xmlSecSize size) {
+    xmlNodePtr oaepParamNode;
+    xmlChar *base64;
+
+    xmlSecAssert2(transformNode != NULL, -1);
+    xmlSecAssert2(buf != NULL, -1);
+    xmlSecAssert2(size > 0, -1);
+
+    oaepParamNode = xmlSecFindChild(transformNode, xmlSecNodeRsaOAEPparams, xmlSecEncNs);
+    if(oaepParamNode != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeRsaOAEPparams),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);    
+    }
+
+    oaepParamNode = xmlSecAddChild(transformNode, xmlSecNodeRsaOAEPparams, xmlSecEncNs);
+    if(oaepParamNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s", 
+		    xmlSecErrorsSafeString(xmlSecNodeRsaOAEPparams));
+	return(-1);    
+    }
+    
+    base64 = xmlSecBase64Encode(buf, size, 0);
+    if(base64 == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecBase64Encode",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "size=%d", size);
+	return(-1);    
+    }
+    
+    xmlNodeSetContent(oaepParamNode, base64);
+    xmlFree(base64);
+    return(0);
+}
+
+/**
+ * xmlSecTmplTransformAddXsltStylesheet:
+ * @transformNode: 	the pointer to <dsig:Transform/> node.
+ * @xslt: 		the XSLT transform exspression.
+ * 
+ * Writes the XSLT transform expression to the @node.
+ *
+ * Returns 0 on success or a negative value otherwise.
+ */
+EXPORT_C
+int
+xmlSecTmplTransformAddXsltStylesheet(xmlNodePtr transformNode, const xmlChar *xslt) {
+    xmlDocPtr xsltDoc;
+    int ret;
+        
+    xmlSecAssert2(transformNode != NULL, -1);    
+    xmlSecAssert2(xslt != NULL, -1);    
+    
+    xsltDoc = xmlParseMemory((const char*)xslt, xmlStrlen(xslt));
+    if(xsltDoc == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlParseMemory",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    ret = xmlSecReplaceContent(transformNode, xmlDocGetRootElement(xsltDoc));
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecReplaceContent",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlFreeDoc(xsltDoc);
+	return(-1);
+    }
+    
+    xmlFreeDoc(xsltDoc);
+    return(0);
+}
+
+/**
+ * xmlSecTmplTransformAddC14NInclNamespaces:
+ * @transformNode: 	the pointer to <dsig:Transform/> node.
+ * @prefixList: 	the white space delimited  list of namespace prefixes, 
+ *			where "#default" indicates the default namespace
+ *			(optional).
+ *
+ * Adds "inclusive" namespaces to the ExcC14N transform node @node.
+ *
+ * Returns 0 if success or a negative value otherwise.
+ */
+EXPORT_C
+int		
+xmlSecTmplTransformAddC14NInclNamespaces(xmlNodePtr transformNode, 
+					 const xmlChar *prefixList) {
+    xmlNodePtr cur;
+    xmlAttrPtr ptr;
+
+    xmlSecAssert2(transformNode != NULL, -1);    
+    xmlSecAssert2(prefixList != NULL, -1);
+
+    cur = xmlSecFindChild(transformNode, xmlSecNodeInclusiveNamespaces, xmlSecNsExcC14N);
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE, 
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeInclusiveNamespaces),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    cur = xmlSecAddChild(transformNode, xmlSecNodeInclusiveNamespaces, xmlSecNsExcC14N);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE, 
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(transformNode)),
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeInclusiveNamespaces));
+	return(-1);
+    }    
+    
+    ptr = xmlSetProp(cur, xmlSecAttrPrefixList, prefixList);
+    if (!ptr && OOM_FLAG) 
+        {
+        xmlUnlinkNode(cur);
+	    xmlFreeNode(cur);
+	    return(-1);
+        }
+    return(0);
+}
+
+/**
+ * xmlSecTmplTransformAddXPath:
+ * @transformNode: 	the pointer to the <dsig:Transform/> node.
+ * @expression: 	the XPath expression.
+ * @nsList: 		the NULL terminated list of namespace prefix/href pairs
+ *			(optional).
+ *
+ * Writes XPath transform infromation to the <dsig:Transform/> node 
+ * @node.
+ *
+ * Returns 0 for success or a negative value otherwise.
+ */
+EXPORT_C
+int 	
+xmlSecTmplTransformAddXPath(xmlNodePtr transformNode, const xmlChar *expression,
+			 const xmlChar **nsList) {
+    xmlNodePtr xpathNode;
+    
+    xmlSecAssert2(transformNode != NULL, -1);
+    xmlSecAssert2(expression != NULL, -1);
+    
+    xpathNode = xmlSecFindChild(transformNode, xmlSecNodeXPath, xmlSecDSigNs);
+    if(xpathNode != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeXPath),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);    
+    }
+
+    xpathNode = xmlSecAddChild(transformNode, xmlSecNodeXPath, xmlSecDSigNs);
+    if(xpathNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeXPath));
+	return(-1);    
+    }
+    
+    xmlNodeSetContent(xpathNode, expression);
+    return((nsList != NULL) ? xmlSecTmplNodeWriteNsList(xpathNode, nsList) : 0);
+}
+
+/**
+ * xmlSecTmplTransformAddXPath2:
+ * @transformNode: 	the pointer to the <dsig:Transform/> node.
+ * @type: 		the XPath2 transform type ("union", "intersect" or "subtract").
+ * @expression: 	the XPath expression.
+ * @nsList: 		the NULL terminated list of namespace prefix/href pairs.
+ *			(optional).
+ *
+ * Writes XPath2 transform infromation to the <dsig:Transform/> node 
+ * @node.
+ *
+ * Returns 0 for success or a negative value otherwise.
+ */
+EXPORT_C
+int
+xmlSecTmplTransformAddXPath2(xmlNodePtr transformNode, const xmlChar* type,
+			const xmlChar *expression, const xmlChar **nsList) {
+    xmlNodePtr xpathNode;
+    xmlAttrPtr ptr;
+
+    xmlSecAssert2(transformNode != NULL, -1);
+    xmlSecAssert2(type != NULL, -1);
+    xmlSecAssert2(expression != NULL, -1);
+
+    xpathNode = xmlSecAddChild(transformNode, xmlSecNodeXPath, xmlSecXPath2Ns);
+    if(xpathNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeXPath));
+	return(-1);    
+    }
+    ptr = xmlSetProp(xpathNode, xmlSecAttrFilter, type);
+    if (!ptr && OOM_FLAG) 
+        {
+        xmlUnlinkNode(xpathNode);
+	    xmlFreeNode(xpathNode);
+	    return(-1);
+        }
+    
+    xmlNodeSetContent(xpathNode, expression);
+    return((nsList != NULL) ? xmlSecTmplNodeWriteNsList(xpathNode, nsList) : 0);
+}
+
+/**
+ * xmlSecTmplTransformAddXPointer:
+ * @transformNode: 	the pointer to the <dsig:Transform/> node.
+ * @expression: 	the XPath expression.
+ * @nsList: 		the NULL terminated list of namespace prefix/href pairs.
+ *			(optional).
+ *
+ * Writes XPoniter transform infromation to the <dsig:Transform/> node 
+ * @node.
+ *
+ * Returns 0 for success or a negative value otherwise.
+ */
+EXPORT_C
+int 	
+xmlSecTmplTransformAddXPointer(xmlNodePtr transformNode, const xmlChar *expression,
+			 const xmlChar **nsList) {
+    xmlNodePtr xpointerNode;
+
+    xmlSecAssert2(expression != NULL, -1);
+    xmlSecAssert2(transformNode != NULL, -1);
+
+    xpointerNode = xmlSecFindChild(transformNode, xmlSecNodeXPointer, xmlSecXPointerNs);
+    if(xpointerNode != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeXPointer),
+		    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);    
+    }
+
+    xpointerNode = xmlSecAddChild(transformNode, xmlSecNodeXPointer, xmlSecXPointerNs);
+    if(xpointerNode == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeXPointer));
+	return(-1);    
+    }
+    
+    
+    xmlNodeSetContent(xpointerNode, expression);
+    return((nsList != NULL) ? xmlSecTmplNodeWriteNsList(xpointerNode, nsList) : 0);
+}
+
+static int 
+xmlSecTmplNodeWriteNsList(xmlNodePtr parentNode, const xmlChar** nsList) {
+    xmlNsPtr ns;
+    const xmlChar *prefix;
+    const xmlChar *href;
+    const xmlChar **ptr;
+
+    xmlSecAssert2(parentNode != NULL, -1);
+    xmlSecAssert2(nsList != NULL, -1);
+    	
+    ptr = nsList;
+    while((*ptr) != NULL) {
+	if(xmlStrEqual(BAD_CAST "#default", (*ptr))) {
+	    prefix = NULL;
+	} else {
+	    prefix = (*ptr);
+	}
+	if((++ptr) == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			NULL,
+			XMLSEC_ERRORS_R_INVALID_DATA,
+			"unexpected end of ns list");
+	    return(-1);
+	}
+	href = *(ptr++);
+
+	ns = xmlNewNs(parentNode, href, prefix);
+	if(ns == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlNewNs",
+			XMLSEC_ERRORS_R_XML_FAILED,
+			"href=%s;prefix=%s", 
+			xmlSecErrorsSafeString(href),
+			xmlSecErrorsSafeString(prefix));
+	    return(-1);
+	}
+    }
+    return(0);
+}