xmlsecurityengine/xmlsec/src/xmlsec_keyinfo.c
changeset 0 e35f40988205
child 16 d10d750052f0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xmlsecurityengine/xmlsec/src/xmlsec_keyinfo.c	Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,1583 @@
+/** 
+ * XML Security Library (http://www.aleksey.com/xmlsec).
+ *
+ * <dsig:KeyInfo/> element processing 
+ * (http://www.w3.org/TR/xmlSec-core/#sec-KeyInfo:
+ *
+ * The KeyInfo Element
+ *
+ * KeyInfo is an optional element that enables the recipient(s) to obtain 
+ * the key needed to validate the signature.  KeyInfo may contain keys, 
+ * names, certificates and other public key management information, such as 
+ * in-band key distribution or key agreement data. 
+ * 
+ *  Schema Definition:
+ *
+ *  <element name="KeyInfo" type="ds:KeyInfoType"/> 
+ *  <complexType name="KeyInfoType" mixed="true">
+ *    <choice maxOccurs="unbounded"> 
+ *       <element ref="ds:KeyName"/> 
+ *       <element ref="ds:KeyValue"/> 
+ *       <element ref="ds:RetrievalMethod"/> 
+ *       <element ref="ds:X509Data"/> 
+ *       <element ref="ds:PGPData"/> 
+ *       <element ref="ds:SPKIData"/>
+ *       <element ref="ds:MgmtData"/>
+ *       <any processContents="lax" namespace="##other"/>
+ *       <!-- (1,1) elements from (0,unbounded) namespaces -->
+ *    </choice>
+ *    <attribute name="Id" type="ID" use="optional"/>
+ *  </complexType>
+ *    
+ * DTD:
+ *    
+ * <!ELEMENT KeyInfo (#PCDATA|KeyName|KeyValue|RetrievalMethod|
+ *                    X509Data|PGPData|SPKIData|MgmtData %KeyInfo.ANY;)* >      
+ * <!ATTLIST KeyInfo  Id  ID   #IMPLIED >
+ *  
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ * 
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
+ */
+#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_base64.h"
+#include "xmlsec_keys.h"
+#include "xmlsec_keysmngr.h"
+#include "xmlsec_transforms.h"
+#include "xmlsec_xmlenc.h"
+#include "xmlsec_keyinfo.h"
+#include "xmlsec_errors.h"
+
+
+/**************************************************************************
+ *
+ * Hi level functions
+ *
+ *************************************************************************/
+/**
+ * xmlSecKeyInfoNodeRead:
+ * @keyInfoNode: 	the pointer to <dsig:KeyInfo/> node.
+ * @key:		the pointer to result key object.
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Parses the <dsig:KeyInfo/> element @keyInfoNode, extracts the key data
+ * and stores into @key.
+ *
+ * Returns 0 on success or -1 if an error occurs.
+ */
+EXPORT_C
+int
+xmlSecKeyInfoNodeRead(xmlNodePtr keyInfoNode, xmlSecKeyPtr key, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    const xmlChar* nodeName;
+    const xmlChar* nodeNs;
+    xmlSecKeyDataId dataId;
+    xmlNodePtr cur;
+    int ret;
+    
+    xmlSecAssert2(keyInfoNode != NULL, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1);
+
+    for(cur = xmlSecGetNextElementNode(keyInfoNode->children); 
+	(cur != NULL) && 
+	(((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_DONT_STOP_ON_KEY_FOUND) != 0) || 
+	 (xmlSecKeyIsValid(key) == 0) || 
+	 (xmlSecKeyMatch(key, NULL, &(keyInfoCtx->keyReq)) == 0));
+	cur = xmlSecGetNextElementNode(cur->next)) {
+    
+	/* find data id */
+	nodeName = cur->name;
+	nodeNs = xmlSecGetNodeNsHref(cur);
+	
+	/* use global list only if we don't have a local one */
+	if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) {
+	    dataId = xmlSecKeyDataIdListFindByNode(&(keyInfoCtx->enabledKeyData),
+			    nodeName, nodeNs, xmlSecKeyDataUsageKeyInfoNodeRead);
+	} else {	
+    	    dataId = xmlSecKeyDataIdListFindByNode(xmlSecKeyDataIdsGet(),
+			    nodeName, nodeNs, xmlSecKeyDataUsageKeyInfoNodeRead);
+	}
+	if(dataId != xmlSecKeyDataIdUnknown) {
+	    /* read data node */
+	    ret = xmlSecKeyDataXmlRead(dataId, key, cur, keyInfoCtx);
+	    if(ret < 0) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)),
+			    "xmlSecKeyDataXmlRead",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    "node=%s", 
+			    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+		return(-1);
+	    }
+	} else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_UNKNOWN_CHILD) != 0) {
+	    /* there is a laxi schema validation but application may
+	     * desire to disable unknown nodes*/
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+			XMLSEC_ERRORS_R_INVALID_NODE,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+    }
+    
+    return(0);    
+}
+
+/**
+ * xmlSecKeyInfoNodeWrite:
+ * @keyInfoNode: 	the pointer to <dsig:KeyInfo/> node.
+ * @key:		the pointer to key object.
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Writes the @key into the <dsig:KeyInfo/> element template @keyInfoNode.
+ *
+ * Returns 0 on success or -1 if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecKeyInfoNodeWrite(xmlNodePtr keyInfoNode, xmlSecKeyPtr key, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    const xmlChar* nodeName;
+    const xmlChar* nodeNs;
+    xmlSecKeyDataId dataId;
+    xmlNodePtr cur;
+    int ret;
+    
+    xmlSecAssert2(keyInfoNode != NULL, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1);
+
+    for(cur = xmlSecGetNextElementNode(keyInfoNode->children); 
+	cur != NULL;
+	cur = xmlSecGetNextElementNode(cur->next)) {
+    
+	/* find data id */
+	nodeName = cur->name;
+	nodeNs = xmlSecGetNodeNsHref(cur);
+
+	/* use global list only if we don't have a local one */
+	if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) {
+        	dataId = xmlSecKeyDataIdListFindByNode(&(keyInfoCtx->enabledKeyData),
+			    nodeName, nodeNs, 
+			    xmlSecKeyDataUsageKeyInfoNodeWrite);
+	} else {
+        	dataId = xmlSecKeyDataIdListFindByNode(xmlSecKeyDataIdsGet(),
+			    nodeName, nodeNs, 
+			    xmlSecKeyDataUsageKeyInfoNodeWrite);
+	}
+	if(dataId != xmlSecKeyDataIdUnknown) {
+	    ret = xmlSecKeyDataXmlWrite(dataId, key, cur, keyInfoCtx);
+	    if(ret < 0) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)),
+			    "xmlSecKeyDataXmlWrite",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    "node=%s", 
+			    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+		return(-1);
+	    }
+	} else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_UNKNOWN_CHILD) != 0) {
+	    /* laxi schema validation but application can disable it*/
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+			XMLSEC_ERRORS_R_INVALID_NODE,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+    }
+    
+    return(0);
+} 
+
+/**************************************************************************
+ *
+ * KeyInfo context
+ *
+ *************************************************************************/
+/**
+ * xmlSecKeyInfoCtxCreate:
+ * @keysMngr: 		the pointer to keys manager (may be NULL).
+ *
+ * Allocates and initializes <dsig:KeyInfo/> element processing context.
+ * Caller is responsible for freeing it by calling #xmlSecKeyInfoCtxDestroy 
+ * function.
+ *
+ * Returns pointer to newly allocated object or NULL if an error occurs.
+ */
+EXPORT_C
+xmlSecKeyInfoCtxPtr 
+xmlSecKeyInfoCtxCreate(xmlSecKeysMngrPtr keysMngr) {
+    xmlSecKeyInfoCtxPtr keyInfoCtx;
+    int ret;
+    
+    /* Allocate a new xmlSecKeyInfoCtx and fill the fields. */
+    keyInfoCtx = (xmlSecKeyInfoCtxPtr)xmlMalloc(sizeof(xmlSecKeyInfoCtx));
+    if(keyInfoCtx == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    NULL,
+		    XMLSEC_ERRORS_R_MALLOC_FAILED,
+		    "size=%d", sizeof(xmlSecKeyInfoCtx)); 
+	return(NULL);
+    }
+    
+    ret = xmlSecKeyInfoCtxInitialize(keyInfoCtx, keysMngr);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecKeyInfoCtxInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecKeyInfoCtxDestroy(keyInfoCtx);
+	return(NULL);
+    }
+    
+    return(keyInfoCtx);
+}
+
+/** 
+ * xmlSecKeyInfoCtxDestroy:
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Destroys @keyInfoCtx object created with #xmlSecKeyInfoCtxCreate function.
+ */
+EXPORT_C
+void 
+xmlSecKeyInfoCtxDestroy(xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    xmlSecAssert(keyInfoCtx != NULL);
+    
+    xmlSecKeyInfoCtxFinalize(keyInfoCtx);
+    xmlFree(keyInfoCtx);
+}
+
+/** 
+ * xmlSecKeyInfoCtxInitialize:
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ * @keysMngr: 		the pointer to keys manager (may be NULL).
+ *
+ * Initializes <dsig:KeyInfo/> element processing context. Caller is 
+ * responsible for cleaning it up by #xmlSecKeyInfoCtxFinalize function.
+ * 
+ * Returns 0 on success and a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecKeyInfoCtxInitialize(xmlSecKeyInfoCtxPtr keyInfoCtx, xmlSecKeysMngrPtr keysMngr) {
+    int ret;
+    
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    
+    memset(keyInfoCtx, 0, sizeof(xmlSecKeyInfoCtx));
+    keyInfoCtx->keysMngr = keysMngr;
+    keyInfoCtx->base64LineSize = XMLSEC_BASE64_LINESIZE;    
+    ret = xmlSecPtrListInitialize(&(keyInfoCtx->enabledKeyData), xmlSecKeyDataIdListId);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecPtrListInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    keyInfoCtx->maxRetrievalMethodLevel = 1;
+    ret = xmlSecTransformCtxInitialize(&(keyInfoCtx->retrievalMethodCtx));
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformCtxInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+#ifndef XMLSEC_NO_XMLENC
+    keyInfoCtx->maxEncryptedKeyLevel = 1;
+#endif /* XMLSEC_NO_XMLENC */
+
+#ifndef XMLSEC_NO_X509
+    keyInfoCtx->certsVerificationDepth= 9;
+#endif /* XMLSEC_NO_X509 */
+
+    ret = xmlSecKeyReqInitialize(&(keyInfoCtx->keyReq));
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecKeyReqInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+        
+    return(0);
+}
+
+/** 
+ * xmlSecKeyInfoCtxFinalize:
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Cleans up the @keyInfoCtx initialized with #xmlSecKeyInfoCtxInitialize
+ * function.
+ */
+EXPORT_C
+void 
+xmlSecKeyInfoCtxFinalize(xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    xmlSecAssert(keyInfoCtx != NULL);
+    
+    xmlSecPtrListFinalize(&(keyInfoCtx->enabledKeyData));
+    xmlSecTransformCtxFinalize(&(keyInfoCtx->retrievalMethodCtx));
+    xmlSecKeyReqFinalize(&(keyInfoCtx->keyReq));
+
+#ifndef XMLSEC_NO_XMLENC
+    if(keyInfoCtx->encCtx != NULL) {
+        xmlSecEncCtxDestroy(keyInfoCtx->encCtx);
+    }
+#endif /* XMLSEC_NO_XMLENC */
+
+    memset(keyInfoCtx, 0, sizeof(xmlSecKeyInfoCtx));
+}
+
+/** 
+ * xmlSecKeyInfoCtxReset:
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ * 
+ * Resets the @keyInfoCtx state. User settings are not changed.
+ */
+EXPORT_C
+void 
+xmlSecKeyInfoCtxReset(xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    xmlSecAssert(keyInfoCtx != NULL);
+    
+    xmlSecTransformCtxReset(&(keyInfoCtx->retrievalMethodCtx));
+    keyInfoCtx->curRetrievalMethodLevel = 0;
+
+#ifndef XMLSEC_NO_XMLENC
+    if(keyInfoCtx->encCtx != NULL) { 	   
+        xmlSecEncCtxReset(keyInfoCtx->encCtx);
+    }
+    keyInfoCtx->curEncryptedKeyLevel = 0;
+#endif /* XMLSEC_NO_XMLENC */
+    
+    xmlSecKeyReqReset(&(keyInfoCtx->keyReq));
+}
+
+/** 
+ * xmlSecKeyInfoCtxCreateEncCtx:
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ * 
+ * Creates encryption context form processing <enc:EncryptedKey/> child
+ * of <dsig:KeyInfo/> element.
+ * 
+ * Returns 0 on success and a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecKeyInfoCtxCreateEncCtx(xmlSecKeyInfoCtxPtr keyInfoCtx) {
+#ifndef XMLSEC_NO_XMLENC
+    xmlSecEncCtxPtr tmp;
+    int ret;
+    
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->encCtx == NULL, -1);
+
+    /* we have to use tmp variable to avoid a recursive loop */ 
+    tmp = xmlSecEncCtxCreate(keyInfoCtx->keysMngr);
+    if(tmp == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecEncCtxCreate",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    tmp->mode = xmlEncCtxModeEncryptedKey;
+        
+    /* copy user preferences from our current ctx */
+    switch(keyInfoCtx->mode) {
+	case xmlSecKeyInfoModeRead:
+	    ret = xmlSecKeyInfoCtxCopyUserPref(&(tmp->keyInfoReadCtx), keyInfoCtx);
+	    if(ret < 0) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    NULL,
+			    "xmlSecKeyInfoCtxCopyUserPref",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    XMLSEC_ERRORS_NO_MESSAGE);
+		xmlSecEncCtxDestroy(tmp);
+		return(-1);
+	    }    
+	    break;
+	case xmlSecKeyInfoModeWrite:
+	    ret = xmlSecKeyInfoCtxCopyUserPref(&(tmp->keyInfoWriteCtx), keyInfoCtx);
+	    if(ret < 0) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    NULL,
+			    "xmlSecKeyInfoCtxCopyUserPref",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    XMLSEC_ERRORS_NO_MESSAGE);
+		xmlSecEncCtxDestroy(tmp);
+		return(-1);
+	    }
+	    break;
+    }    
+    keyInfoCtx->encCtx = tmp;
+        
+    return(0);
+#else /* XMLSEC_NO_XMLENC */    
+    xmlSecError(XMLSEC_ERRORS_HERE,
+		NULL,
+		"xml encryption",
+		XMLSEC_ERRORS_R_DISABLED,
+		XMLSEC_ERRORS_NO_MESSAGE);
+    return(-1);
+#endif /* XMLSEC_NO_XMLENC */    
+}
+
+/** 
+ * xmlSecKeyInfoCtxCopyUserPref:
+ * @dst:		the pointer to destination context object.
+ * @src:		the pointer to source context object.
+ *
+ * Copies user preferences from @src context to @dst context.
+ *  
+ * Returns 0 on success and a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecKeyInfoCtxCopyUserPref(xmlSecKeyInfoCtxPtr dst, xmlSecKeyInfoCtxPtr src) {
+    int ret;
+    
+    xmlSecAssert2(dst != NULL, -1);
+    xmlSecAssert2(src != NULL, -1);
+    
+    dst->userData 	= src->userData;
+    dst->flags		= src->flags;
+    dst->flags2		= src->flags2;
+    dst->keysMngr	= src->keysMngr;
+    dst->mode		= src->mode;
+    dst->base64LineSize	= src->base64LineSize;
+
+    ret = xmlSecPtrListCopy(&(dst->enabledKeyData), &(src->enabledKeyData));
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecPtrListCopy",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "enabledKeyData");    
+	return(-1);
+    }
+    
+    /* <dsig:RetrievalMethod/> */
+    dst->maxRetrievalMethodLevel= src->maxRetrievalMethodLevel;
+    ret = xmlSecTransformCtxCopyUserPref(&(dst->retrievalMethodCtx), 
+					 &(src->retrievalMethodCtx));
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecTransformCtxCopyUserPref",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "enabledKeyData");    
+	return(-1);
+    }
+
+    /* <enc:EncryptedContext /> */    
+#ifndef XMLSEC_NO_XMLENC
+    xmlSecAssert2(dst->encCtx == NULL, -1);
+    if(src->encCtx != NULL) { 	   	
+	dst->encCtx = xmlSecEncCtxCreate(dst->keysMngr);
+	if(dst->encCtx == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+			"xmlSecEncCtxCreate",
+		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		        XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+	
+	dst->encCtx->mode = xmlEncCtxModeEncryptedKey;
+        ret = xmlSecEncCtxCopyUserPref(dst->encCtx, src->encCtx);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+			"xmlSecEncCtxCopyUserPref",
+		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		        XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+    }
+    dst->maxEncryptedKeyLevel	= src->maxEncryptedKeyLevel;
+#endif /* XMLSEC_NO_XMLENC */
+
+    /* <dsig:X509Data /> */    
+#ifndef XMLSEC_NO_X509
+    dst->certsVerificationTime	= src->certsVerificationTime;
+    dst->certsVerificationDepth	= src->certsVerificationDepth;
+#endif /* XMLSEC_NO_X509 */
+    
+    return(0);
+}
+
+/** 
+ * xmlSecKeyInfoCtxDebugDump:
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ * @output:		the output file pointer.
+ *
+ * Prints user settings and current context state to @output.
+ */
+EXPORT_C
+void 
+xmlSecKeyInfoCtxDebugDump(xmlSecKeyInfoCtxPtr keyInfoCtx, FILE* output) {
+    xmlSecAssert(keyInfoCtx != NULL);
+    xmlSecAssert(output != NULL);
+
+    switch(keyInfoCtx->mode) {
+	case xmlSecKeyInfoModeRead:
+	    fprintf(output, "= KEY INFO READ CONTEXT\n");
+	    break;
+	case xmlSecKeyInfoModeWrite:
+	    fprintf(output, "= KEY INFO WRITE CONTEXT\n");
+	    break;
+    }
+    
+    fprintf(output, "== flags: 0x%08x\n", keyInfoCtx->flags);
+    fprintf(output, "== flags2: 0x%08x\n", keyInfoCtx->flags2);
+    if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) {
+	fprintf(output, "== enabled key data: ");
+	xmlSecKeyDataIdListDebugDump(&(keyInfoCtx->enabledKeyData), output);
+    } else {
+	fprintf(output, "== enabled key data: all\n");
+    }
+    fprintf(output, "== RetrievalMethod level (cur/max): %d/%d\n",
+	    keyInfoCtx->curRetrievalMethodLevel, 
+	    keyInfoCtx->maxRetrievalMethodLevel);
+    xmlSecTransformCtxDebugDump(&(keyInfoCtx->retrievalMethodCtx), output);
+    
+#ifndef XMLSEC_NO_XMLENC
+    fprintf(output, "== EncryptedKey level (cur/max): %d/%d\n",
+	    keyInfoCtx->curEncryptedKeyLevel, 
+	    keyInfoCtx->maxEncryptedKeyLevel);
+    if(keyInfoCtx->encCtx != NULL) {
+	xmlSecEncCtxDebugDump(keyInfoCtx->encCtx, output);
+    }
+#endif /* XMLSEC_NO_XMLENC */
+
+    xmlSecKeyReqDebugDump(&(keyInfoCtx->keyReq), output);
+}
+
+/** 
+ * xmlSecKeyInfoCtxDebugXmlDump:
+ * @keyInfoCtx:		the pointer to <dsig:KeyInfo/> element processing context.
+ * @output:		the output file pointer.
+ *
+ * Prints user settings and current context state in XML format to @output. 
+ */
+EXPORT_C
+void 
+xmlSecKeyInfoCtxDebugXmlDump(xmlSecKeyInfoCtxPtr keyInfoCtx, FILE* output) {
+    xmlSecAssert(keyInfoCtx != NULL);
+    xmlSecAssert(output != NULL);
+
+    switch(keyInfoCtx->mode) {
+	case xmlSecKeyInfoModeRead:
+	    fprintf(output, "<KeyInfoReadContext>\n");
+	    break;
+	case xmlSecKeyInfoModeWrite:
+	    fprintf(output, "<KeyInfoWriteContext>\n");
+	    break;
+    }
+    	    
+    fprintf(output, "<Flags>%08x</Flags>\n", keyInfoCtx->flags);
+    fprintf(output, "<Flags2>%08x</Flags2>\n", keyInfoCtx->flags2);
+    if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) {
+	fprintf(output, "<EnabledKeyData>\n");
+	xmlSecKeyDataIdListDebugXmlDump(&(keyInfoCtx->enabledKeyData), output);
+	fprintf(output, "</EnabledKeyData>\n");
+    } else {
+	fprintf(output, "<EnabledKeyData>all</EnabledKeyData>\n");
+    }
+
+    fprintf(output, "<RetrievalMethodLevel cur=\"%d\" max=\"%d\" />\n",
+	    keyInfoCtx->curRetrievalMethodLevel, 
+	    keyInfoCtx->maxRetrievalMethodLevel);
+    xmlSecTransformCtxDebugXmlDump(&(keyInfoCtx->retrievalMethodCtx), output);
+
+#ifndef XMLSEC_NO_XMLENC
+    fprintf(output, "<EncryptedKeyLevel cur=\"%d\" max=\"%d\" />\n",
+	    keyInfoCtx->curEncryptedKeyLevel, 
+	    keyInfoCtx->maxEncryptedKeyLevel);
+    if(keyInfoCtx->encCtx != NULL) {
+	xmlSecEncCtxDebugXmlDump(keyInfoCtx->encCtx, output);
+    }
+#endif /* XMLSEC_NO_XMLENC */
+    
+    xmlSecKeyReqDebugXmlDump(&(keyInfoCtx->keyReq), output);
+    switch(keyInfoCtx->mode) {
+	case xmlSecKeyInfoModeRead:
+	    fprintf(output, "</KeyInfoReadContext>\n");
+	    break;
+	case xmlSecKeyInfoModeWrite:
+	    fprintf(output, "</KeyInfoWriteContext>\n");
+	    break;
+    }
+}
+
+/**************************************************************************
+ *
+ * <dsig:KeyName/> processing
+ *
+ *************************************************************************/
+static int			xmlSecKeyDataNameXmlRead	(xmlSecKeyDataId id,
+								 xmlSecKeyPtr key,
+								 xmlNodePtr node,
+								 xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int			xmlSecKeyDataNameXmlWrite	(xmlSecKeyDataId id,
+								 xmlSecKeyPtr key,
+								 xmlNodePtr node,
+								 xmlSecKeyInfoCtxPtr keyInfoCtx);
+
+static xmlSecKeyDataKlass xmlSecKeyDataNameKlass = {
+    sizeof(xmlSecKeyDataKlass),
+    sizeof(xmlSecKeyData),
+
+    /* data */
+    xmlSecNameKeyName,
+    xmlSecKeyDataUsageKeyInfoNode, 		/* xmlSecKeyDataUsage usage; */
+    NULL,					/* const xmlChar* href; */
+    xmlSecNodeKeyName,				/* const xmlChar* dataNodeName; */
+    xmlSecDSigNs,				/* const xmlChar* dataNodeNs; */
+    
+    /* constructors/destructor */
+    NULL,					/* xmlSecKeyDataInitializeMethod initialize; */
+    NULL,					/* xmlSecKeyDataDuplicateMethod duplicate; */
+    NULL,					/* xmlSecKeyDataFinalizeMethod finalize; */
+    NULL,					/* xmlSecKeyDataGenerateMethod generate; */
+    
+    /* get info */
+    NULL,					/* xmlSecKeyDataGetTypeMethod getType; */
+    NULL,					/* xmlSecKeyDataGetSizeMethod getSize; */
+    NULL,					/* xmlSecKeyDataGetIdentifier getIdentifier; */    
+
+    /* read/write */
+    xmlSecKeyDataNameXmlRead,			/* xmlSecKeyDataXmlReadMethod xmlRead; */
+    xmlSecKeyDataNameXmlWrite,   		/* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+    NULL,					/* xmlSecKeyDataBinReadMethod binRead; */
+    NULL,					/* xmlSecKeyDataBinWriteMethod binWrite; */
+
+    /* debug */
+    NULL,					/* xmlSecKeyDataDebugDumpMethod debugDump; */
+    NULL,					/* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+    /* reserved for the future */
+    NULL,					/* void* reserved0; */
+    NULL,					/* void* reserved1; */
+};
+
+/** 
+ * xmlSecKeyDataNameGetKlass:
+ *
+ * The <dsig:KeyName/> element key data klass 
+ * (http://www.w3.org/TR/xmldsig-core/#sec-KeyName):
+ *
+ * The KeyName element contains a string value (in which white space is 
+ * significant) which may be used by the signer to communicate a key 
+ * identifier to the recipient. Typically, KeyName contains an identifier 
+ * related to the key pair used to sign the message, but it may contain 
+ * other protocol-related information that indirectly identifies a key pair. 
+ * (Common uses of KeyName include simple string names for keys, a key index, 
+ * a distinguished name (DN), an email address, etc.) 
+ *
+ * Returns the <dsig:KeyName/> element processing key data klass.
+ */
+EXPORT_C
+xmlSecKeyDataId 
+xmlSecKeyDataNameGetKlass(void) {
+    return(&xmlSecKeyDataNameKlass);
+}
+
+static int 
+xmlSecKeyDataNameXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    const xmlChar* oldName;
+    xmlChar* newName;
+    int ret;
+
+    xmlSecAssert2(id == xmlSecKeyDataNameId, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1);
+
+    oldName = xmlSecKeyGetName(key);
+    newName = xmlNodeGetContent(node);
+    if(newName == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+		    XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    /* compare name values */
+    if((oldName != NULL) && !xmlStrEqual(oldName, newName)) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "key name is already specified",
+		    XMLSEC_ERRORS_R_INVALID_KEY_DATA,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlFree(newName);
+	return(-1);
+    }
+
+    /* try to find key in the manager */
+    if((xmlSecKeyGetValue(key) == NULL) && (keyInfoCtx->keysMngr != NULL)) {
+	xmlSecKeyPtr tmpKey;
+
+	tmpKey = xmlSecKeysMngrFindKey(keyInfoCtx->keysMngr, newName, keyInfoCtx);
+	if(tmpKey != NULL) {
+	    /* erase any current information in the key */
+	    xmlSecKeyEmpty(key);
+
+	     
+	    /* and copy what we've found */
+	    ret = xmlSecKeyCopy(key, tmpKey);
+	    
+	    if(ret < 0) {
+		xmlSecError(XMLSEC_ERRORS_HERE,
+			    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+			    "xmlSecKeyCopy",
+			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			    XMLSEC_ERRORS_NO_MESSAGE); 
+		xmlSecKeyDestroy(tmpKey);
+		xmlFree(newName);
+		return(-1);
+	    }
+	    tmpKey->value=NULL;
+	    xmlSecKeyDestroy(tmpKey);
+	}
+    }		
+    
+    /* finally set key name if it is not there */
+    if(xmlSecKeyGetName(key) == NULL) {
+	xmlSecKeySetName(key, newName);
+    }
+    xmlFree(newName);
+    return(0);
+}
+
+static int 
+xmlSecKeyDataNameXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    const xmlChar* name;
+
+    xmlSecAssert2(id == xmlSecKeyDataNameId, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1);
+
+    name = xmlSecKeyGetName(key);
+    if(name != NULL) {
+	xmlNodeSetContent(node, name);
+	if (OOM_FLAG)
+	    {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlNodeSetContent",
+			XMLSEC_ERRORS_R_MALLOC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	    }
+    }
+    return(0);
+}
+
+/**************************************************************************
+ *
+ * <dsig:KeyValue/> processing
+ *
+ *************************************************************************/
+static int			xmlSecKeyDataValueXmlRead	(xmlSecKeyDataId id,
+								 xmlSecKeyPtr key,
+								 xmlNodePtr node,
+								 xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int			xmlSecKeyDataValueXmlWrite	(xmlSecKeyDataId id,
+								 xmlSecKeyPtr key,
+								 xmlNodePtr node,
+								 xmlSecKeyInfoCtxPtr keyInfoCtx);
+
+static xmlSecKeyDataKlass xmlSecKeyDataValueKlass = {
+    sizeof(xmlSecKeyDataKlass),
+    sizeof(xmlSecKeyData),
+
+    /* data */
+    xmlSecNameKeyValue,
+    xmlSecKeyDataUsageKeyInfoNode, 		/* xmlSecKeyDataUsage usage; */
+    NULL,					/* const xmlChar* href; */
+    xmlSecNodeKeyValue,				/* const xmlChar* dataNodeName; */
+    xmlSecDSigNs,				/* const xmlChar* dataNodeNs; */
+    
+    /* constructors/destructor */
+    NULL,					/* xmlSecKeyDataInitializeMethod initialize; */
+    NULL,					/* xmlSecKeyDataDuplicateMethod duplicate; */
+    NULL,					/* xmlSecKeyDataFinalizeMethod finalize; */
+    NULL,					/* xmlSecKeyDataGenerateMethod generate; */
+    
+    /* get info */
+    NULL,					/* xmlSecKeyDataGetTypeMethod getType; */
+    NULL,					/* xmlSecKeyDataGetSizeMethod getSize; */
+    NULL,					/* xmlSecKeyDataGetIdentifier getIdentifier; */    
+
+    /* read/write */
+    xmlSecKeyDataValueXmlRead,			/* xmlSecKeyDataXmlReadMethod xmlRead; */
+    xmlSecKeyDataValueXmlWrite, 	  	/* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+    NULL,					/* xmlSecKeyDataBinReadMethod binRead; */
+    NULL,					/* xmlSecKeyDataBinWriteMethod binWrite; */
+
+    /* debug */
+    NULL,					/* xmlSecKeyDataDebugDumpMethod debugDump; */
+    NULL,					/* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+    /* reserved for the future */
+    NULL,					/* void* reserved0; */
+    NULL,					/* void* reserved1; */
+};
+
+/** 
+ * xmlSecKeyDataValueGetKlass:
+ *
+ * The <dsig:KeyValue/> element key data klass 
+ * (http://www.w3.org/TR/xmldsig-core/#sec-KeyValue):
+ *
+ * The KeyValue element contains a single public key that may be useful in 
+ * validating the signature. 
+ * 
+ * Returns the <dsig:KeyValue/> element processing key data klass.
+ */
+EXPORT_C
+xmlSecKeyDataId 
+xmlSecKeyDataValueGetKlass(void) {
+    return(&xmlSecKeyDataValueKlass);
+}
+
+static int 
+xmlSecKeyDataValueXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    const xmlChar* nodeName;
+    const xmlChar* nodeNs;
+    xmlSecKeyDataId dataId;
+    xmlNodePtr cur;
+    int ret;
+
+    xmlSecAssert2(id == xmlSecKeyDataValueId, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1);
+
+    cur = xmlSecGetNextElementNode(node->children);
+    if(cur == NULL) {
+	/* just an empty node */
+	return(0);
+    }
+
+    /* find data id */
+    nodeName = cur->name;
+    nodeNs = xmlSecGetNodeNsHref(cur);
+
+    /* use global list only if we don't have a local one */
+    if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) {
+	dataId = xmlSecKeyDataIdListFindByNode(&(keyInfoCtx->enabledKeyData),
+			    nodeName, nodeNs, xmlSecKeyDataUsageKeyValueNodeRead);
+    } else {	
+    	dataId = xmlSecKeyDataIdListFindByNode(xmlSecKeyDataIdsGet(),
+			    nodeName, nodeNs, xmlSecKeyDataUsageKeyValueNodeRead);
+    }
+    if(dataId != xmlSecKeyDataIdUnknown) {
+	/* read data node */
+	ret = xmlSecKeyDataXmlRead(dataId, key, cur, keyInfoCtx);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+			"xmlSecKeyDataXmlRead",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+	    return(-1);
+	}
+    } else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_KEYVALUE_STOP_ON_UNKNOWN_CHILD) != 0) {
+	/* laxi schema validation but application can disable it */
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_INVALID_NODE,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);	
+    }
+
+    /* <dsig:KeyValue/> might have only one node */
+    cur = xmlSecGetNextElementNode(cur->next);  
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    return(0);
+}
+
+static int 
+xmlSecKeyDataValueXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    const xmlChar* nodeName;
+    const xmlChar* nodeNs;  
+    xmlNodePtr cur;
+    int ret;
+    
+    xmlSecAssert2(id == xmlSecKeyDataValueId, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1);
+
+    if(!xmlSecKeyDataIsValid(key->value) || 
+       !xmlSecKeyDataCheckUsage(key->value, xmlSecKeyDataUsageKeyValueNodeWrite)){
+	/* nothing to write */
+	return(0);
+    }
+    if((xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) && 
+        (xmlSecKeyDataIdListFind(&(keyInfoCtx->enabledKeyData), id) != 1)) {
+
+	/* we are not enabled to write out key data with this id */
+	return(0);
+    }
+    if(xmlSecKeyReqMatchKey(&(keyInfoCtx->keyReq), key) != 1) {
+	/* we are not allowed to write out this key */
+	return(0);
+    }
+
+    nodeName = key->value->id->dataNodeName;
+    nodeNs = key->value->id->dataNodeNs;
+    xmlSecAssert2(nodeName != NULL, -1);
+    
+    /* remove all existing key value */
+    xmlNodeSetContent(node, NULL);
+    
+    /* create key node */
+    cur = xmlSecAddChild(node, nodeName, nodeNs);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "xmlSecAddChild",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(node)));
+	return(-1);	
+    }
+
+    ret = xmlSecKeyDataXmlWrite(key->value->id, key, cur, keyInfoCtx);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "xmlSecKeyDataXmlWrite",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+	return(-1);	
+    }
+
+    return(0);
+}
+
+/**************************************************************************
+ *
+ * <dsig:RetrievalMethod/> processing
+ *
+ *************************************************************************/
+static int			xmlSecKeyDataRetrievalMethodXmlRead(xmlSecKeyDataId id,
+								 xmlSecKeyPtr key,
+								 xmlNodePtr node,
+								 xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int			xmlSecKeyDataRetrievalMethodXmlWrite(xmlSecKeyDataId id,
+								 xmlSecKeyPtr key,
+								 xmlNodePtr node,
+								 xmlSecKeyInfoCtxPtr keyInfoCtx);
+
+
+
+static xmlSecKeyDataKlass xmlSecKeyDataRetrievalMethodKlass = {
+    sizeof(xmlSecKeyDataKlass),
+    sizeof(xmlSecKeyData),
+
+    /* data */
+    xmlSecNameRetrievalMethod,
+    xmlSecKeyDataUsageKeyInfoNode, 		/* xmlSecKeyDataUsage usage; */
+    NULL,					/* const xmlChar* href; */
+    xmlSecNodeRetrievalMethod,			/* const xmlChar* dataNodeName; */
+    xmlSecDSigNs,				/* const xmlChar* dataNodeNs; */
+    
+    /* constructors/destructor */
+    NULL,					/* xmlSecKeyDataInitializeMethod initialize; */
+    NULL,					/* xmlSecKeyDataDuplicateMethod duplicate; */
+    NULL,					/* xmlSecKeyDataFinalizeMethod finalize; */
+    NULL,					/* xmlSecKeyDataGenerateMethod generate; */
+    
+    /* get info */
+    NULL,					/* xmlSecKeyDataGetTypeMethod getType; */
+    NULL,					/* xmlSecKeyDataGetSizeMethod getSize; */
+    NULL,					/* xmlSecKeyDataGetIdentifier getIdentifier; */    
+
+    /* read/write */
+    xmlSecKeyDataRetrievalMethodXmlRead,	/* xmlSecKeyDataXmlReadMethod xmlRead; */
+    xmlSecKeyDataRetrievalMethodXmlWrite,   	/* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+    NULL,					/* xmlSecKeyDataBinReadMethod binRead; */
+    NULL,					/* xmlSecKeyDataBinWriteMethod binWrite; */
+
+    /* debug */
+    NULL,					/* xmlSecKeyDataDebugDumpMethod debugDump; */
+    NULL,					/* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+    /* reserved for the future */
+    NULL,					/* void* reserved0; */
+    NULL,					/* void* reserved1; */
+};
+
+static int			xmlSecKeyDataRetrievalMethodReadXmlResult(xmlSecKeyDataId typeId,
+								 xmlSecKeyPtr key,
+								 const xmlChar* buffer,
+								 xmlSecSize bufferSize,
+								 xmlSecKeyInfoCtxPtr keyInfoCtx);
+
+/** 
+ * xmlSecKeyDataRetrievalMethodGetKlass:
+ *
+ * The <dsig:RetrievalMethod/> element key data klass 
+ * (http://www.w3.org/TR/xmldsig-core/#sec-RetrievalMethod):
+ * A RetrievalMethod element within KeyInfo is used to convey a reference to 
+ * KeyInfo information that is stored at another location. For example, 
+ * several signatures in a document might use a key verified by an X.509v3 
+ * certificate chain appearing once in the document or remotely outside the 
+ * document; each signature's KeyInfo can reference this chain using a single 
+ * RetrievalMethod element instead of including the entire chain with a 
+ * sequence of X509Certificate elements.
+ *
+ * RetrievalMethod uses the same syntax and dereferencing behavior as 
+ * Reference's URI and The Reference Processing Model.
+ * 
+ * Returns the <dsig:RetrievalMethod/> element processing key data klass.
+ */
+EXPORT_C
+xmlSecKeyDataId 
+xmlSecKeyDataRetrievalMethodGetKlass(void) {
+    return(&xmlSecKeyDataRetrievalMethodKlass);
+}
+
+static int 
+xmlSecKeyDataRetrievalMethodXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    xmlSecKeyDataId dataId = xmlSecKeyDataIdUnknown;
+    xmlChar *retrType = NULL;
+    xmlChar *uri = NULL;
+    xmlNodePtr cur;
+    int res = -1;
+    int ret;
+    
+    xmlSecAssert2(id == xmlSecKeyDataRetrievalMethodId, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(node->doc != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1);
+
+    /* check retrieval level */
+    if(keyInfoCtx->curRetrievalMethodLevel >= keyInfoCtx->maxRetrievalMethodLevel) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    NULL,
+		    XMLSEC_ERRORS_R_MAX_RETRIEVALS_LEVEL,
+		    "cur=%d;max=%d", 
+		    keyInfoCtx->curRetrievalMethodLevel,
+		    keyInfoCtx->maxRetrievalMethodLevel);
+	goto done;
+    }
+    ++keyInfoCtx->curRetrievalMethodLevel;
+
+    retrType = xmlGetProp(node, xmlSecAttrType);
+    if(retrType != NULL) {
+	/* use global list only if we don't have a local one */
+	if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) {
+	    dataId = xmlSecKeyDataIdListFindByHref(&(keyInfoCtx->enabledKeyData),
+			    retrType, xmlSecKeyDataUsageRetrievalMethodNode);
+	} else {	
+    	    dataId = xmlSecKeyDataIdListFindByHref(xmlSecKeyDataIdsGet(),
+			    retrType, xmlSecKeyDataUsageRetrievalMethodNode);
+	}
+    }
+
+    /* laxi schema validation but aplication can disable it */
+    if(dataId == xmlSecKeyDataIdUnknown) {
+	if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_RETRMETHOD_STOP_ON_UNKNOWN_HREF) != 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+			xmlSecErrorsSafeString(xmlSecAttrType),
+			XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE,
+			"value=%s", xmlSecErrorsSafeString(retrType));
+	} else {
+	    res = 0;
+	}
+	goto done;
+    }
+
+    /* destroy prev retrieval method context */
+    xmlSecTransformCtxReset(&(keyInfoCtx->retrievalMethodCtx));
+
+    /* set start URI and check that it is enabled */
+    uri = xmlGetProp(node, xmlSecAttrURI);
+    ret = xmlSecTransformCtxSetUri(&(keyInfoCtx->retrievalMethodCtx), uri, node);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "xmlSecTransformCtxSetUri",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "uri=%s",
+		    xmlSecErrorsSafeString(uri));
+	goto done;
+    }
+
+    /* the only one node is optional Transforms node */
+    cur = xmlSecGetNextElementNode(node->children);
+    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeTransforms, xmlSecDSigNs))) {
+	ret = xmlSecTransformCtxNodesListRead(&(keyInfoCtx->retrievalMethodCtx), 
+					    cur, xmlSecTransformUsageDSigTransform);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+			"xmlSecTransformCtxNodesListRead",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+	    goto done;
+	}	
+        cur = xmlSecGetNextElementNode(cur->next);
+    }
+
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	goto done;
+    }
+
+    /* finally get transforms results */
+    ret = xmlSecTransformCtxExecute(&(keyInfoCtx->retrievalMethodCtx), node->doc);
+    if((ret < 0) || 
+       (keyInfoCtx->retrievalMethodCtx.result == NULL) ||
+       (xmlSecBufferGetData(keyInfoCtx->retrievalMethodCtx.result) == NULL)) {
+
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "xmlSecTransformCtxExecute",
+	    	    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	goto done;
+    }
+
+
+    /* assume that the data is in XML if we could not find id */    
+    if((dataId == xmlSecKeyDataIdUnknown) || 
+       ((dataId->usage & xmlSecKeyDataUsageRetrievalMethodNodeXml) != 0)) {
+
+	ret = xmlSecKeyDataRetrievalMethodReadXmlResult(dataId, key,
+		    xmlSecBufferGetData(keyInfoCtx->retrievalMethodCtx.result),
+                    xmlSecBufferGetSize(keyInfoCtx->retrievalMethodCtx.result),
+		    keyInfoCtx);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+			"xmlSecKeyDataRetrievalMethodReadXmlResult",
+	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    goto done;
+	}    
+    } else {
+	ret = xmlSecKeyDataBinRead(dataId, key, 
+		    xmlSecBufferGetData(keyInfoCtx->retrievalMethodCtx.result),
+                    xmlSecBufferGetSize(keyInfoCtx->retrievalMethodCtx.result),
+		    keyInfoCtx);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+			"xmlSecKeyDataBinRead",
+	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    goto done;
+	}    
+    }
+    --keyInfoCtx->curRetrievalMethodLevel;
+    
+    res = 0;    
+done:
+    if(uri != NULL) {
+	xmlFree(uri);
+    }
+    if(retrType != NULL) {
+	xmlFree(retrType);
+    }
+    return(res);
+}
+
+static int 
+xmlSecKeyDataRetrievalMethodXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    xmlSecAssert2(id == xmlSecKeyDataRetrievalMethodId, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1);
+
+    /* just do nothing */
+    return(0);
+}
+
+static int
+xmlSecKeyDataRetrievalMethodReadXmlResult(xmlSecKeyDataId typeId, xmlSecKeyPtr key,
+					  const xmlChar* buffer, xmlSecSize bufferSize,
+					  xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    xmlDocPtr doc;
+    xmlNodePtr cur;
+    const xmlChar* nodeName;
+    const xmlChar* nodeNs;
+    xmlSecKeyDataId dataId;
+    int ret;
+    
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(buffer != NULL, -1);
+    xmlSecAssert2(bufferSize > 0, -1); 
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1);
+
+    doc = xmlRecoverMemory((const char*)buffer, bufferSize);
+    if(doc == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)),
+		    "xmlRecoverMemory",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+	
+    cur = xmlDocGetRootElement(doc);
+    if(cur == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)),
+		    "xmlDocGetRootElement",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlFreeDoc(doc);
+	return(-1);	
+    }
+
+    nodeName = cur->name;
+    nodeNs = xmlSecGetNodeNsHref(cur);
+
+    /* use global list only if we don't have a local one */
+    if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) {
+	dataId = xmlSecKeyDataIdListFindByNode(&(keyInfoCtx->enabledKeyData),
+			    nodeName, nodeNs, xmlSecKeyDataUsageRetrievalMethodNodeXml);
+    } else {	
+    	dataId = xmlSecKeyDataIdListFindByNode(xmlSecKeyDataIdsGet(),
+			    nodeName, nodeNs, xmlSecKeyDataUsageRetrievalMethodNodeXml);
+    }
+    if(dataId == xmlSecKeyDataIdUnknown) {
+	xmlFreeDoc(doc);
+
+	/* laxi schema validation but application can disable it */
+	if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_KEYVALUE_STOP_ON_UNKNOWN_CHILD) != 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)),
+			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+			XMLSEC_ERRORS_R_INVALID_NODE,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+	return(0);
+    } else if((typeId != xmlSecKeyDataIdUnknown) && (typeId != dataId) &&
+	      ((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_RETRMETHOD_STOP_ON_MISMATCH_HREF) != 0)) {
+	
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)),
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)),		    
+		    XMLSEC_ERRORS_R_MAX_RETRIEVAL_TYPE_MISMATCH,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlFreeDoc(doc);
+	return(-1);
+    }
+
+    /* read data node */
+    ret = xmlSecKeyDataXmlRead(dataId, key, cur, keyInfoCtx);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)),
+		    "xmlSecKeyDataXmlRead",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "node=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+	xmlFreeDoc(doc);
+	return(-1);
+    }
+    
+    xmlFreeDoc(doc);
+    return(0);
+}
+
+
+#ifndef XMLSEC_NO_XMLENC
+/**************************************************************************
+ *
+ * <enc:EncryptedKey/> processing
+ *
+ *************************************************************************/
+static int	xmlSecKeyDataEncryptedKeyXmlRead	(xmlSecKeyDataId id,
+							 xmlSecKeyPtr key,
+							 xmlNodePtr node,
+							 xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int	xmlSecKeyDataEncryptedKeyXmlWrite	(xmlSecKeyDataId id,
+							 xmlSecKeyPtr key,
+							 xmlNodePtr node,
+							 xmlSecKeyInfoCtxPtr keyInfoCtx);
+
+
+
+static xmlSecKeyDataKlass xmlSecKeyDataEncryptedKeyKlass = {
+    sizeof(xmlSecKeyDataKlass),
+    sizeof(xmlSecKeyData),
+
+    /* data */
+    xmlSecNameEncryptedKey,
+    xmlSecKeyDataUsageKeyInfoNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, 		
+						/* xmlSecKeyDataUsage usage; */
+    xmlSecHrefEncryptedKey,			/* const xmlChar* href; */
+    xmlSecNodeEncryptedKey,			/* const xmlChar* dataNodeName; */
+    xmlSecEncNs,				/* const xmlChar* dataNodeNs; */
+    
+    /* constructors/destructor */
+    NULL,					/* xmlSecKeyDataInitializeMethod initialize; */
+    NULL,					/* xmlSecKeyDataDuplicateMethod duplicate; */
+    NULL,					/* xmlSecKeyDataFinalizeMethod finalize; */
+    NULL,					/* xmlSecKeyDataGenerateMethod generate; */
+    
+    /* get info */
+    NULL,					/* xmlSecKeyDataGetTypeMethod getType; */
+    NULL,					/* xmlSecKeyDataGetSizeMethod getSize; */
+    NULL,					/* xmlSecKeyDataGetIdentifier getIdentifier; */    
+
+    /* read/write */
+    xmlSecKeyDataEncryptedKeyXmlRead,		/* xmlSecKeyDataXmlReadMethod xmlRead; */
+    xmlSecKeyDataEncryptedKeyXmlWrite,   	/* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+    NULL,					/* xmlSecKeyDataBinReadMethod binRead; */
+    NULL,					/* xmlSecKeyDataBinWriteMethod binWrite; */
+
+    /* debug */
+    NULL,					/* xmlSecKeyDataDebugDumpMethod debugDump; */
+    NULL,					/* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+    /* reserved for the future */
+    NULL,					/* void* reserved0; */
+    NULL,					/* void* reserved1; */
+};
+
+/** 
+ * xmlSecKeyDataEncryptedKeyGetKlass:
+ *
+ * The <enc:EncryptedKey/> element key data klass 
+ * (http://www.w3.org/TR/xmlenc-core/#sec-EncryptedKey):
+ *
+ * The EncryptedKey element is used to transport encryption keys from 
+ * the originator to a known recipient(s). It may be used as a stand-alone 
+ * XML document, be placed within an application document, or appear inside 
+ * an EncryptedData element as a child of a ds:KeyInfo element. The key value 
+ * is always encrypted to the recipient(s). When EncryptedKey is decrypted the 
+ * resulting octets are made available to the EncryptionMethod algorithm 
+ * without any additional processing.
+ * 
+ * Returns the <enc:EncryptedKey/> element processing key data klass.
+ */
+EXPORT_C
+xmlSecKeyDataId 
+xmlSecKeyDataEncryptedKeyGetKlass(void) {
+    return(&xmlSecKeyDataEncryptedKeyKlass);
+}
+
+static int 
+xmlSecKeyDataEncryptedKeyXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    xmlSecBufferPtr result;
+    int ret;
+
+    xmlSecAssert2(id == xmlSecKeyDataEncryptedKeyId, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1);
+
+    /* check the enc level */    
+    if(keyInfoCtx->curEncryptedKeyLevel >= keyInfoCtx->maxEncryptedKeyLevel) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    NULL,
+		    XMLSEC_ERRORS_R_MAX_ENCKEY_LEVEL,
+		    "cur=%d;max=%d", 
+		    keyInfoCtx->curEncryptedKeyLevel,
+		    keyInfoCtx->maxEncryptedKeyLevel);
+	return(-1);
+    }
+    ++keyInfoCtx->curEncryptedKeyLevel;
+
+    /* init Enc context */    
+    if(keyInfoCtx->encCtx != NULL) {
+	xmlSecEncCtxReset(keyInfoCtx->encCtx);
+    } else {
+	ret = xmlSecKeyInfoCtxCreateEncCtx(keyInfoCtx);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		        "xmlSecKeyInfoCtxCreateEncCtx",
+		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);		
+        }
+    }
+    xmlSecAssert2(keyInfoCtx->encCtx != NULL, -1);
+    
+    result = xmlSecEncCtxDecryptToBuffer(keyInfoCtx->encCtx, node);
+    if((result == NULL) || (xmlSecBufferGetData(result) == NULL)) {
+	/* We might have multiple EncryptedKey elements, encrypted 
+	 * for different receipints but application can enforce
+	 * correct enc key.
+	 */
+        if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_ENCKEY_DONT_STOP_ON_FAILED_DECRYPTION) != 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+			"xmlSecEncCtxDecryptToBuffer",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+	return(0);
+    }
+	 
+    ret = xmlSecKeyDataBinRead(keyInfoCtx->keyReq.keyId, key,
+			   xmlSecBufferGetData(result),
+			   xmlSecBufferGetSize(result),
+			   keyInfoCtx);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "xmlSecKeyDataBinRead",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }			   
+    --keyInfoCtx->curEncryptedKeyLevel;
+
+    return(0);
+}
+
+static int 
+xmlSecKeyDataEncryptedKeyXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+    xmlSecKeyInfoCtx keyInfoCtx2;
+    xmlSecByte *keyBuf = NULL;
+    xmlSecSize keySize = 0;
+    int res = -1;
+    int ret;
+
+    xmlSecAssert2(id == xmlSecKeyDataEncryptedKeyId, -1);
+    xmlSecAssert2(key != NULL, -1);
+    xmlSecAssert2(xmlSecKeyIsValid(key), -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(keyInfoCtx != NULL, -1);
+    xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1);
+    
+    /* dump key to a binary buffer */
+    ret = xmlSecKeyInfoCtxInitialize(&keyInfoCtx2, NULL);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "xmlSecKeyInfoCtxInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	goto done;
+    }
+    
+    ret = xmlSecKeyInfoCtxCopyUserPref(&keyInfoCtx2, keyInfoCtx);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "xmlSecKeyInfoCtxCopyUserPref",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecKeyInfoCtxFinalize(&keyInfoCtx2);
+	goto done;
+    }
+
+    keyInfoCtx2.keyReq.keyType = xmlSecKeyDataTypeAny;
+    ret = xmlSecKeyDataBinWrite(key->value->id, key, &keyBuf, &keySize, &keyInfoCtx2);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "xmlSecKeyDataBinWrite",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecKeyInfoCtxFinalize(&keyInfoCtx2);
+	goto done;
+    }
+    xmlSecKeyInfoCtxFinalize(&keyInfoCtx2);
+    
+    /* init Enc context */    
+    if(keyInfoCtx->encCtx != NULL) {
+	xmlSecEncCtxReset(keyInfoCtx->encCtx);
+    } else {
+	ret = xmlSecKeyInfoCtxCreateEncCtx(keyInfoCtx);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+			"xmlSecKeyInfoCtxCreateEncCtx",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		        XMLSEC_ERRORS_NO_MESSAGE);
+    	    goto done;	
+	}
+    }
+    xmlSecAssert2(keyInfoCtx->encCtx != NULL, -1);
+
+    ret = xmlSecEncCtxBinaryEncrypt(keyInfoCtx->encCtx, node, keyBuf, keySize);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+		    "xmlSecEncCtxBinaryEncrypt",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	goto done;	
+    }
+    
+    res = 0;
+done:
+    if(keyBuf != NULL) {
+	memset(keyBuf, 0, keySize);
+	xmlFree(keyBuf); keyBuf = NULL;
+    }
+    return(res);
+}
+
+#endif /* XMLSEC_NO_XMLENC */
+