xmlsecurityengine/xmlsec/src/xmlsec_xkms.c
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 09:29:21 +0200
changeset 0 e35f40988205
child 8 e65204f75c47
permissions -rw-r--r--
Revision: 200947 Kit: 200951

/** 
 * XML Security Library (http://www.aleksey.com/xmlsec).
 *
 * "XML Key Management Specification v 2.0" implementation
 *  http://www.w3.org/TR/xkms2/
 * 
 * This is free software; see Copyright file in the source
 * distribution for preciese wording.
 * 
 * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
 * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
 */

#include "xmlsec_config.h"
#ifndef XMLSEC_NO_XKMS
#include "xmlsec_globals.h"
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

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

#include "xmlsec_xmlsec.h"
#include "xmlsec_buffer.h"
#include "xmlsec_xmltree.h"
#include "xmlsec_keys.h"
#include "xmlsec_keysmngr.h"
#include "xmlsec_transforms.h"
#include "xmlsec_keyinfo.h"
#include "xmlsec_soap.h"
#include "xmlsec_xkms.h"
#include "xmlsec_private.h"
#include "xmlsec_privatexkms.h"
#include "xmlsec_errors.h"

#define XMLSEC_XKMS_ID_ATTRIBUTE_LEN		32

/* The ID attribute in XKMS is 'Id' */
static const xmlChar* xmlSecXkmsServerIds[] = { BAD_CAST "Id", NULL };

#ifndef XMLSEC_NO_SOAP
static int      xmlSecXkmsServerCtxWriteSoap11FatalError	(xmlSecXkmsServerCtxPtr ctx,
							         xmlNodePtr envNode);
static int      xmlSecXkmsServerCtxWriteSoap12FatalError	(xmlSecXkmsServerCtxPtr ctx,
							         xmlNodePtr envNode);
#endif /* XMLSEC_NO_SOAP */

static int	xmlSecXkmsServerCtxRequestAbstractTypeNodeRead	(xmlSecXkmsServerCtxPtr ctx,
							         xmlNodePtr* node);
static int	xmlSecXkmsServerCtxSignatureNodeRead		(xmlSecXkmsServerCtxPtr ctx, 
								 xmlNodePtr node);
static int	xmlSecXkmsServerCtxMessageExtensionNodesRead	(xmlSecXkmsServerCtxPtr ctx, 
								 xmlNodePtr* node);
static int	xmlSecXkmsServerCtxOpaqueClientDataNodeRead	(xmlSecXkmsServerCtxPtr ctx, 
								 xmlNodePtr node);
static int	xmlSecXkmsServerCtxPendingNotificationNodeRead	(xmlSecXkmsServerCtxPtr ctx, 
								 xmlNodePtr node);
static int	xmlSecXkmsServerCtxRespondWithNodesRead		(xmlSecXkmsServerCtxPtr ctx, 
								 xmlNodePtr* node);
static int	xmlSecXkmsServerCtxPendingRequestNodeRead	(xmlSecXkmsServerCtxPtr ctx,
							         xmlNodePtr* node);
static int	xmlSecXkmsServerCtxQueryKeyBindingNodeRead	(xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static int	xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeRead(xmlSecXkmsServerCtxPtr ctx,
							         xmlNodePtr* node);
static int	xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite(xmlSecXkmsServerCtxPtr ctx,
							         xmlNodePtr node,
								 xmlSecKeyPtr key);
static int	xmlSecXkmsServerCtxKeyInfoNodeWrite		(xmlSecXkmsServerCtxPtr ctx,
							    	 xmlNodePtr node,
								 xmlSecKeyPtr key);
static int	xmlSecXkmsServerCtxUseKeyWithNodesRead		(xmlSecXkmsServerCtxPtr ctx, 
								 xmlNodePtr* node);
static int	xmlSecXkmsServerCtxUseKeyWithNodesWrite		(xmlSecXkmsServerCtxPtr ctx, 
								 xmlNodePtr node,
								 xmlSecKeyPtr key);
static int	xmlSecXkmsServerCtxTimeInstantNodeRead		(xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static int	xmlSecXkmsServerCtxResultTypeNodeWrite		(xmlSecXkmsServerCtxPtr ctx, 
								 xmlNodePtr node);
static int	xmlSecXkmsServerCtxRequestSignatureValueNodeWrite(xmlSecXkmsServerCtxPtr ctx, 
								 xmlNodePtr node);
static int	xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite(xmlSecXkmsServerCtxPtr ctx,
							    	 xmlNodePtr node,
								 xmlSecKeyPtr key);
static int	xmlSecXkmsServerCtxKeyBindingNodeWrite		(xmlSecXkmsServerCtxPtr ctx,
							    	 xmlNodePtr node,
								 xmlSecKeyPtr key);
static int 	xmlSecXkmsServerCtxValidityIntervalNodeWrite	(xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node, 
								 xmlSecKeyPtr key);
static int	xmlSecXkmsServerCtxKeyBindingStatusNodeWrite	(xmlSecXkmsServerCtxPtr ctx,
							    	 xmlNodePtr node,
								 xmlSecKeyPtr key);


static const xmlSecQName2IntegerInfo gXmlSecXkmsResultMajorInfo[] = 
{
  { xmlSecXkmsNs, xmlSecResultMajorCodeSuccess,
    xmlSecXkmsResultMajorSuccess },
  { xmlSecXkmsNs, xmlSecResultMajorCodeVersionMismatch,
    xmlSecXkmsResultMajorVersionMismatch },
  { xmlSecXkmsNs, xmlSecResultMajorCodeSender, 
    xmlSecXkmsResultMajorSender },
  { xmlSecXkmsNs, xmlSecResultMajorCodeReceiver,
    xmlSecXkmsResultMajorReceiver },
  { xmlSecXkmsNs, xmlSecResultMajorCodeRepresent,     
    xmlSecXkmsResultMajorRepresent },
  { xmlSecXkmsNs, xmlSecResultMajorCodePending, 
    xmlSecXkmsResultMajorPending, },
  { NULL , NULL, 0 }	/* MUST be last in the list */
};

static const xmlSecQName2IntegerInfo gXmlSecXkmsMinorErrorInfo[] = 
{
  { xmlSecXkmsNs, xmlSecResultMinorCodeNoMatch,
    xmlSecXkmsResultMinorNoMatch },
  { xmlSecXkmsNs, xmlSecResultMinorCodeTooManyResponses, 
    xmlSecXkmsResultMinorTooManyResponses },
  { xmlSecXkmsNs, xmlSecResultMinorCodeIncomplete,
    xmlSecXkmsResultMinorIncomplete },
  { xmlSecXkmsNs, xmlSecResultMinorCodeFailure, 
    xmlSecXkmsResultMinorFailure },
  { xmlSecXkmsNs, xmlSecResultMinorCodeRefused, 
    xmlSecXkmsResultMinorRefused },
  { xmlSecXkmsNs, xmlSecResultMinorCodeNoAuthentication, 
    xmlSecXkmsResultMinorNoAuthentication },
  { xmlSecXkmsNs, xmlSecResultMinorCodeMessageNotSupported, 
    xmlSecXkmsResultMinorMessageNotSupported },
  { xmlSecXkmsNs, xmlSecResultMinorCodeUnknownResponseId, 
    xmlSecXkmsResultMinorUnknownResponseId },
  { xmlSecXkmsNs, xmlSecResultMinorCodeNotSynchronous, 
    xmlSecXkmsResultMinorSynchronous },
  { NULL, NULL, 0 }	/* MUST be last in the list */
};

static const xmlSecQName2IntegerInfo gXmlSecXkmsKeyBindingStatusInfo[] = 
{
  { xmlSecXkmsNs, xmlSecKeyBindingStatusValid, 
    xmlSecXkmsKeyBindingStatusValid },
  { xmlSecXkmsNs, xmlSecKeyBindingStatusInvalid,
    xmlSecXkmsKeyBindingStatusInvalid },
  { xmlSecXkmsNs, xmlSecKeyBindingStatusIndeterminate, 
    xmlSecXkmsKeyBindingStatusIndeterminate },
  { NULL, NULL, 0 }	/* MUST be last in the list */
};

static const xmlSecQName2BitMaskInfo gXmlSecXkmsKeyUsageInfo[] = 
{
  { xmlSecXkmsNs, xmlSecKeyUsageEncryption,
    xmlSecKeyUsageEncrypt | xmlSecKeyUsageDecrypt },
  { xmlSecXkmsNs, xmlSecKeyUsageSignature,
    xmlSecKeyUsageSign | xmlSecKeyUsageVerify },
  { xmlSecXkmsNs, xmlSecKeyUsageExchange,
    xmlSecKeyUsageKeyExchange},
  { NULL, NULL, 0 }	/* MUST be last in the list */
};

static const xmlSecQName2BitMaskInfo gXmlSecXkmsKeyBindingReasonInfo[] = 
{
    { xmlSecXkmsNs, xmlSecKeyBindingReasonIssuerTrust,
      XMLSEC_XKMS_KEY_BINDING_REASON_MASK_ISSUER_TRAST },
    { xmlSecXkmsNs, xmlSecKeyBindingReasonRevocationStatus,
      XMLSEC_XKMS_KEY_BINDING_REASON_MASK_REVOCATION_STATUS },
    { xmlSecXkmsNs, xmlSecKeyBindingReasonValidityInterval,
      XMLSEC_XKMS_KEY_BINDING_REASON_MASK_VALIDITY_INTERVAL },
    { xmlSecXkmsNs, xmlSecKeyBindingReasonSignature,
      XMLSEC_XKMS_KEY_BINDING_REASON_MASK_SIGNATURE },
    { NULL, NULL, 0 }	/* MUST be last in the list */
};

static const xmlSecQName2BitMaskInfo gXmlSecXkmsResponseMechanismInfo[] = 
{
    { xmlSecXkmsNs, xmlSecResponseMechanismRepresent,
      XMLSEC_XKMS_RESPONSE_MECHANISM_MASK_REPRESENT },
    { xmlSecXkmsNs, xmlSecResponseMechanismPending,
      XMLSEC_XKMS_RESPONSE_MECHANISM_MASK_PENDING },
    { xmlSecXkmsNs, xmlSecResponseMechanismRequestSignatureValue,
      XMLSEC_XKMS_RESPONSE_MECHANISM_MASK_REQUEST_SIGNATURE_VALUE },
    { NULL, NULL, 0 }	/* MUST be last in the list */
};

static const xmlSecQName2IntegerInfo gXmlSecXkmsFormatInfo[] = 
{
  { NULL, xmlSecXkmsFormatStrPlain, 
    xmlSecXkmsServerFormatPlain },
#ifndef XMLSEC_NO_SOAP
  { NULL, xmlSecXkmsFormatStrSoap11,
    xmlSecXkmsServerFormatSoap11 },
  { NULL, xmlSecXkmsFormatStrSoap12, 
    xmlSecXkmsServerFormatSoap12 },
#endif /* XMLSEC_NO_SOAP */
  { NULL, NULL, 0 }	/* MUST be last in the list */
};

/**
 * xmlSecXkmsServerFormatFromString:
 * @str         the string.
 *  
 * Gets xmlSecXkmsServerFormat from string @str.
 * 
 * Returns corresponding format or xmlSecXkmsServerFormatUnknown
 * if format could not be recognized.
 */
EXPORT_C 
xmlSecXkmsServerFormat 
xmlSecXkmsServerFormatFromString(const xmlChar* str) {
    int res;
    int ret;

    xmlSecAssert2(str != NULL, xmlSecXkmsServerFormatUnknown);
    
    ret = xmlSecQName2IntegerGetInteger(gXmlSecXkmsFormatInfo, NULL, str, &res);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecQName2IntegerGetInteger",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(xmlSecXkmsServerFormatUnknown);   
    }

    return((xmlSecXkmsServerFormat)res);
}

/**
 * xmlSecXkmsServerFormatToString:
 * @format:     the format.
 *
 * Gets string from @format.
 *
 * Returns string corresponding to @format or NULL if an error occurs.
 */
EXPORT_C
const xmlChar* 
xmlSecXkmsServerFormatToString (xmlSecXkmsServerFormat format) {
    xmlSecQName2IntegerInfoConstPtr info;
    
    xmlSecAssert2(format != xmlSecXkmsServerFormatUnknown, NULL);

    info = xmlSecQName2IntegerGetInfo(gXmlSecXkmsFormatInfo, format);
    if(info == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecQName2IntegerGetInfo",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
        return(NULL);
    }
    return(info->qnameLocalPart);
}

/**
 * xmlSecXkmsServerCtxCreate:
 * @keysMngr: 	the pointer to keys manager.
 *
 * Creates XKMS request server side processing context.
 * The caller is responsible for destroying returend object by calling 
 * #xmlSecXkmsServerCtxDestroy function.
 *
 * Returns pointer to newly allocated context object or NULL if an error
 * occurs.
 */
EXPORT_C
xmlSecXkmsServerCtxPtr	
xmlSecXkmsServerCtxCreate(xmlSecKeysMngrPtr keysMngr) {
    xmlSecXkmsServerCtxPtr ctx;
    int ret;
    
    ctx = (xmlSecXkmsServerCtxPtr) xmlMalloc(sizeof(xmlSecXkmsServerCtx));
    if(ctx == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_MALLOC_FAILED,
		    "sizeof(xmlSecXkmsServerCtx)=%d", 
		    sizeof(xmlSecXkmsServerCtx));
	return(NULL);
    }
    
    ret = xmlSecXkmsServerCtxInitialize(ctx, keysMngr);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecXkmsServerCtxDestroy(ctx);
	return(NULL);   
    }
    return(ctx);    
}

/**
 * xmlSecXkmsServerCtxDestroy:
 * @ctx:	the pointer to XKMS processing context.
 *
 * Destroy context object created with #xmlSecXkmsServerCtxCreate function.
 */
EXPORT_C
void  
xmlSecXkmsServerCtxDestroy(xmlSecXkmsServerCtxPtr ctx) {
    xmlSecAssert(ctx != NULL);
    
    xmlSecXkmsServerCtxFinalize(ctx);
    xmlFree(ctx);
}

/**
 * xmlSecXkmsServerCtxInitialize:
 * @ctx:	the pointer to XKMS processing context.
 * @keysMngr: 	the pointer to keys manager.
 *
 * Initializes XKMS element processing context.
 * The caller is responsible for cleaing up returend object by calling 
 * #xmlSecXkmsServerCtxFinalize function.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsServerCtxInitialize(xmlSecXkmsServerCtxPtr ctx, xmlSecKeysMngrPtr keysMngr) {
    int ret;
    
    xmlSecAssert2(ctx != NULL, -1);
    
    memset(ctx, 0, sizeof(xmlSecXkmsServerCtx));

    ctx->resultMajor 	= xmlSecXkmsResultMajorSuccess;
    ctx->resultMinor 	= xmlSecXkmsResultMinorNone;
    ctx->responseLimit  = XMLSEC_XKMS_NO_RESPONSE_LIMIT;
    ctx->idLen		= XMLSEC_XKMS_ID_ATTRIBUTE_LEN;

    /* initialize key info */
    ret = xmlSecKeyInfoCtxInitialize(&(ctx->keyInfoReadCtx), keysMngr);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyInfoCtxInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);   
    }
    ctx->keyInfoReadCtx.mode = xmlSecKeyInfoModeRead;
    
    ret = xmlSecKeyInfoCtxInitialize(&(ctx->keyInfoWriteCtx), keysMngr);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyInfoCtxInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);   
    }
    ctx->keyInfoWriteCtx.mode = xmlSecKeyInfoModeWrite;

    /* enabled RespondWith */
    ret = xmlSecPtrListInitialize(&(ctx->enabledRespondWithIds), xmlSecXkmsRespondWithIdListId);
    if(ret < 0) { 
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* enabled ServerRequest */
    ret = xmlSecPtrListInitialize(&(ctx->enabledServerRequestIds), xmlSecXkmsServerRequestIdListId);
    if(ret < 0) { 
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }



    /* initialize keys list */
    ret = xmlSecPtrListInitialize(&(ctx->keys), xmlSecKeyPtrListId);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);   
    }

    /* initialize RespondWith list */
    ret = xmlSecPtrListInitialize(&(ctx->respWithList), xmlSecXkmsRespondWithIdListId);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);   
    }

    return(0);
}

/**
 * xmlSecXkmsServerCtxFinalize:
 * @ctx:	the pointer to XKMS processing context.
 *
 * Cleans up @ctx object.
 */
EXPORT_C
void 
xmlSecXkmsServerCtxFinalize(xmlSecXkmsServerCtxPtr ctx) {
    xmlSecAssert(ctx != NULL);

    xmlSecXkmsServerCtxReset(ctx);
    
    if(ctx->expectedService != NULL) {
	xmlFree(ctx->expectedService);
    }
    if(ctx->idPrefix != NULL) {
	xmlFree(ctx->idPrefix);
    }

    xmlSecKeyInfoCtxFinalize(&(ctx->keyInfoReadCtx));
    xmlSecKeyInfoCtxFinalize(&(ctx->keyInfoWriteCtx));
    xmlSecPtrListFinalize(&(ctx->enabledRespondWithIds));
    xmlSecPtrListFinalize(&(ctx->enabledServerRequestIds));
    xmlSecPtrListFinalize(&(ctx->keys));
    xmlSecPtrListFinalize(&(ctx->respWithList));
    memset(ctx, 0, sizeof(xmlSecXkmsServerCtx));
}

/**
 * xmlSecXkmsServerCtxReset:
 * @ctx:	the pointer to XKMS processing context.
 *
 * Resets @ctx object, user settings are not touched.
 */
EXPORT_C
void 
xmlSecXkmsServerCtxReset(xmlSecXkmsServerCtxPtr ctx) {
    xmlSecAssert(ctx != NULL);
    
    ctx->resultMajor = xmlSecXkmsResultMajorSuccess;
    ctx->resultMinor = xmlSecXkmsResultMinorNone;
    xmlSecKeyInfoCtxReset(&(ctx->keyInfoReadCtx));
    xmlSecKeyInfoCtxReset(&(ctx->keyInfoWriteCtx));
    xmlSecPtrListEmpty(&(ctx->keys));
    xmlSecPtrListEmpty(&(ctx->respWithList));

    ctx->requestNode            = NULL;    
    ctx->opaqueClientDataNode   = NULL;    
    ctx->firtsMsgExtNode 	= NULL;
    ctx->keyInfoNode		= NULL;
    ctx->requestId		= xmlSecXkmsServerRequestIdUnknown;
    
    if(ctx->id != NULL) {
	xmlFree(ctx->id); ctx->id = NULL;
    }
    if(ctx->service != NULL) {
	xmlFree(ctx->service); ctx->service = NULL;
    }
    if(ctx->nonce != NULL) {
	xmlFree(ctx->nonce); ctx->nonce = NULL;
    }
    if(ctx->originalRequestId != NULL) {
	xmlFree(ctx->originalRequestId); ctx->originalRequestId = NULL;
    }
    if(ctx->pendingNotificationMechanism != NULL) {
	xmlFree(ctx->pendingNotificationMechanism); 
	ctx->pendingNotificationMechanism = NULL;
    }
    if(ctx->pendingNotificationIdentifier != NULL) {
	xmlFree(ctx->pendingNotificationIdentifier); 
	ctx->pendingNotificationIdentifier = NULL;
    }
    if(ctx->compoundRequestContexts != NULL) {
        xmlSecPtrListDestroy(ctx->compoundRequestContexts);
        ctx->compoundRequestContexts = NULL;
    }
    
    ctx->responseLimit 		= XMLSEC_XKMS_NO_RESPONSE_LIMIT;
    ctx->responseMechanismMask  = 0;
}

/**
 * xmlSecXkmsServerCtxCopyUserPref:
 * @dst:	the pointer to destination context.
 * @src:	the pointer to source context.
 * 
 * Copies user preference from @src context to @dst.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsServerCtxCopyUserPref(xmlSecXkmsServerCtxPtr dst, xmlSecXkmsServerCtxPtr src) {
    int ret;
    
    xmlSecAssert2(dst != NULL, -1);
    xmlSecAssert2(src != NULL, -1);

    dst->userData 	= src->userData;
    dst->flags		= src->flags;
    dst->flags2		= src->flags2;

    ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoReadCtx), &(src->keyInfoReadCtx));
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyInfoCtxCopyUserPref",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoWriteCtx), &(src->keyInfoWriteCtx));
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyInfoCtxCopyUserPref",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    if(src->expectedService != NULL) {
	dst->expectedService = xmlStrdup(src->expectedService);
	if(dst->expectedService == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlStrdup",
		        XMLSEC_ERRORS_R_MALLOC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    }

    if(src->idPrefix != NULL) {
	dst->idPrefix = xmlStrdup(src->idPrefix);
	if(dst->idPrefix == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlStrdup",
		        XMLSEC_ERRORS_R_MALLOC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    }
    src->idLen = dst->idLen;


    ret = xmlSecPtrListCopy(&(dst->enabledRespondWithIds), &(src->enabledRespondWithIds));
    if(ret < 0) { 
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListCopy",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    ret = xmlSecPtrListCopy(&(dst->enabledServerRequestIds), &(src->enabledServerRequestIds));
    if(ret < 0) { 
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListCopy",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    return(0);
} 

/** 
 * xmlSecXkmsServerCtxProcess: 
 * @ctx:	the pointer to XKMS processing context.
 * @node:	the pointer to request node.
 * @format:     the request/response format.
 * @doc:	the pointer to response parent XML document (might be NULL).
 * 
 * Reads XKMS request from @node and creates response to a newly created node. 
 * Caller is responsible for adding the returned node to the XML document.
 *
 * Returns pointer to newly created XKMS response node or NULL
 * if an error occurs.
 */
EXPORT_C
xmlNodePtr 
xmlSecXkmsServerCtxProcess(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, 
                              xmlSecXkmsServerFormat format, xmlDocPtr doc) {
    int ret;

    xmlSecAssert2(ctx != NULL, NULL);
    xmlSecAssert2(ctx->requestId == NULL, NULL);
    xmlSecAssert2(ctx->requestNode == NULL, NULL);
    xmlSecAssert2(node != NULL, NULL);

    ctx->requestNode = xmlSecXkmsServerCtxRequestUnwrap(ctx, node, format);
    if(ctx->requestNode == NULL) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxRequestUnwrap",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "node=%s",
		    xmlSecErrorsSafeString(node->name));
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	goto done;
    }    
        
    ret = xmlSecXkmsServerCtxRequestRead(ctx, ctx->requestNode);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestIdListFindByNode",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "ctx->requestNode=%s",
		    xmlSecErrorsSafeString(ctx->requestNode->name));
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	goto done;
    }    

    ret = xmlSecXkmsServerRequestExecute(ctx->requestId, ctx);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestExecute",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "ctx->requestNode=%s",
		    xmlSecErrorsSafeString(ctx->requestNode->name));
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	goto done;
    }

done:
    /* always try to write response back */    
    if(ctx->requestId != NULL) {
        xmlNodePtr respNode;
        xmlNodePtr wrappedRespNode;
        
        respNode = xmlSecXkmsServerCtxResponseWrite(ctx, doc);
        if(respNode == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerCtxResponseWrite",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "ctx->requestNode=%s",
		        xmlSecErrorsSafeString(ctx->requestNode->name));
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            goto error;    
        }
    

        wrappedRespNode = xmlSecXkmsServerCtxResponseWrap(ctx, respNode, format, doc);
        if(wrappedRespNode == NULL) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerCtxResponseWrite",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "ctx->requestNode=%s",
		        xmlSecErrorsSafeString(ctx->requestNode->name));
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            xmlFreeNode(respNode);
            goto error;    
        }

        return(wrappedRespNode);
    }
    
error:
    /* last attempt: create fatatl error response */
    return(xmlSecXkmsServerCtxFatalErrorResponseCreate(ctx, format, doc));
}

/** 
 * xmlSecXkmsServerCtxRequestRead: 
 * @ctx:	the pointer to XKMS processing context.
 * @node:	the pointer to request node.
 *
 * Reads XKMS request from @node and stores data in @ctx.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsServerCtxRequestRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    int ret;
    
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(ctx->requestId == NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* find out what the request is */
    if(xmlSecPtrListGetSize(&(ctx->enabledServerRequestIds)) > 0) {
	ctx->requestId = xmlSecXkmsServerRequestIdListFindByNode(&(ctx->enabledServerRequestIds), node);
    } else {
	ctx->requestId = xmlSecXkmsServerRequestIdListFindByNode(xmlSecXkmsServerRequestIdsGet(), node);
    }
    if(ctx->requestId == xmlSecXkmsServerRequestIdUnknown) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestIdListFindByNode",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "node=%s",
		    xmlSecErrorsSafeString(node->name));
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorMessageNotSupported);
	return(-1);
    }

    xmlSecAddIDs(node->doc, node, xmlSecXkmsServerIds);
    ret = xmlSecXkmsServerRequestNodeRead(ctx->requestId, ctx, node);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "request=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctx->requestId)));
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	return(-1);
    }
        
    return(0);
}

/** 
 * xmlSecXkmsServerCtxResponseWrite: 
 * @ctx:	the pointer to XKMS processing context.
 * @doc:	the pointer to response parent XML document (might be NULL).
 *
 * Writes XKMS response from context to a newly created node. Caller is 
 * responsible for adding the returned node to the XML document.
 *
 * Returns pointer to newly created XKMS response node or NULL
 * if an error occurs.
 */
EXPORT_C
xmlNodePtr
xmlSecXkmsServerCtxResponseWrite(xmlSecXkmsServerCtxPtr ctx, xmlDocPtr doc) {
    xmlNodePtr respNode;
    
    xmlSecAssert2(ctx != NULL, NULL);
    xmlSecAssert2(ctx->requestId != NULL, NULL);

    /* now write results */
    respNode = xmlSecXkmsServerRequestNodeWrite(ctx->requestId, ctx, doc, NULL);
    if(respNode == NULL) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "request=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctx->requestId)));
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
        return(NULL);
    }
    
    return(respNode);
}

/**
 * xmlSecXkmsServerCtxRequestUnwrap:
 * @ctx:	the pointer to XKMS processing context.
 * @node:	the pointer to request node.
 * @format:     the request/response format.
 * 
 * Removes SOAP or other envelope from XKMS request.
 *
 * Returns pointer to "real" XKMS request node or NULL if an error occurs. 
 */
EXPORT_C
xmlNodePtr 
xmlSecXkmsServerCtxRequestUnwrap(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node,  xmlSecXkmsServerFormat format) {
    xmlNodePtr result = NULL;
        
    xmlSecAssert2(ctx != NULL, NULL);
    xmlSecAssert2(node != NULL, NULL);
    
    switch(format) {
    case xmlSecXkmsServerFormatPlain:
        result = node;
        break;
#ifndef XMLSEC_NO_SOAP
    case xmlSecXkmsServerFormatSoap11:
        /* verify that it is actually soap Envelope node */
        if(xmlSecSoap11CheckEnvelope(node) != 1) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap11CheckEnvelope",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }   
        
        /* check that Body has exactly one entry */
        if(xmlSecSoap11GetBodyEntriesNumber(node) != 1) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap11GetBodyEntriesNumber",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        
        /* this one enntry is our xkms request */
        result = xmlSecSoap11GetBodyEntry(node, 0);
        if(result == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap11GetBodyEntry",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        
        break;
    case xmlSecXkmsServerFormatSoap12:
        /* verify that it is actually soap Envelope node */
        if(xmlSecSoap12CheckEnvelope(node) != 1) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap12CheckEnvelope",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }   
        
        /* check that Body has exactly one entry */
        if(xmlSecSoap12GetBodyEntriesNumber(node) != 1) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap12GetBodyEntriesNumber",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        
        /* this one enntry is our xkms request */
        result = xmlSecSoap12GetBodyEntry(node, 0);
        if(result == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap12GetBodyEntry",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        
        break;
#endif /* XMLSEC_NO_SOAP */
    default:
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_NOT_IMPLEMENTED,
		    "format=%d",
                    format);
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	return(NULL);
    }
    
    return(result);
}

/** 
 * xmlSecXkmsServerCtxResponseWrap: 
 * @ctx:	the pointer to XKMS processing context.
 * @node:	the pointer to response node.
 * @format:     the request/response format.
 * @doc:	the pointer to response parent XML document (might be NULL).
 *
 * Creates SOAP or other envelope around XKMS response.
 * Caller is responsible for adding the returned node to the XML document.
 *
 * Returns pointer to newly created response envelope node or NULL
 * if an error occurs.
 */
EXPORT_C
xmlNodePtr 
xmlSecXkmsServerCtxResponseWrap(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecXkmsServerFormat format, xmlDocPtr doc) {
    xmlNodePtr result = NULL;
    
    xmlSecAssert2(ctx != NULL, NULL);
    xmlSecAssert2(node != NULL, NULL);
    
    switch(format) {
    case xmlSecXkmsServerFormatPlain:
        result = node; /* do nothing */
        break;
#ifndef XMLSEC_NO_SOAP
    case xmlSecXkmsServerFormatSoap11:
        result = xmlSecSoap11CreateEnvelope(doc);
        if(result == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap11CreateEnvelope",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        
        if(xmlSecSoap11AddBodyEntry(result, node) == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap11AddBodyEntry",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        break;
    case xmlSecXkmsServerFormatSoap12:
        result = xmlSecSoap12CreateEnvelope(doc);
        if(result == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap12CreateEnvelope",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        
        if(xmlSecSoap12AddBodyEntry(result, node) == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap12AddBodyEntry",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        break;
#endif /* XMLSEC_NO_SOAP */
    default:
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_NOT_IMPLEMENTED,
		    "format=%d",
                    format);
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	return(NULL);
    }
    
    return(result);
}

/** 
 * xmlSecXkmsServerCtxFatalErrorResponseCreate: 
 * @ctx:	the pointer to XKMS processing context.
 * @format:     the request/response format.
 * @doc:	the pointer to response parent XML document (might be NULL).
 *
 * Creates a "fatal error" SOAP or other envelope respons. Caller is 
 * responsible for adding the returned node to the XML document.
 *
 * Returns pointer to newly created fatal error response (it might be NULL).
 */
EXPORT_C
xmlNodePtr 
xmlSecXkmsServerCtxFatalErrorResponseCreate(xmlSecXkmsServerCtxPtr ctx, xmlSecXkmsServerFormat format, xmlDocPtr doc) {
    xmlNodePtr result = NULL;
    int ret;
    
    xmlSecAssert2(ctx != NULL, NULL);

    /* make sure that we have an error */
    if(ctx->resultMajor == xmlSecXkmsResultMajorSuccess) {
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
    }
    
    switch(format) {
    case xmlSecXkmsServerFormatPlain:
        /* try to create fatal error response with XKMS Status request */
        result = xmlSecXkmsServerRequestNodeWrite(xmlSecXkmsServerRequestResultId, ctx, doc, NULL);
        if(result == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerRequestNodeWrite",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    return(NULL);
        }
        break;
#ifndef XMLSEC_NO_SOAP
    case xmlSecXkmsServerFormatSoap11:
        result = xmlSecSoap11CreateEnvelope(doc);
        if(result == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap11CreateEnvelope",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        
        ret = xmlSecXkmsServerCtxWriteSoap11FatalError(ctx, result);
        if(ret < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerCtxWriteSoap11FatalError",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            xmlFreeNode(result);
	    return(NULL);
        }
                
        break;
    case xmlSecXkmsServerFormatSoap12:
        result = xmlSecSoap12CreateEnvelope(doc);
        if(result == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap12CreateEnvelope",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	    return(NULL);
        }
        
        ret = xmlSecXkmsServerCtxWriteSoap12FatalError(ctx, result);
        if(ret < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerCtxWriteSoap12FatalError",
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            xmlFreeNode(result);
	    return(NULL);
        }
                
        break;
#endif /* XMLSEC_NO_SOAP */
    default:
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_NOT_IMPLEMENTED,
		    "format=%d",
                    format);
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	return(NULL);
    }
    
    return(result);
}

#ifndef XMLSEC_NO_SOAP
static int 
xmlSecXkmsServerCtxWriteSoap11FatalError(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr envNode) {
    const xmlChar* faultCodeHref = NULL;
    const xmlChar* faultCodeLocalPart = NULL;
    xmlChar* faultString = NULL;
    int len;
    
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(envNode != NULL, -1);

    if((ctx->resultMajor == xmlSecXkmsResultMajorVersionMismatch) ||
       (ctx->requestNode == NULL)) {
        /* we were not able to parse the envelope or its general version mismatch error */
        faultCodeHref = xmlSecSoap11Ns;
        faultCodeLocalPart = xmlSecSoapFaultCodeVersionMismatch;
        faultString = xmlStrdup(xmlSecXkmsSoapFaultReasonUnsupportedVersion);
        if(faultString == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlStrdup",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
    } else if((ctx->resultMajor == xmlSecXkmsResultMajorSender) && 
              (ctx->requestId == NULL)) {
        /* we understood the request but were not able to parse input message */
        faultCodeHref = xmlSecSoap11Ns;
        faultCodeLocalPart = xmlSecSoapFaultCodeClient;

        len = xmlStrlen(BAD_CAST xmlSecErrorsSafeString(ctx->requestNode->name)) +
              xmlStrlen(xmlSecXkmsSoapFaultReasonMessageInvalid) + 1;
        faultString = xmlMalloc(len + 1);
        if(faultString == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlMalloc",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
        xmlSecStrPrintf(faultString, len , xmlSecXkmsSoapFaultReasonMessageInvalid,
                        xmlSecErrorsSafeString(ctx->requestNode->name));        
    } else if((ctx->resultMajor == xmlSecXkmsResultMajorReceiver) &&
              (ctx->requestId == NULL)) {
        /* we understood the request but were not able to process it */
        faultCodeHref = xmlSecSoap11Ns;
        faultCodeLocalPart = xmlSecSoapFaultCodeServer;
        faultString = xmlStrdup(xmlSecXkmsSoapFaultReasonServiceUnavailable);
        if(faultString == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlStrdup",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
    } else if((ctx->requestId == NULL) && (ctx->requestNode != NULL)) {
        /* we parsed the envelope but were not able to understand this request */
        faultCodeHref = xmlSecSoap11Ns;
        faultCodeLocalPart = xmlSecSoapFaultCodeClient;

        len = xmlStrlen(BAD_CAST xmlSecErrorsSafeString(ctx->requestNode->name)) + 
              xmlStrlen(xmlSecXkmsSoapFaultReasonMessageNotSupported) + 1;
        faultString = xmlMalloc(len + 1);
        if(faultString == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlMalloc",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
        xmlSecStrPrintf(faultString, len , xmlSecXkmsSoapFaultReasonMessageNotSupported,
                        xmlSecErrorsSafeString(ctx->requestNode->name));
    } else {
        /* just some error */
        faultCodeHref = xmlSecSoap11Ns;
        faultCodeLocalPart = xmlSecSoapFaultCodeServer;
        faultString = xmlStrdup(xmlSecXkmsSoapFaultReasonServiceUnavailable);
        if(faultString == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlStrdup",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
    }
    
    if(xmlSecSoap11AddFaultEntry(envNode, faultCodeHref, faultCodeLocalPart, faultString, NULL) == NULL) {
        xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecSoap11AddFaultEntry",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
        xmlFree(faultString);    
        return(-1);
    }

    xmlFree(faultString);    
    return(0);
}

static int 
xmlSecXkmsServerCtxWriteSoap12FatalError(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr envNode) {
    xmlSecSoap12FaultCode faultCode = xmlSecSoap12FaultCodeUnknown;
    const xmlChar* faultSubCodeHref = NULL;
    const xmlChar* faultSubCodeLocalPart = NULL;
    xmlChar* faultReason = NULL;
    int len;
    xmlNodePtr faultNode;
    
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(envNode != NULL, -1);

    if((ctx->resultMajor == xmlSecXkmsResultMajorVersionMismatch) ||
       (ctx->requestNode == NULL)) {
        /* we were not able to parse the envelope or its general version mismatch error */
        faultCode = xmlSecSoap12FaultCodeVersionMismatch;
        faultReason = xmlStrdup(xmlSecXkmsSoapFaultReasonUnsupportedVersion);
        if(faultReason == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlStrdup",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
    } else if((ctx->resultMajor == xmlSecXkmsResultMajorSender) && 
              (ctx->requestId == NULL)) {
        /* we understood the request but were not able to parse input message */
        faultCode = xmlSecSoap12FaultCodeSender;
        faultSubCodeHref = xmlSecXkmsNs;
        faultSubCodeLocalPart = xmlSecXkmsSoapSubcodeValueMessageNotSupported;

        len = xmlStrlen(BAD_CAST xmlSecErrorsSafeString(ctx->requestNode->name)) +
              xmlStrlen(xmlSecXkmsSoapFaultReasonMessageInvalid) + 1;
        faultReason = xmlMalloc(len + 1);
        if(faultReason == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlMalloc",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
        xmlSecStrPrintf(faultReason, len , xmlSecXkmsSoapFaultReasonMessageInvalid,
                        xmlSecErrorsSafeString(ctx->requestNode->name));        
    } else if((ctx->resultMajor == xmlSecXkmsResultMajorReceiver) &&
              (ctx->requestId == NULL)) {
        /* we understood the request but were not able to process it */
        faultCode = xmlSecSoap12FaultCodeReceiver;
        faultReason = xmlStrdup(xmlSecXkmsSoapFaultReasonServiceUnavailable);
        if(faultReason == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlStrdup",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
    } else if((ctx->requestId == NULL) && (ctx->requestNode != NULL)) {
        /* we parsed the envelope but were not able to understand this request */
        faultCode = xmlSecSoap12FaultCodeSender;
        faultSubCodeHref = xmlSecXkmsNs;
        faultSubCodeLocalPart = xmlSecXkmsSoapSubcodeValueBadMessage;

        len = xmlStrlen(BAD_CAST xmlSecErrorsSafeString(ctx->requestNode->name)) + 
              xmlStrlen(xmlSecXkmsSoapFaultReasonMessageNotSupported) + 1;
        faultReason = xmlMalloc(len + 1);
        if(faultReason == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlMalloc",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
        xmlSecStrPrintf(faultReason, len , xmlSecXkmsSoapFaultReasonMessageNotSupported,
                        xmlSecErrorsSafeString(ctx->requestNode->name));
    } else {
        /* just some error */
        faultCode = xmlSecSoap12FaultCodeReceiver;
        faultReason = xmlStrdup(xmlSecXkmsSoapFaultReasonServiceUnavailable);
        if(faultReason == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlStrdup",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
            return(-1);
        }
    }
    xmlSecAssert2(faultCode != xmlSecSoap12FaultCodeUnknown, -1);
    xmlSecAssert2(faultReason != NULL, -1);
    
    faultNode = xmlSecSoap12AddFaultEntry(envNode, faultCode, faultReason, 
                                    xmlSecXkmsSoapFaultReasonLang, NULL, NULL);
    if(faultNode == NULL) {
        xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecSoap12AddFaultEntry",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
        xmlFree(faultReason);    
        return(-1);
    }
    xmlFree(faultReason);    

    if((faultSubCodeHref != NULL) && (faultSubCodeLocalPart != NULL)) {
        /* make sure that we have subcode (xkms) namespace declared */
        if(xmlNewNs(faultNode, faultSubCodeHref, BAD_CAST "xkms") == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlNewNs",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        "ns=%s",
		        xmlSecErrorsSafeString(faultSubCodeHref));
            return(-1);
        }
        if(xmlSecSoap12AddFaultSubcode(faultNode, faultSubCodeHref, faultSubCodeLocalPart) == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecSoap12AddFaultSubcode",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "href=%s,value=%s",
		        xmlSecErrorsSafeString(faultSubCodeHref),
		        xmlSecErrorsSafeString(faultSubCodeLocalPart));
            return(-1);
        }
    }

    return(0);
}

#endif /* XMLSEC_NO_SOAP */


/** 
 * xmlSecXkmsServerCtxSetResult: 
 * @ctx:	 the pointer to XKMS processing context.
 * @resultMajor: the major result code.
 * @resultMinor: the minor result code.
 * 
 * Sets the major/minor result code in the context if no other result is already
 * reported.
 */
EXPORT_C
void 
xmlSecXkmsServerCtxSetResult(xmlSecXkmsServerCtxPtr ctx, xmlSecXkmsResultMajor resultMajor, 
                             xmlSecXkmsResultMinor resultMinor) {
    xmlSecAssert(ctx != NULL);
    
    if((ctx->resultMajor == xmlSecXkmsResultMajorSuccess) && 
       (resultMinor != xmlSecXkmsResultMajorSuccess)) {
	ctx->resultMajor = resultMajor;
	ctx->resultMinor = resultMinor;
    } else if((ctx->resultMajor == xmlSecXkmsResultMajorSuccess) && 
       (ctx->resultMinor == xmlSecXkmsResultMinorNone)) {
	xmlSecAssert(resultMajor == xmlSecXkmsResultMajorSuccess);
	
	ctx->resultMinor = resultMinor;
    }
}


/**
 * xmlSecXkmsServerCtxDebugDump:
 * @ctx:	the pointer to XKMS processing context.
 * @output:	the pointer to output FILE.
 *
 * Prints the debug information about @ctx to @output.
 */
EXPORT_C
void 
xmlSecXkmsServerCtxDebugDump(xmlSecXkmsServerCtxPtr ctx, FILE* output) {
    xmlSecAssert(ctx != NULL);
    xmlSecAssert(output != NULL);
    
    fprintf(output, "= XKMS SERVER CONTEXT: %s\n",
	    (ctx->requestId != xmlSecXkmsServerRequestIdUnknown && 
	     xmlSecXkmsServerRequestKlassGetName(ctx->requestId)) ? 
		xmlSecXkmsServerRequestKlassGetName(ctx->requestId) :
		BAD_CAST "NULL");

    xmlSecQName2IntegerDebugDump(gXmlSecXkmsResultMajorInfo, 
		ctx->resultMajor, BAD_CAST "resultMajor", output);    
    xmlSecQName2IntegerDebugDump(gXmlSecXkmsMinorErrorInfo, 
		ctx->resultMinor, BAD_CAST "resultMinor", output);    

    fprintf(output, "== id: %s\n", 
		(ctx->id) ? ctx->id : BAD_CAST "");
    fprintf(output, "== service: %s\n", 
		(ctx->service) ? ctx->service : BAD_CAST "");
    fprintf(output, "== nonce: %s\n", 
		(ctx->nonce) ? ctx->nonce : BAD_CAST "");
    fprintf(output, "== originalRequestId: %s\n", 
		(ctx->originalRequestId) ? ctx->originalRequestId : BAD_CAST "");
    fprintf(output, "== pendingNotificationMechanism: %s\n", 
		(ctx->pendingNotificationMechanism) ? 
		    ctx->pendingNotificationMechanism : 
		    BAD_CAST "");
    fprintf(output, "== pendingNotificationIdentifier: %s\n", 
		(ctx->pendingNotificationIdentifier) ? 
		    ctx->pendingNotificationIdentifier : 
		    BAD_CAST "");
    if(ctx->responseLimit != XMLSEC_XKMS_NO_RESPONSE_LIMIT) {
        fprintf(output, "== ResponseLimit: %d\n", ctx->responseLimit);
    }
    xmlSecQName2BitMaskDebugDump(gXmlSecXkmsResponseMechanismInfo, 
		ctx->responseMechanismMask, BAD_CAST "responseMechanism", output);    

    if(ctx->expectedService != NULL) {    
        fprintf(output, "== expected service: %s\n", ctx->expectedService);
    }
    fprintf(output, "== flags: 0x%08x\n", ctx->flags);
    fprintf(output, "== flags2: 0x%08x\n", ctx->flags2);

    fprintf(output, "== Key Info Read Ctx:\n");
    xmlSecKeyInfoCtxDebugDump(&(ctx->keyInfoReadCtx), output);
    
    fprintf(output, "== Key Info Write Ctx:\n");
    xmlSecKeyInfoCtxDebugDump(&(ctx->keyInfoWriteCtx), output);

    if(xmlSecPtrListGetSize(&(ctx->enabledRespondWithIds)) > 0) {
	fprintf(output, "== Enabled RespondWith: ");
	xmlSecTransformIdListDebugDump(&(ctx->enabledRespondWithIds), output);
    } else {
	fprintf(output, "== Enabled RespondWith: all\n");
    }

    if(xmlSecPtrListGetSize(&(ctx->enabledServerRequestIds)) > 0) {
	fprintf(output, "== Enabled ServerRequest: ");
	xmlSecTransformIdListDebugDump(&(ctx->enabledServerRequestIds), output);
    } else {
	fprintf(output, "== Enabled ServerRequest: all\n");
    }

    fprintf(output, "== RespondWith List:\n");
    xmlSecPtrListDebugDump(&(ctx->respWithList), output);

    fprintf(output, "== Keys:\n");
    xmlSecPtrListDebugDump(&(ctx->keys), output);
    
    if(ctx->compoundRequestContexts != NULL) {
        fprintf(output, "== Compound Request:\n");
        xmlSecPtrListDebugDump(ctx->compoundRequestContexts, output);
    }
}

/**
 * xmlSecXkmsServerCtxDebugXmlDump:
 * @ctx:	the pointer to XKMS processing context.
 * @output:	the pointer to output FILE.
 *
 * Prints the debug information about @ctx to @output in XML format.
 */
EXPORT_C
void 
xmlSecXkmsServerCtxDebugXmlDump(xmlSecXkmsServerCtxPtr ctx, FILE* output) {
    xmlSecAssert(ctx != NULL);
    xmlSecAssert(output != NULL);

    fprintf(output, "<XkmsServerRequestContext name=\"%s\">\n",
	    (ctx->requestId != xmlSecXkmsServerRequestIdUnknown && 
	     xmlSecXkmsServerRequestKlassGetName(ctx->requestId)) ? 
		xmlSecXkmsServerRequestKlassGetName(ctx->requestId) :
		BAD_CAST "NULL");

    xmlSecQName2IntegerDebugXmlDump(gXmlSecXkmsResultMajorInfo, 
		ctx->resultMajor, BAD_CAST "MajorError", output);    
    xmlSecQName2IntegerDebugXmlDump(gXmlSecXkmsMinorErrorInfo, 
		ctx->resultMinor, BAD_CAST "MinorError", output);    

    fprintf(output, "<Id>%s</Id>\n", 
		(ctx->id) ? ctx->id : BAD_CAST "");
    fprintf(output, "<Service>%s</Service>\n", 
		(ctx->service) ? ctx->service : BAD_CAST "");
    fprintf(output, "<Nonce>%s</Nonce>\n", 
		(ctx->nonce) ? ctx->nonce : BAD_CAST "");
    fprintf(output, "<OriginalRequestId>%s</OriginalRequestId>\n", 
		(ctx->originalRequestId) ? ctx->originalRequestId : BAD_CAST "");
    fprintf(output, "<PendingNotificationMechanism>%s</PendingNotificationMechanism>\n", 
		(ctx->pendingNotificationMechanism) ? 
		    ctx->pendingNotificationMechanism : 
		    BAD_CAST "");
    fprintf(output, "<PendingNotificationIdentifier>%s</PendingNotificationIdentifier>\n", 
		(ctx->pendingNotificationIdentifier) ? 
		    ctx->pendingNotificationIdentifier : 
		    BAD_CAST "");
    if(ctx->responseLimit != XMLSEC_XKMS_NO_RESPONSE_LIMIT) {
        fprintf(output, "<ResponseLimit>%d</ResponseLimit>\n", ctx->responseLimit);
    }
    xmlSecQName2BitMaskDebugXmlDump(gXmlSecXkmsResponseMechanismInfo, 
		ctx->responseMechanismMask, BAD_CAST "ResponseMechanism", output);    


    if(ctx->expectedService != NULL) {    
        fprintf(output, "<ExpectedService>%s</ExpectedService>\n", ctx->expectedService);
    }
    fprintf(output, "<Flags>%08x</Flags>\n", ctx->flags);
    fprintf(output, "<Flags2>%08x</Flags2>\n", ctx->flags2);

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

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

    if(xmlSecPtrListGetSize(&(ctx->enabledRespondWithIds)) > 0) {
	fprintf(output, "<EnabledRespondWith>\n");
	xmlSecTransformIdListDebugXmlDump(&(ctx->enabledRespondWithIds), output);
	fprintf(output, "</EnabledRespondWith>\n");
    } else {
	fprintf(output, "<EnabledRespondWith>all</EnabledRespondWith>\n");
    }

    if(xmlSecPtrListGetSize(&(ctx->enabledServerRequestIds)) > 0) {
	fprintf(output, "<EnabledServerRequest>\n");
	xmlSecTransformIdListDebugXmlDump(&(ctx->enabledServerRequestIds), output);
	fprintf(output, "</EnabledServerRequest>\n");
    } else {
	fprintf(output, "<EnabledServerRequest>all</EnabledServerRequest>\n");
    }


    fprintf(output, "<RespondWithList>\n");
    xmlSecPtrListDebugXmlDump(&(ctx->respWithList), output);
    fprintf(output, "</RespondWithList>\n");

    fprintf(output, "<Keys>\n");
    xmlSecPtrListDebugXmlDump(&(ctx->keys), output);
    fprintf(output, "</Keys>\n");

    if(ctx->compoundRequestContexts != NULL) {
        fprintf(output, "<CompoundRequest>\n");
        xmlSecPtrListDebugXmlDump(ctx->compoundRequestContexts, output);
        fprintf(output, "</CompoundRequest>\n");
    }

    fprintf(output, "</XkmsServerRequestContext>\n");
}

/**
 *  <xkms:MessageAbstractType Id Service Nonce?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *  
 *  <xkms:RequestAbstractType Id Service Nonce? OriginalRequestId? ResponseLimit?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:ResponseMechanism>*
 *      <xkms:RespondWith>*
 *      <xkms:PendingNotification Mechanism Identifier>?
 *
 * XML Schema:
 *
 *   <!-- RequestAbstractType -->
 *   <complexType name="RequestAbstractType" abstract="true">
 *      <complexContent>
 *         <extension base="xkms:MessageAbstractType">
 *            <sequence>
 *              <element ref="xkms:ResponseMechanism" minOccurs="0" 
 *                     maxOccurs="unbounded"/>
 *               <element ref="xkms:RespondWith" minOccurs="0" 
 *                     maxOccurs="unbounded"/>
 *               <element ref="xkms:PendingNotification" minOccurs="0"/>
 *            </sequence>
 *            <attribute name="OriginalRequestId" type="anyURI" 
 *                  use="optional"/>
 *            <attribute name="ResponseLimit" type="integer" use="optional"/>
 *         </extension>
 *      </complexContent>
 *   </complexType>
 *   <!-- /RequestAbstractType -->
 *
 *   <!-- MessageAbstractType -->
 *   <complexType name="MessageAbstractType" abstract="true">
 *      <sequence>
 *         <element ref="ds:Signature" minOccurs="0"/>
 *         <element ref="xkms:MessageExtension" minOccurs="0" 
 *               maxOccurs="unbounded"/>
 *         <element ref="xkms:OpaqueClientData" minOccurs="0"/>
 *      </sequence>
 *      <attribute name="Id" type="ID" use="required"/>
 *      <attribute name="Service" type="anyURI" use="required"/>
 *      <attribute name="Nonce" type="base64Binary" use="optional"/>
 *   </complexType>
 *   <!-- /MessageAbstractType -->
 */
static int 
xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) {
    xmlNodePtr cur;
    xmlChar* tmp;
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    xmlSecAssert2((*node) != NULL, -1);
    
    cur = (*node);
    xmlSecAssert2(cur != NULL, -1);

    /* required Id attribute */
    xmlSecAssert2(ctx->id == NULL, -1);
    ctx->id = xmlGetProp(cur, xmlSecAttrId);
    if(ctx->id == NULL) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlGetProp",
		    XMLSEC_ERRORS_R_XML_FAILED,
		    "name=%s;node=%s",
		    xmlSecErrorsSafeString(xmlSecAttrId),
		    xmlSecErrorsSafeString(cur->name));
	return(-1);
    }
    
    /* required Service attribute */
    xmlSecAssert2(ctx->service == NULL, -1);
    ctx->service = xmlGetProp(cur, xmlSecAttrService);
    if(ctx->service == NULL) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlGetProp",
		    XMLSEC_ERRORS_R_XML_FAILED,
		    "name=%s;node=%s",
		    xmlSecErrorsSafeString(xmlSecAttrService),
		    xmlSecErrorsSafeString(cur->name));
	return(-1);
    }
    
    /* check service */
    if((ctx->expectedService != NULL) && (!xmlStrEqual(ctx->expectedService, ctx->service))) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    NULL,
		    XMLSEC_ERRORS_R_INVALID_DATA,
		    "expectedService=%s;actualService=%s",
		    xmlSecErrorsSafeString(ctx->expectedService),
		    xmlSecErrorsSafeString(ctx->service));
	return(-1);
    }

    /* optional Nonce attribute */
    xmlSecAssert2(ctx->nonce == NULL, -1);
    ctx->nonce = xmlGetProp(cur, xmlSecAttrNonce);

    /* optional OriginalRequestId attribute */
    xmlSecAssert2(ctx->originalRequestId == NULL, -1);
    ctx->originalRequestId = xmlGetProp(cur, xmlSecAttrOriginalRequestId);

    /* optional ResponseLimit attribute */
    xmlSecAssert2(ctx->responseLimit == XMLSEC_XKMS_NO_RESPONSE_LIMIT, -1);
    tmp = xmlGetProp(cur, xmlSecAttrResponseLimit);
    if(tmp != NULL) {
	ctx->responseLimit = atoi((char*)tmp);
	xmlFree(tmp);
    }

    /* now read children */   
    cur = xmlSecGetNextElementNode(cur->children);
    
    /* first node is optional <dsig:Signature/> node */
    if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeSignature, xmlSecDSigNs)) {
	ret = xmlSecXkmsServerCtxSignatureNodeRead(ctx, cur);
	if(ret < 0) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerCtxSignatureNodeRead",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	cur = xmlSecGetNextElementNode(cur->next);
    }
    
    /* next is zero or more <xkms:MessageExtension/> nodes */
    ret = xmlSecXkmsServerCtxMessageExtensionNodesRead(ctx, &cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxMessageExtensionNodesRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    /* next is optional <xkms:OpaqueClientData/> node */
    if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeOpaqueClientData, xmlSecXkmsNs)) {
	ret = xmlSecXkmsServerCtxOpaqueClientDataNodeRead(ctx, cur);
	if(ret < 0) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerCtxOpaqueClientDataNodeRead",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	cur = xmlSecGetNextElementNode(cur->next);
    }

    /* next is zero or more <xkms:ResponseMechanism/> nodes */
    ret = xmlSecQName2BitMaskNodesRead(gXmlSecXkmsResponseMechanismInfo, &cur, 
			xmlSecNodeResponseMechanism, xmlSecXkmsNs,
                        ((ctx->flags & XMLSEC_XKMS_SERVER_FLAGS_STOP_ON_UNKNOWN_RESPONSE_MECHANISM) != 0) ? 1 : 0, 
			&ctx->responseMechanismMask);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecQName2BitMaskNodesRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecNodeResponseMechanism));
	return(-1);
    }
    
    /* next is zero or more <xkms:RespondWith/> nodes */
    ret = xmlSecXkmsServerCtxRespondWithNodesRead(ctx, &cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxRespondWithNodesRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* next is optional <xkms:PendingNotification/> node */
    if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodePendingNotification, xmlSecXkmsNs)) {
	ret = xmlSecXkmsServerCtxPendingNotificationNodeRead(ctx, cur);    
	if(ret < 0) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerCtxPendingNotificationNodeRead",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	cur = xmlSecGetNextElementNode(cur->next);
    }

    (*node) = cur;    
    return(0);
}

static int 
xmlSecXkmsServerCtxSignatureNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    
    return(0);
}

/** 
 *   <!-- MessageExtension -->
 *   <element name="MessageExtension" type="xkms:MessageExtensionAbstractType"
 *         abstract="true"/>
 *   <complexType name="MessageExtensionAbstractType" abstract="true"/>
 *   <!-- /MessageExtension -->
 */
static int
xmlSecXkmsServerCtxMessageExtensionNodesRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) {
    xmlNodePtr cur;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(ctx->firtsMsgExtNode == NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    cur = (*node);
    while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeMessageExtension, xmlSecXkmsNs)) {
	if(ctx->firtsMsgExtNode == NULL) {
	    ctx->firtsMsgExtNode = cur;
	}
	cur = xmlSecGetNextElementNode(cur->next);
    }

    (*node) = cur;    
    return(0);
}

static int 
xmlSecXkmsServerCtxOpaqueClientDataNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(ctx->opaqueClientDataNode == NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* remember that node, will copy it in the response later */
    ctx->opaqueClientDataNode = node;
    return(0);
}

static int
xmlSecXkmsServerCtxRespondWithNodesRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) {
    xmlNodePtr cur;
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    cur = (*node);
    while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeRespondWith, xmlSecXkmsNs)) {
	xmlSecXkmsRespondWithId id = xmlSecXkmsRespondWithIdUnknown;

	if(xmlSecPtrListGetSize(&(ctx->enabledRespondWithIds)) > 0) {
	    id = xmlSecXkmsRespondWithIdListFindByNodeValue(&(ctx->enabledRespondWithIds), cur);
	} else {
	    id = xmlSecXkmsRespondWithIdListFindByNodeValue(xmlSecXkmsRespondWithIdsGet(), cur);	
	}

	if(id != xmlSecXkmsRespondWithIdUnknown) {	
	    ret = xmlSecXkmsRespondWithNodeRead(id, ctx, cur);
	    if(ret < 0) {
	        xmlSecError(XMLSEC_ERRORS_HERE,
			    NULL,
			    "xmlSecCreateTree",
			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
			    XMLSEC_ERRORS_NO_MESSAGE);
		return(-1);
	    }
	} else if((ctx->flags & XMLSEC_XKMS_SERVER_FLAGS_STOP_ON_UNKNOWN_RESPOND_WITH) != 0) {
            xmlChar* content ;
            
            content = xmlNodeGetContent(cur);
    	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			NULL,
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"name=%s,value=%s",
                        xmlSecErrorsSafeString(cur->name),
                        xmlSecErrorsSafeString(content));
            if(content != NULL) {
                xmlFree(content);
            }
	    return(-1);
	}
	cur = xmlSecGetNextElementNode(cur->next);
    }
    
    (*node) = cur;    
    return(0);
}

/** 
 * XML Schema:
 *   <!-- PendingNotification -->
 *   <element name="PendingNotification" type="xkms:PendingNotificationType"/>
 *   <complexType name="PendingNotificationType">
 *      <attribute name="Mechanism" type="anyURI" use="required"/>
 *      <attribute name="Identifier" type="anyURI" use="required"/>
 *   </complexType>
 *   <!-- /PendingNotification -->
 */
static int 
xmlSecXkmsServerCtxPendingNotificationNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    xmlSecAssert2(ctx->pendingNotificationMechanism == NULL, -1);
    ctx->pendingNotificationMechanism = xmlGetProp(node, xmlSecAttrMechanism);
    if(ctx->pendingNotificationMechanism == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlGetProp",
		    XMLSEC_ERRORS_R_XML_FAILED,
		    "name=%s;node=%s",
		    xmlSecErrorsSafeString(xmlSecAttrMechanism),
		    xmlSecErrorsSafeString(node->name));
    	return(-1);
    }

    xmlSecAssert2(ctx->pendingNotificationIdentifier == NULL, -1);
    ctx->pendingNotificationIdentifier = xmlGetProp(node, xmlSecAttrIdentifier);
    if(ctx->pendingNotificationIdentifier == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlGetProp",
		    XMLSEC_ERRORS_R_XML_FAILED,
		    "name=%s;node=%s",
		    xmlSecErrorsSafeString(xmlSecAttrIdentifier),
		    xmlSecErrorsSafeString(node->name));
    	return(-1);
    }
    
    return(0);
}

/**
 *  <xkms:PendingRequestType Id Service Nonce? OriginalRequestId? ResponseLimit? ResponseId?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:ResponseMechanism>*
 *      <xkms:RespondWith>*
 *      <xkms:PendingNotification Mechanism Identifier>?
 *  
 * XML Schema:
 *
 *   <!-- PendingRequest -->  
 *   <element name="PendingRequest" type="xkms:PendingRequestType"/>   
 *   <complexType name="PendingRequestType">
 *       <complexContent>
 *           <extension base="xkms:RequestAbstractType">
 *               <attribute name="ResponseId" type="anyURI" use="optional"/>
 *            </extension>
 *       </complexContent>
 *    </complexType>
 *    <!-- /PendingRequest --> * 
 */
static int 
xmlSecXkmsServerCtxPendingRequestNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) {
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    
    /* first read "parent" type */
    ret = xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(ctx, node);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxRequestAbstractTypeNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    return(0);
}

/**
 *  <xkms:QueryKeyBinding Id?
 *      <ds:KeyInfo>?
 *      <xkms:KeyUsage>?
 *      <xkms:KeyUsage>?
 *      <xkms:KeyUsage>?
 *      <xkms:UseKeyWith Application Identifier>*    
 *      <xkms:TimeInstant Time>?
 *  
 * XML Schema:
 *   <!-- QueryKeyBinding -->
 *   <element name="QueryKeyBinding" type="xkms:QueryKeyBindingType"/>
 *   <complexType name="QueryKeyBindingType">
 *      <complexContent>
 *          <extension base="xkms:KeyBindingAbstractType">
 *	        <sequence>
 *		    <element ref="xkms:TimeInstant" minOccurs="0"/>
 *		</sequence>
 *	    </extension>
 *	</complexContent>
 *   </complexType>
 *   <!-- /QueryKeyBinding -->
 */
static int 
xmlSecXkmsServerCtxQueryKeyBindingNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlNodePtr cur;
    int ret;
    
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    
    /* first read "parent" type */
    cur = node;
    ret = xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeRead(ctx, &cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* next is optional <xkms:TimeInstant/> node */
    if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeTimeInstant, xmlSecXkmsNs)) {
	ret = xmlSecXkmsServerCtxTimeInstantNodeRead(ctx, cur);
	if(ret < 0) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
			"xmlSecXkmsServerCtxTimeInstantNodeRead",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	cur = xmlSecGetNextElementNode(cur->next);
    }

    /* check that there is nothing after the last node */
    if(cur != NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    return(0);
}

/**
 *  <xkms:KeyBindingAbstractType Id?>
 *      <ds:KeyInfo>?
 *      <xkms:KeyUsage>?
 *      <xkms:KeyUsage>?
 *      <xkms:KeyUsage>?
 *      <xkms:UseKeyWith Application Identifier>*
 *
 * XML Schema:
 *    <!-- KeyBindingAbstractType-->
 *    <complexType name="KeyBindingAbstractType" abstract="true">
 *       <sequence>
 *          <element ref="ds:KeyInfo" minOccurs="0"/>
 *          <element ref="xkms:KeyUsage" minOccurs="0" maxOccurs="3"/>
 *          <element ref="xkms:UseKeyWith" minOccurs="0" 
 *                   maxOccurs="unbounded"/>
 *       </sequence>
 *       <attribute name="Id" type="ID" use="optional"/>
 *    </complexType>
 *    <!-- /KeyBindingAbstractType-->
 */
static int 
xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) {
    xmlNodePtr cur;
    int ret;
    
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    xmlSecAssert2((*node) != NULL, -1);
    
    cur = (*node);
    xmlSecAssert2(cur != NULL, -1);
    
    /* we don't care about Id attribute in this node */
    cur = xmlSecGetNextElementNode(cur->children);
    
    /* first node is optional <dsig:KeyInfo/> node. for now we only remember pointer */
    xmlSecAssert2(ctx->keyInfoNode == NULL, -1);
    if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs)) {
	ctx->keyInfoNode = cur;
	cur = xmlSecGetNextElementNode(cur->next);
    }
    
    /* next is zero or more <xkms:KeyUsage/> nodes */
    ret = xmlSecQName2BitMaskNodesRead(gXmlSecXkmsKeyUsageInfo, &cur,
		    xmlSecNodeKeyUsage, xmlSecXkmsNs, 
                    ((ctx->flags & XMLSEC_XKMS_SERVER_FLAGS_STOP_ON_UNKNOWN_KEY_USAGE) != 0) ? 1 : 0,
		    &(ctx->keyInfoReadCtx.keyReq.keyUsage));
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecQName2BitMaskNodesRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecNodeKeyUsage));
	return(-1);
    }
    
    /* next is zero or more <xkms:UseKeyWith/> nodes */
    ret = xmlSecXkmsServerCtxUseKeyWithNodesRead(ctx, &cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxUseKeyWithNodesRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    (*node) = cur;
    return(0);
}

static int 
xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) {
    xmlNodePtr cur;
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    xmlSecAssert2(key != NULL, -1);

    /* generate and add Id attribute */
    ret = xmlSecGenerateAndAddID(node, xmlSecAttrId, ctx->idPrefix, ctx->idLen);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecGenerateAndAddID",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }

    /* <dsig:KeyInfo/> node */
    cur = xmlSecAddChild(node, xmlSecNodeKeyInfo, xmlSecDSigNs);
    if(cur == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecAddChild",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "node=%s",
		    xmlSecErrorsSafeString(xmlSecNodeKeyInfo));
	return(-1);  	
    }

    ret = xmlSecXkmsServerCtxKeyInfoNodeWrite(ctx, cur, key);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxKeyInfoNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    /* next is <xkms:KeyUsage/> node */
    ret = xmlSecQName2BitMaskNodesWrite(gXmlSecXkmsKeyUsageInfo, node,
		    xmlSecNodeKeyUsage, xmlSecXkmsNs, 
		    key->usage);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecQName2BitMaskNodesWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecNodeKeyUsage));
	return(-1);
    }

    /* and the last node is <xkms:UseKeyWith/> */
    ret = xmlSecXkmsServerCtxUseKeyWithNodesWrite(ctx, node, key);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxUseKeyWithNodesWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    
    return(0);
}

static int 
xmlSecXkmsServerCtxKeyInfoNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) {
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(key != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* add child nodes as requested in <xkms:RespondWith/> nodes */
    ret = xmlSecXkmsRespondWithIdListWrite(&(ctx->respWithList), ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdListWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }

    ret = xmlSecKeyInfoNodeWrite(node, key, &(ctx->keyInfoWriteCtx));
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecKeyInfoNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }

    return(0);
}


/**
 * XML Schema:
 *    <!-- UseKeyWith -->
 *    <element name="UseKeyWith" type="xkms:UseKeyWithType"/>
 *    <complexType name="UseKeyWithType">
 *      <attribute name="Application" type="anyURI" use="required"/>
 *      <attribute name="Identifier" type="string" use="required"/>
 *    </complexType>
 *    <!-- /UseKeyWith -->
 */
static int
xmlSecXkmsServerCtxUseKeyWithNodesRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) {
    xmlSecPtrListPtr list;
    xmlNodePtr cur;
    xmlSecKeyUseWithPtr keyUseWith;
    xmlChar* application;
    xmlChar* identifier;
    int ret;
    
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    list = &(ctx->keyInfoReadCtx.keyReq.keyUseWithList);
    xmlSecAssert2(xmlSecPtrListGetSize(list) == 0, -1);

    cur = (*node);
    while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeUseKeyWith, xmlSecXkmsNs)) {
	application = xmlGetProp(cur, xmlSecAttrApplication);
	if(application == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		    	NULL,
			"xmlGetProp",
			XMLSEC_ERRORS_R_XML_FAILED,
			"name=%s;node=%s",
			xmlSecErrorsSafeString(xmlSecAttrApplication),
			xmlSecErrorsSafeString(cur->name));
    	    return(-1);
	}

	identifier = xmlGetProp(cur, xmlSecAttrIdentifier);
	if(identifier == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		    	NULL,
			"xmlGetProp",
			XMLSEC_ERRORS_R_XML_FAILED,
			"name=%s;node=%s",
			xmlSecErrorsSafeString(xmlSecAttrIdentifier),
			xmlSecErrorsSafeString(cur->name));
	    xmlFree(application);
    	    return(-1);
	}
	
	keyUseWith = xmlSecKeyUseWithCreate(application, identifier);
	if(keyUseWith == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		    	NULL,
			"xmlSecKeyUseWithCreate",
		    	XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlFree(application);
	    xmlFree(identifier);
    	    return(-1);
	}
	xmlFree(application);
	xmlFree(identifier);
	
	ret = xmlSecPtrListAdd(list, keyUseWith);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		    	NULL,
			"xmlSecPtrListAdd",
		    	XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlSecKeyUseWithDestroy(keyUseWith);
    	    return(-1);
	}
	
	cur = xmlSecGetNextElementNode(cur->next);
    }

    (*node) = cur;    
    return(0);
}

static int 
xmlSecXkmsServerCtxUseKeyWithNodesWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) {
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    xmlSecAssert2(key != NULL, -1);

    return(0);
}


static int 
xmlSecXkmsServerCtxTimeInstantNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    return(0);
}

/**
 *  <xkms:ResultType Id Service Nonce? ResultMajor ResultMinor? RequestId?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:RequestSignatureValue>*
 *
 * XML Schema:
 *    <!-- ResultType -->
 *    <element name="Result" type="xkms:ResultType"/>
 *    <complexType name="ResultType">
 *       <complexContent>
 *          <extension base="xkms:MessageAbstractType">
 *             <sequence>
 *                <element ref="xkms:RequestSignatureValue" minOccurs="0"/>
 *	       </sequence>
 *	       <attribute name="ResultMajor" type="QName" use="required"/>
 *	       <attribute name="ResultMinor" type="QName" use="optional"/>
 *	       <attribute name="RequestId" type="anyURI" use="optional"/>
 *	    </extension>
 *	 </complexContent>
 *    </complexType>
 *    <!-- /ResultType -->
 */
static int 
xmlSecXkmsServerCtxResultTypeNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    int ret;
    
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* generate and add Id attribute */
    ret = xmlSecGenerateAndAddID(node, xmlSecAttrId, ctx->idPrefix, ctx->idLen);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecGenerateAndAddID",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }


    /* set Service atribute (required) */   
    if((ctx->service == NULL) || (xmlSetProp(node, xmlSecAttrService, ctx->service) == NULL)) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSetProp",
		    XMLSEC_ERRORS_R_XML_FAILED,
		    "name=%s,value=%s",
		    xmlSecErrorsSafeString(xmlSecAttrService),
		    xmlSecErrorsSafeString(ctx->service));
	return(-1);	
    }
    

    /* set RequestId atribute (optional) */   
    if((ctx->id != NULL) && (xmlSetProp(node, xmlSecAttrRequestId, ctx->id) == NULL)) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSetProp",
		    XMLSEC_ERRORS_R_XML_FAILED,
		    "name=%s,value=%s",
		    xmlSecErrorsSafeString(xmlSecAttrRequestId),
		    xmlSecErrorsSafeString(ctx->id));
	return(-1);	
    }
    
    
    /* set major code (required) */ 
    ret = xmlSecQName2IntegerAttributeWrite(gXmlSecXkmsResultMajorInfo, node,
					     xmlSecAttrResultMajor, ctx->resultMajor);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecQName2IntegerAttributeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s,value=%d",
		    xmlSecErrorsSafeString(xmlSecAttrResultMajor),
		    ctx->resultMajor);
	return(-1);	
    }

    /* set minor code (optional) */ 
    if(ctx->resultMinor != xmlSecXkmsResultMinorNone) {
        ret = xmlSecQName2IntegerAttributeWrite(gXmlSecXkmsMinorErrorInfo, node,
					     xmlSecAttrResultMinor, ctx->resultMinor);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
			"xmlSecQName2IntegerAttributeWrite",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "name=%s,value=%d",
			xmlSecErrorsSafeString(xmlSecAttrResultMinor),
			ctx->resultMinor);
	    return(-1);	
	}
    }

    

    /* <xkms:OpaqueClientData/>: An XKMS service SHOULD return the value of 
     * the <OpaqueClientData> element unmodified in a request in a response 
     * with status code Succes */
    if((ctx->resultMajor == xmlSecXkmsResultMajorSuccess) && (ctx->opaqueClientDataNode != NULL)) {
        xmlNodePtr copyNode;

	copyNode = xmlDocCopyNode(ctx->opaqueClientDataNode, node->doc, 1);
	if(copyNode == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		    	NULL,
			"xmlSetProp",
			XMLSEC_ERRORS_R_XML_FAILED,
			"name=%s",
			xmlSecErrorsSafeString(ctx->opaqueClientDataNode->name));
	    return(-1);
	}	
	
	if(xmlSecAddChildNode(node, copyNode) == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		    	NULL,
			"xmlSecAddChildNode",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"name=%s",
			xmlSecErrorsSafeString(copyNode->name));
	    return(-1);
	}
    }

    ret = xmlSecXkmsServerCtxRequestSignatureValueNodeWrite(ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxRequestSignatureValueNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }

    return(0);
}

/** 
 * A service SHOULD include the <RequestSignatureValue> element in a response 
 * if the following conditions are satisfied and MUST NOT include the value 
 * otherwise:
 *
 *
 *  - The <ds:Signature> element was present in the corresponding request
 *  - The service successfully verified the <ds:Signature> element in the 
 *  corresponding request, and
 *  - The ResponseMechanism RequestSignatureValue was specified.
 *    
 */
static int 
xmlSecXkmsServerCtxRequestSignatureValueNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    
    if((ctx->responseMechanismMask & XMLSEC_XKMS_RESPONSE_MECHANISM_MASK_REQUEST_SIGNATURE_VALUE) == 0) {
	/* The ResponseMechanism RequestSignatureValue was not specified. */
	return(0);
    }
    
    return(0);
}


/** 
 *  
 *  <xkms:UnverifiedKeyBindingType Id?>
 *      <ds:KeyInfo>?
 *      <xkms:KeyUsage>?
 *      <xkms:KeyUsage>?
 *      <xkms:KeyUsage>?
 *      <xkms:UseKeyWith Application Identifier>*    
 *      <xkms:ValidityInterval NotBefore NotOnOrAfter>?
 *  
 * XML Schema:
 *
 *    <!-- UnverifiedKeyBinding -->
 *    <element name="UnverifiedKeyBinding" type="xkms:UnverifiedKeyBindingType"/>
 *    <complexType name="UnverifiedKeyBindingType">
 *       <complexContent>
 *          <extension base="xkms:KeyBindingAbstractType">
 *             <sequence>
 *                 <element ref="xkms:ValidityInterval" minOccurs="0"/>
 *             </sequence>
 *          </extension>
 *       </complexContent>
 *    </complexType>
 *    <!-- /UnverifiedKeyBinding -->
 */
static int 
xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) {
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(key != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* first write "parent" type */
    ret = xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite(ctx, node, key);    
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    /* <xkms:ValidityInterval/> node */
    ret = xmlSecXkmsServerCtxValidityIntervalNodeWrite(ctx, node, key);    
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxValidityIntervalNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }

    return(0);
}

static int 
xmlSecXkmsServerCtxValidityIntervalNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) {
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(key != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    
    return(0);
}

/** 
 *  <xkms:KeyBinding Id?>
 *      <ds:KeyInfo>?
 *      <xkms:KeyUsage>?
 *      <xkms:KeyUsage>?
 *      <xkms:KeyUsage>?
 *      <xkms:UseKeyWith Application Identifier>*    
 *      <xkms:ValidityInterval NotBefore NotOnOrAfter>?
 *      <xkms:Status StatusValue>
 *          (<xkms:ValidReason>?
 *           <xkms:IndeterminateReason>?
 *           <xkms:InvalidReason>?
 *           )*
 *
 * XML Schema:
 * 
 *    <!-- KeyBinding -->   
 *    <element name="KeyBinding" type="xkms:KeyBindingType"/>   
 *    <complexType name="KeyBindingType">      
 *        <complexContent>         
 *            <extension base="xkms:UnverifiedKeyBindingType">            
 *                <sequence>               
 *                    <element ref="xkms:Status"/>
 *                </sequence>
 *            </extension>
 *        </complexContent>
 *    </complexType>
 *    <!-- /KeyBinding -->
 */
static int 
xmlSecXkmsServerCtxKeyBindingNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) {
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(key != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* first write "parent" type */
    ret = xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite(ctx, node, key);    
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }

    /* <xkms:Status/> node */
    ret = xmlSecXkmsServerCtxKeyBindingStatusNodeWrite(ctx, node, key);    
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxKeyBindingStatusNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }

    return(0);
}

/**
 *  <xkms:Status StatusValue>
 *      (<xkms:ValidReason>?
 *       <xkms:IndeterminateReason>?
 *       <xkms:InvalidReason>?
 *      )*
 * 
 * XML Schema:
 *
 *    <!-- Status -->   
 *    <element name="Status" type="xkms:StatusType"/>
 *    <complexType name="StatusType">
 *       <sequence>
 *          <element ref="xkms:ValidReason" minOccurs="0" 
 *                maxOccurs="unbounded"/>
 *          <element ref="xkms:IndeterminateReason" minOccurs="0" 
 *                maxOccurs="unbounded"/>
 *          <element ref="xkms:InvalidReason" minOccurs="0" 
 *                maxOccurs="unbounded"/>
 *       </sequence>
 *       <attribute name="StatusValue" type="xkms:KeyBindingStatus" 
 *             use="required"/>
 *    </complexType>
 *    <simpleType name="KeyBindingStatus">
 *       <restriction base="QName">
 *          <enumeration value="xkms:Valid"/>
 *          <enumeration value="xkms:Invalid"/>
 *          <enumeration value="xkms:Indeterminate"/>
 *       </restriction>
 *    </simpleType>
 *    <!-- /Status -->
 */
static int 
xmlSecXkmsServerCtxKeyBindingStatusNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) {
    xmlNodePtr cur;
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(key != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    cur = xmlSecAddChild(node, xmlSecNodeStatus, xmlSecXkmsNs);
    if(cur == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecAddChild",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "node=%s",
		    xmlSecErrorsSafeString(xmlSecNodeStatus));
	return(-1);  	
    }

    /* if we are here then the key was validated */
    ret = xmlSecQName2IntegerAttributeWrite(gXmlSecXkmsKeyBindingStatusInfo, cur, 
		    xmlSecAttrStatusValue, xmlSecXkmsKeyBindingStatusValid);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecQName2IntegerAttributeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecAttrStatusValue));
	return(-1);	
    }
    
    return(0);
}

/************************************************************************
 *
 * xmlSecXkmsServerCtx list
 *
 ************************************************************************/ 
static xmlSecPtrListKlass xmlSecXkmsServerCtxPtrListKlass = {
    BAD_CAST "xkms-server-ctx-list",
    NULL, 								/* xmlSecPtrDuplicateItemMethod duplicateItem; */
    (xmlSecPtrDestroyItemMethod)xmlSecXkmsServerCtxDestroy,	        /* xmlSecPtrDestroyItemMethod destroyItem; */
    (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsServerCtxDebugDump,	        /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
    (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsServerCtxDebugXmlDump,	/* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
};
EXPORT_C

xmlSecPtrListId	
xmlSecXkmsServerCtxPtrListGetKlass(void) {
    return(&xmlSecXkmsServerCtxPtrListKlass);
}


/**************************************************************************
 *
 * Global xmlSecXkmsRespondWithIds list functions
 *
 *************************************************************************/
static xmlSecPtrList xmlSecAllXkmsRespondWithIds;


/** 
 * xmlSecXkmsRespondWithIdsGet:
 *
 * Gets global registered RespondWith klasses list.
 * 
 * Returns the pointer to list of all registered RespondWith klasses.
 */
EXPORT_C
xmlSecPtrListPtr
xmlSecXkmsRespondWithIdsGet(void) {
    return(&xmlSecAllXkmsRespondWithIds);
}

/** 
 * xmlSecXkmsRespondWithIdsInit:
 *
 * Initializes the RespondWith klasses. This function is called from the 
 * #xmlSecInit function and the application should not call it directly.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsRespondWithIdsInit(void) {
    int ret;
    
    ret = xmlSecPtrListInitialize(xmlSecXkmsRespondWithIdsGet(), xmlSecXkmsRespondWithIdListId);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListPtrInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "xmlSecXkmsRespondWithIdListId");
        return(-1);
    }
    
    ret = xmlSecXkmsRespondWithIdsRegisterDefault();
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegisterDefault",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
        return(-1);
    }
    
    return(0);
}

/**
 * xmlSecXkmsRespondWithIdsShutdown:
 * 
 * Shuts down the keys data klasses. This function is called from the 
 * #xmlSecShutdown function and the application should not call it directly.
 */
EXPORT_C
void
xmlSecXkmsRespondWithIdsShutdown(void) {
    xmlSecPtrListFinalize(xmlSecXkmsRespondWithIdsGet());
}

/** 
 * xmlSecXkmsRespondWithIdsRegister:
 * @id:		the RespondWith klass.
 *
 * Registers @id in the global list of RespondWith klasses.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithId id) {
    int ret;
        
    xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1);
    
    ret = xmlSecPtrListAdd(xmlSecXkmsRespondWithIdsGet(), (xmlSecPtr)id);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListAdd",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "RespondWith=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)));
        return(-1);
    }
    
    return(0);    
}

/**
 * xmlSecXkmsRespondWithIdsRegisterDefault:
 *
 * Registers default (implemented by XML Security Library)
 * RespondWith klasses: KeyName, KeyValue,...
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsRespondWithIdsRegisterDefault(void) {
    if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithKeyNameId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithKeyNameId)));
	return(-1);
    }

    if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithKeyValueId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithKeyValueId)));
	return(-1);
    }

    if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithPrivateKeyId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithPrivateKeyId)));
	return(-1);
    }

    if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithRetrievalMethodId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithRetrievalMethodId)));
	return(-1);
    }

    if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithX509CertId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithX509CertId)));
	return(-1);
    }

    if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithX509ChainId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithX509ChainId)));
	return(-1);
    }

    if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithX509CRLId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithX509CRLId)));
	return(-1);
    }

    /*
    if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithPGPId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithPGPId)));
	return(-1);
    }

    if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithSPKIId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsRespondWithIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithSPKIId)));
	return(-1);
    }
    */
    return(0);
}


/************************************************************************
 *
 * XKMS RespondWith Klass
 *
 ************************************************************************/ 
/**
 * xmlSecXkmsRespondWithNodeRead:
 * @id:		the RespondWith class.
 * @ctx:	the XKMS request processing context.
 * @node:	the pointer to <xkms:RespondWith/> node.
 *
 * Reads the content of the <xkms:RespondWith/> @node.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int  
xmlSecXkmsRespondWithNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx,
			      xmlNodePtr node) {
    xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    if(id->readNode != NULL) {
	return((id->readNode)(id, ctx, node));
    }
    return(0);
}

/**
 * xmlSecXkmsRespondWithNodeWrite:
 * @id:		the RespondWith class.
 * @ctx:	the XKMS request processing context.
 * @node:	the pointer to <xkms:RespondWith/> node.
 *
 * Writes the content of the <xkms:RespondWith/> @node.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsRespondWithNodeWrite(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx,
			     xmlNodePtr node) {
    xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    if(id->writeNode != NULL) {
	return((id->writeNode)(id, ctx, node));
    }
    return(0);
}

/**
 * xmlSecXkmsRespondWithDebugDump:
 * @id:		the RespondWith class.
 * @output:	the output file.
 *
 * Writes debug information about @id into the @output.
 */
EXPORT_C
void 
xmlSecXkmsRespondWithDebugDump(xmlSecXkmsRespondWithId id, FILE* output) {
    xmlSecAssert(id != xmlSecXkmsRespondWithIdUnknown);
    xmlSecAssert(output != NULL);

    fprintf(output, "=== RespondWith: \"%s\" (href=\"%s\")\n", 
        xmlSecErrorsSafeString(id->valueName),
        xmlSecErrorsSafeString(id->valueNs));
}

/**
 * xmlSecXkmsRespondWithDebugXmlDump:
 * @id:		the RespondWith class.
 * @output:	the output file.
 *
 * Writes debug information about @id into the @output in XML format.
 */
EXPORT_C
void 
xmlSecXkmsRespondWithDebugXmlDump(xmlSecXkmsRespondWithId id, FILE* output) {
    xmlSecAssert(id != xmlSecXkmsRespondWithIdUnknown);
    xmlSecAssert(output != NULL);

    fprintf(output, "<RespondWith href=\"%s\">%s</RespondWith>\n", 
        xmlSecErrorsSafeString(id->valueNs),
        xmlSecErrorsSafeString(id->valueName));
}
EXPORT_C

int 
xmlSecXkmsRespondWithDefaultNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx,
			    xmlNodePtr node) {
    int ret;

    xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    ret = xmlSecXkmsRespondWithIdListFind(&(ctx->respWithList), id);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)),
		    "xmlSecXkmsRespondWithIdListFind",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    } else if(ret > 0) {
	/* do nothing, we already have it in the list */
	return(0);
    }    
    
    ret = xmlSecPtrListAdd(&(ctx->respWithList), id);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)),
		    "xmlSecPtrListAdd",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }

    return(0);
}
EXPORT_C

int  
xmlSecXkmsRespondWithDefaultNodeWrite(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx,
			    xmlNodePtr node) {
    xmlNodePtr cur;

    xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1);
    xmlSecAssert2(id->nodeName != NULL, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    cur = xmlSecAddChild(node, id->nodeName, id->nodeNs);
    if(cur == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)),
		    "xmlSecAddChild",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "node=%s",
		    xmlSecErrorsSafeString(id->nodeName));
	return(-1);  	
    }

    return(0);
}

/************************************************************************
 *
 * XKMS RespondWith Klass List
 *
 ************************************************************************/ 
static xmlSecPtrListKlass xmlSecXkmsRespondWithIdListKlass = {
    BAD_CAST "respond-with-ids-list",
    NULL, 								/* xmlSecPtrDuplicateItemMethod duplicateItem; */
    NULL,								/* xmlSecPtrDestroyItemMethod destroyItem; */
    (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsRespondWithDebugDump,	/* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
    (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsRespondWithDebugXmlDump,	/* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
};
EXPORT_C

xmlSecPtrListId	
xmlSecXkmsRespondWithIdListGetKlass(void) {
    return(&xmlSecXkmsRespondWithIdListKlass);
}
EXPORT_C

int 
xmlSecXkmsRespondWithIdListFind(xmlSecPtrListPtr list, xmlSecXkmsRespondWithId id) {
    xmlSecSize i, size;
    
    xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsRespondWithIdListId), -1);
    xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1);
    
    size = xmlSecPtrListGetSize(list);
    for(i = 0; i < size; ++i) {
	if((xmlSecXkmsRespondWithId)xmlSecPtrListGetItem(list, i) == id) {
	    return(1);
	}
    }
    return(0);
}
EXPORT_C

xmlSecXkmsRespondWithId 
xmlSecXkmsRespondWithIdListFindByNodeValue(xmlSecPtrListPtr list, xmlNodePtr node) {
    xmlSecXkmsRespondWithId result = xmlSecXkmsRespondWithIdUnknown;
    xmlSecXkmsRespondWithId id;
    xmlChar* content;
    xmlChar* qnameLocalPart = NULL;
    xmlChar* qnamePrefix = NULL;
    const xmlChar* qnameHref;
    xmlNsPtr ns;
    xmlSecSize i, size;
    
    xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsRespondWithIdListId), xmlSecXkmsRespondWithIdUnknown);
    xmlSecAssert2(node != NULL, xmlSecXkmsRespondWithIdUnknown);

    content = xmlNodeGetContent(node);
    if(content == NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
                    NULL,
		    "xmlNodeGetContent",
		    XMLSEC_ERRORS_R_XML_FAILED,
		    "node=%s",
		    xmlSecErrorsSafeString(node->name));
	return(xmlSecXkmsRespondWithIdUnknown);  	
    }

    qnameLocalPart = (xmlChar*)xmlStrchr(content, ':');
    if(qnameLocalPart != NULL) {
        qnamePrefix = content;
        *(qnameLocalPart++) = '\0';
    } else {
        qnamePrefix = NULL;
        qnameLocalPart = content;
    }
    
    /* search namespace href */
    ns = xmlSearchNs(node->doc, node, qnamePrefix);
    if((ns == NULL) && (qnamePrefix != NULL)) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSearchNs",
	    	    XMLSEC_ERRORS_R_XML_FAILED,
		    "node=%s,qnamePrefix=%s",
		    xmlSecErrorsSafeString(node->name),
                    xmlSecErrorsSafeString(qnamePrefix));
        xmlFree(content);
	return(xmlSecXkmsRespondWithIdUnknown);	
    }
    qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL;

    size = xmlSecPtrListGetSize(list);
    for(i = 0; i < size; ++i) {
	id = (xmlSecXkmsRespondWithId)xmlSecPtrListGetItem(list, i);
	if((id !=  xmlSecXkmsRespondWithIdUnknown) && 
                xmlStrEqual(id->valueName, qnameLocalPart) &&
                xmlStrEqual(id->valueNs, qnameHref)) {
	    result = id;
            break;
	}
    }
    
    xmlFree(content);
    return(result);    
}
EXPORT_C

int 
xmlSecXkmsRespondWithIdListWrite(xmlSecPtrListPtr list, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlSecXkmsRespondWithId id;
    xmlSecSize i, size;
    int ret;

    xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsRespondWithIdListId), -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    size = xmlSecPtrListGetSize(list);
    for(i = 0; i < size; ++i) {
	id = (xmlSecXkmsRespondWithId)xmlSecPtrListGetItem(list, i);
	if(id !=  xmlSecXkmsRespondWithIdUnknown) {
	    ret = xmlSecXkmsRespondWithNodeWrite(id, ctx, node);
	    if(ret < 0) {
		xmlSecError(XMLSEC_ERRORS_HERE,
			    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)),
			    "xmlSecXkmsRespondWithNodeWrite",
		    	    XMLSEC_ERRORS_R_XMLSEC_FAILED,
			    XMLSEC_ERRORS_NO_MESSAGE);
		return(-1);
	    }
	}
    }

    return(0);
}

/******************************************************************** 
 *
 * XML Sec Library RespondWith Ids
 *
 *******************************************************************/
static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithKeyNameKlass = {
    xmlSecRespondWithKeyName,			/* const xmlChar* valueName; */
    xmlSecXkmsNs,			        /* const xmlChar* valueNs; */
    xmlSecNodeKeyName,				/* const xmlChar* nodeName; */
    xmlSecDSigNs,				/* const xmlChar* nodeNs; */
    xmlSecXkmsRespondWithDefaultNodeRead,	/* xmlSecXkmsRespondWithNodeReadMethod readNode; */
    xmlSecXkmsRespondWithDefaultNodeWrite,	/* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsRespondWithKeyNameGetKlass:
 *
 * The respond with KeyName klass.
 *
 * Returns respond with KeyName klass.
 */
EXPORT_C 
xmlSecXkmsRespondWithId	
xmlSecXkmsRespondWithKeyNameGetKlass(void) {
    return(&xmlSecXkmsRespondWithKeyNameKlass);
}



static  int  		xmlSecXkmsRespondWithKeyValueNodeRead	(xmlSecXkmsRespondWithId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithKeyValueKlass = {
    xmlSecRespondWithKeyValue,			/* const xmlChar* valueName; */
    xmlSecXkmsNs,			        /* const xmlChar* valueNs; */
    xmlSecNodeKeyValue,				/* const xmlChar* nodeName; */
    xmlSecDSigNs,				/* const xmlChar* nodeNs; */
    xmlSecXkmsRespondWithKeyValueNodeRead,	/* xmlSecXkmsRespondWithNodeReadMethod readNode; */
    xmlSecXkmsRespondWithDefaultNodeWrite,	/* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsRespondWithKeyValueGetKlass:
 *
 * The respond with KeyValue klass.
 *
 * Returns respond with KeyValue klass.
 */
EXPORT_C 
xmlSecXkmsRespondWithId	
xmlSecXkmsRespondWithKeyValueGetKlass(void) {
    return(&xmlSecXkmsRespondWithKeyValueKlass);
}

static  int  
xmlSecXkmsRespondWithKeyValueNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx,
				      xmlNodePtr node) {
    int ret;

    xmlSecAssert2(id == xmlSecXkmsRespondWithKeyValueId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* do usual stuff */
    ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)),
		    "xmlSecXkmsRespondWithDefaultNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    /* and now set some parameters in the ctx to look for a public or private 
     * key and to write a public key
     */
    ctx->keyInfoReadCtx.keyReq.keyType  |= (xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate);
    ctx->keyInfoWriteCtx.keyReq.keyType |= xmlSecKeyDataTypePublic;

    return(0);
}

static  int  		xmlSecXkmsRespondWithPrivateKeyNodeRead	(xmlSecXkmsRespondWithId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithPrivateKeyKlass = {
    xmlSecRespondWithPrivateKey,		/* const xmlChar* valueName; */
    xmlSecXkmsNs,			        /* const xmlChar* valueNs; */
    xmlSecNodeKeyValue,				/* const xmlChar* nodeName; */
    xmlSecDSigNs,				/* const xmlChar* nodeNs; */
    xmlSecXkmsRespondWithPrivateKeyNodeRead,	/* xmlSecXkmsRespondWithNodeReadMethod readNode; */
    xmlSecXkmsRespondWithDefaultNodeWrite,	/* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsRespondWithPrivateKeyGetKlass:
 *
 * The respond with PrivateKey klass.
 *
 * Returns respond with PrivateKey klass.
 */
EXPORT_C 
xmlSecXkmsRespondWithId	
xmlSecXkmsRespondWithPrivateKeyGetKlass(void) {
    return(&xmlSecXkmsRespondWithPrivateKeyKlass);
}

static  int  
xmlSecXkmsRespondWithPrivateKeyNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx,
				      xmlNodePtr node) {
    int ret;

    xmlSecAssert2(id == xmlSecXkmsRespondWithPrivateKeyId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* do usual stuff */
    ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)),
		    "xmlSecXkmsRespondWithDefaultNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    /* and now set some parameters in the ctx to look for a private 
     * key and to write a private key
     */
    ctx->keyInfoReadCtx.keyReq.keyType  |= xmlSecKeyDataTypePrivate;
    ctx->keyInfoWriteCtx.keyReq.keyType |= xmlSecKeyDataTypePrivate;

    return(0);
}

static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithRetrievalMethodKlass = {
    xmlSecRespondWithRetrievalMethod,		/* const xmlChar* valueName; */
    xmlSecXkmsNs,			        /* const xmlChar* valueNs; */
    xmlSecNodeRetrievalMethod,			/* const xmlChar* nodeName; */
    xmlSecDSigNs,				/* const xmlChar* nodeNs; */
    xmlSecXkmsRespondWithDefaultNodeRead,	/* xmlSecXkmsRespondWithNodeReadMethod readNode; */
    xmlSecXkmsRespondWithDefaultNodeWrite,	/* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsRespondWithRetrievalMethodGetKlass:
 *
 * The respond with RetrievalMethod klass.
 *
 * Returns respond with RetrievalMethod klass.
 */
EXPORT_C 
xmlSecXkmsRespondWithId	
xmlSecXkmsRespondWithRetrievalMethodGetKlass(void) {
    return(&xmlSecXkmsRespondWithRetrievalMethodKlass);
}



static  int  		xmlSecXkmsRespondWithX509CertNodeRead	(xmlSecXkmsRespondWithId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithX509CertKlass = {
    xmlSecRespondWithX509Cert,			/* const xmlChar* valueName; */
    xmlSecXkmsNs,			        /* const xmlChar* valueNs; */
    xmlSecNodeX509Data,				/* const xmlChar* nodeName; */
    xmlSecDSigNs,				/* const xmlChar* nodeNs; */
    xmlSecXkmsRespondWithX509CertNodeRead,	/* xmlSecXkmsRespondWithNodeReadMethod readNode; */
    xmlSecXkmsRespondWithDefaultNodeWrite,	/* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsRespondWithX509CertGetKlass:
 *
 * The respond with X509Cert klass.
 *
 * Returns respond with X509Cert klass.
 */
EXPORT_C 
xmlSecXkmsRespondWithId	
xmlSecXkmsRespondWithX509CertGetKlass(void) {
    return(&xmlSecXkmsRespondWithX509CertKlass);
}

static  int  
xmlSecXkmsRespondWithX509CertNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx,
				      xmlNodePtr node) {
    int ret;

    xmlSecAssert2(id == xmlSecXkmsRespondWithX509CertId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* do usual stuff */
    ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)),
		    "xmlSecXkmsRespondWithDefaultNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    return(0);
}

static  int  		xmlSecXkmsRespondWithX509ChainNodeRead	(xmlSecXkmsRespondWithId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithX509ChainKlass = {
    xmlSecRespondWithX509Chain,			/* const xmlChar* valueName; */
    xmlSecXkmsNs,			        /* const xmlChar* valueNs; */
    xmlSecNodeX509Data,				/* const xmlChar* nodeName; */
    xmlSecDSigNs,				/* const xmlChar* nodeNs; */
    xmlSecXkmsRespondWithX509ChainNodeRead,	/* xmlSecXkmsRespondWithNodeReadMethod readNode; */
    xmlSecXkmsRespondWithDefaultNodeWrite,	/* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsRespondWithX509ChainGetKlass:
 *
 * The respond with X509Chain klass.
 *
 * Returns respond with X509Chain klass.
 */
EXPORT_C 
xmlSecXkmsRespondWithId	
xmlSecXkmsRespondWithX509ChainGetKlass(void) {
    return(&xmlSecXkmsRespondWithX509ChainKlass);
}

static  int  
xmlSecXkmsRespondWithX509ChainNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx,
				      xmlNodePtr node) {
    int ret;

    xmlSecAssert2(id == xmlSecXkmsRespondWithX509ChainId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* do usual stuff */
    ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)),
		    "xmlSecXkmsRespondWithDefaultNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    return(0);
}

static  int  		xmlSecXkmsRespondWithX509CRLNodeRead	(xmlSecXkmsRespondWithId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithX509CRLKlass = {
    xmlSecRespondWithX509CRL,			/* const xmlChar* valueName; */
    xmlSecXkmsNs,			        /* const xmlChar* valueNs; */
    xmlSecNodeX509Data,				/* const xmlChar* nodeName; */
    xmlSecDSigNs,				/* const xmlChar* nodeNs; */
    xmlSecXkmsRespondWithX509CRLNodeRead,	/* xmlSecXkmsRespondWithNodeReadMethod readNode; */
    xmlSecXkmsRespondWithDefaultNodeWrite,	/* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsRespondWithX509CRLGetKlass:
 *
 * The respond with X509CRL klass.
 *
 * Returns respond with X509CRL klass.
 */
EXPORT_C 
xmlSecXkmsRespondWithId	
xmlSecXkmsRespondWithX509CRLGetKlass(void) {
    return(&xmlSecXkmsRespondWithX509CRLKlass);
}

static  int  
xmlSecXkmsRespondWithX509CRLNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx,
				      xmlNodePtr node) {
    int ret;

    xmlSecAssert2(id == xmlSecXkmsRespondWithX509CRLId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* do usual stuff */
    ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)),
		    "xmlSecXkmsRespondWithDefaultNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    return(0);
}

static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithPGPKlass = {
    xmlSecRespondWithPGP,			/* const xmlChar* valueName; */
    xmlSecXkmsNs,			        /* const xmlChar* valueNs; */
    xmlSecNodePGPData,				/* const xmlChar* nodeName; */
    xmlSecDSigNs,				/* const xmlChar* nodeNs; */
    xmlSecXkmsRespondWithDefaultNodeRead,	/* xmlSecXkmsRespondWithNodeReadMethod readNode; */
    xmlSecXkmsRespondWithDefaultNodeWrite,	/* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsRespondWithPGPGetKlass:
 *
 * The respond with PGP klass.
 *
 * Returns respond with PGP klass.
 */
EXPORT_C 
xmlSecXkmsRespondWithId	
xmlSecXkmsRespondWithPGPGetKlass(void) {
    return(&xmlSecXkmsRespondWithPGPKlass);
}

static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithSPKIKlass = {
    xmlSecRespondWithSPKI,			/* const xmlChar* valueName; */
    xmlSecXkmsNs,			        /* const xmlChar* valueNs; */
    xmlSecNodeSPKIData,				/* const xmlChar* nodeName; */
    xmlSecDSigNs,				/* const xmlChar* nodeNs; */
    xmlSecXkmsRespondWithDefaultNodeRead,	/* xmlSecXkmsRespondWithNodeReadMethod readNode; */
    xmlSecXkmsRespondWithDefaultNodeWrite,	/* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsRespondWithSPKIGetKlass:
 *
 * The respond with SPKI klass.
 *
 * Returns respond with SPKI klass.
 */
EXPORT_C 
xmlSecXkmsRespondWithId	
xmlSecXkmsRespondWithSPKIGetKlass(void) {
    return(&xmlSecXkmsRespondWithSPKIKlass);
}

/**************************************************************************
 *
 * Global xmlSecXkmsServerRequestIds list functions
 *
 *************************************************************************/
static xmlSecPtrList xmlSecAllXkmsServerRequestIds;


/** 
 * xmlSecXkmsServerRequestIdsGet:
 *
 * Gets global registered ServerRequest klasses list.
 * 
 * Returns the pointer to list of all registered ServerRequest klasses.
 */
EXPORT_C
xmlSecPtrListPtr
xmlSecXkmsServerRequestIdsGet(void) {
    return(&xmlSecAllXkmsServerRequestIds);
}

/** 
 * xmlSecXkmsServerRequestIdsInit:
 *
 * Initializes the ServerRequest klasses. This function is called from the 
 * #xmlSecInit function and the application should not call it directly.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsServerRequestIdsInit(void) {
    int ret;
    
    ret = xmlSecPtrListInitialize(xmlSecXkmsServerRequestIdsGet(), xmlSecXkmsServerRequestIdListId);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListPtrInitialize",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "xmlSecXkmsServerRequestIdListId");
        return(-1);
    }
    
    ret = xmlSecXkmsServerRequestIdsRegisterDefault();
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestIdsRegisterDefault",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
        return(-1);
    }
    
    return(0);
}

/**
 *  xmlSecXkmsServerRequestIdsShutdown:
 * 
 * Shuts down the keys data klasses. This function is called from the 
 * #xmlSecShutdown function and the application should not call it directly.
 */
EXPORT_C
void
xmlSecXkmsServerRequestIdsShutdown(void) {
    xmlSecPtrListFinalize(xmlSecXkmsServerRequestIdsGet());
}

/** 
 * xmlSecXkmsServerRequestIdsRegister:
 * @id:		the ServerRequest klass.
 *
 * Registers @id in the global list of ServerRequest klasses.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestId id) {
    int ret;
        
    xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, -1);
    
    ret = xmlSecPtrListAdd(xmlSecXkmsServerRequestIdsGet(), (xmlSecPtr)id);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListAdd",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "ServerRequest=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(id)));
        return(-1);
    }
    
    return(0);    
}

/**
 * xmlSecXkmsServerRequestIdsRegisterDefault:
 *
 * Registers default (implemented by XML Security Library)
 * ServerRequest klasses: KeyName, KeyValue,...
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecXkmsServerRequestIdsRegisterDefault(void) {
    if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestResultId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestResultId)));
	return(-1);
    }

    if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestStatusId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestStatusId)));
	return(-1);
    }

    if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestCompoundId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestCompoundId)));
	return(-1);
    }

    if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestLocateId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestLocateId)));
	return(-1);
    }

    if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestValidateId) < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerRequestIdsRegister",	    
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    "name=%s",
		    xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestValidateId)));
	return(-1);
    }

    return(0);
}


/************************************************************************
 *
 * XKMS ServerRequest Klass
 *
 ************************************************************************/ 
/**
 * xmlSecXkmsServerRequestNodeRead:
 * @id:		the ServerRequest class.
 * @ctx:	the XKMS request processing context.
 * @node:	the pointer to <xkms:ServerRequest/> node.
 *
 * Reads the content of the <xkms:ServerRequest/> @node.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int  
xmlSecXkmsServerRequestNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx,
			      xmlNodePtr node) {
    xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    if(id->readNode != NULL) {
	return((id->readNode)(id, ctx, node));
    }
    return(0);
}

/**
 * xmlSecXkmsServerExecute:
 * @id:		the ServerRequest class.
 * @ctx:	the XKMS request processing context.
 *
 * Executes XKMS server request.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int  
xmlSecXkmsServerRequestExecute(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx) {
    xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, -1);
    xmlSecAssert2(ctx != NULL, -1);

    if(id->execute != NULL) {
	return((id->execute)(id, ctx));
    }
    return(0);
}


/**
 * xmlSecXkmsServerResponseNodeWrite:
 * @id:		the ServerRequest class.
 * @ctx:	the XKMS request processing context.
 * @doc:	the pointer to response parent XML document (might be NULL).
 * @node:       the pointer to response parent XML node (might be NULL).
 *
 * Writes XKMS response from context to a newly created node. Caller is 
 * responsible for adding the returned node to the XML document.
 *
 * Returns pointer to newly created XKMS response node or NULL
 * if an error occurs.
 */
EXPORT_C
xmlNodePtr 
xmlSecXkmsServerRequestNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx,
			         xmlDocPtr doc, xmlNodePtr node) {
    xmlNodePtr respNode;
    int ret;
    
    xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, NULL);
    xmlSecAssert2(ctx != NULL, NULL);

    /* create the response root node */
    if(node == NULL) {
        xmlNsPtr ns;
        
        respNode = xmlNewDocNode(doc, NULL, id->resultNodeName, NULL);
        if(respNode == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlNewDocNode",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        "node=%s",
		        xmlSecErrorsSafeString(id->resultNodeName));
            return(NULL);
        }
        ns = xmlNewNs(respNode, id->resultNodeNs, NULL);
        if(ns == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlNewNs",
		        XMLSEC_ERRORS_R_XML_FAILED,
		        "ns=%s",
		        xmlSecErrorsSafeString(id->resultNodeNs));
            xmlFreeNode(respNode);
            return(NULL);
        }
        xmlSetNs(respNode, ns);
    } else {
        respNode = xmlSecAddChild(node, id->resultNodeName, id->resultNodeNs);
        if(respNode == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecAddChild",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "node=%s",
		        xmlSecErrorsSafeString(id->resultNodeName));
            return(NULL);
        }
    }
    
    if(id->writeNode != NULL) {
	ret = (id->writeNode)(id, ctx, respNode);
	if(ret < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "writeNode",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "node=%s",
		        xmlSecErrorsSafeString(id->resultNodeName));
            xmlFreeNode(respNode);
            return(NULL);
        }
    }
    
    return(respNode);
}

/**
 * xmlSecXkmsServerRequestDebugDump:
 * @id:			the ServerRequest class.
 * @output:		the output file.
 *
 * Writes debug information about @id into the @output.
 */
EXPORT_C
void 
xmlSecXkmsServerRequestDebugDump(xmlSecXkmsServerRequestId id, FILE* output) {
    xmlSecAssert(id != xmlSecXkmsServerRequestIdUnknown);
    xmlSecAssert(output != NULL);

    fprintf(output, "=== ServerRequest: %s\n", xmlSecErrorsSafeString(id->name));
}

/**
 * xmlSecXkmsServerRequestDebugXmlDump:
 * @id:			the ServerRequest class.
 * @output:		the output file.
 *
 * Writes debug information about @id into the @output in XML format.
 */
EXPORT_C
void 
xmlSecXkmsServerRequestDebugXmlDump(xmlSecXkmsServerRequestId id, FILE* output) {
    xmlSecAssert(id != xmlSecXkmsServerRequestIdUnknown);
    xmlSecAssert(output != NULL);

    fprintf(output, "<ServerRequest>%s</ServerRequest>\n", xmlSecErrorsSafeString(id->name));
}

/************************************************************************
 *
 * XKMS ServerRequest Klass List
 *
 ************************************************************************/ 
static xmlSecPtrListKlass xmlSecXkmsServerRequestIdListKlass = {
    BAD_CAST "xkms-server-request-ids-list",
    NULL, 								/* xmlSecPtrDuplicateItemMethod duplicateItem; */
    NULL,								/* xmlSecPtrDestroyItemMethod destroyItem; */
    (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsServerRequestDebugDump,	/* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
    (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsServerRequestDebugXmlDump,	/* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
};
EXPORT_C

xmlSecPtrListId	
xmlSecXkmsServerRequestIdListGetKlass(void) {
    return(&xmlSecXkmsServerRequestIdListKlass);
}
EXPORT_C

int 
xmlSecXkmsServerRequestIdListFind(xmlSecPtrListPtr list, xmlSecXkmsServerRequestId id) {
    xmlSecSize i, size;
    
    xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsServerRequestIdListId), -1);
    xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, -1);
    
    size = xmlSecPtrListGetSize(list);
    for(i = 0; i < size; ++i) {
	if((xmlSecXkmsServerRequestId)xmlSecPtrListGetItem(list, i) == id) {
	    return(1);
	}
    }
    return(0);
}
EXPORT_C

xmlSecXkmsServerRequestId 
xmlSecXkmsServerRequestIdListFindByName(xmlSecPtrListPtr list, const xmlChar* name) {
    xmlSecXkmsServerRequestId id;
    xmlSecSize i, size;
    
    xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsServerRequestIdListId), xmlSecXkmsServerRequestIdUnknown);
    xmlSecAssert2(name != NULL, xmlSecXkmsServerRequestIdUnknown);

    size = xmlSecPtrListGetSize(list);
    for(i = 0; i < size; ++i) {
	id = (xmlSecXkmsServerRequestId)xmlSecPtrListGetItem(list, i);
	if((id !=  xmlSecXkmsServerRequestIdUnknown) && xmlStrEqual(id->name, name)) {
	    return(id);
	}
    }
    return(xmlSecXkmsServerRequestIdUnknown);    
}
EXPORT_C

xmlSecXkmsServerRequestId 
xmlSecXkmsServerRequestIdListFindByNode(xmlSecPtrListPtr list, xmlNodePtr node) {
    xmlSecXkmsServerRequestId id;
    xmlSecSize i, size;
    
    xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsServerRequestIdListId), xmlSecXkmsServerRequestIdUnknown);
    xmlSecAssert2(node != NULL, xmlSecXkmsServerRequestIdUnknown);

    size = xmlSecPtrListGetSize(list);
    for(i = 0; i < size; ++i) {
	id = (xmlSecXkmsServerRequestId)xmlSecPtrListGetItem(list, i);
	if((id !=  xmlSecXkmsServerRequestIdUnknown) &&
            xmlSecCheckNodeName(node, id->requestNodeName, id->requestNodeNs)) {

	    return(id);
	}
    }
    return(xmlSecXkmsServerRequestIdUnknown);    
}

/******************************************************************** 
 *
 * XML Sec Library ServerRequest Ids
 *
 *******************************************************************/


/******************************************************************** 
 *
 * Result response
 *
 *******************************************************************/
static int		xmlSecXkmsServerRequestResultNodeWrite	(xmlSecXkmsServerRequestId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);

static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestResultKlass = {
    xmlSecXkmsServerRequestResultName,		/* const xmlChar* name; */
    NULL,					/* const xmlChar* requestNodeName; */
    NULL,					/* const xmlChar* requestNodeNs; */
    xmlSecNodeResult,				/* const xmlChar* responseNodeName; */
    xmlSecXkmsNs,				/* const xmlChar* responseNodeNs; */
    0,                                          /* xmlSecBitMask flags; */
    NULL,					/* xmlSecXkmsServerRequestNodeReadMethod readNode; */
    xmlSecXkmsServerRequestResultNodeWrite,	/* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */
    NULL,					/* xmlSecXkmsServerRequestExecuteMethod execute; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsServerRequestResultGetKlass:
 *
 * The Result response klass.
 *
 * Returns Result response klass.
 */
EXPORT_C 
xmlSecXkmsServerRequestId	
xmlSecXkmsServerRequestResultGetKlass(void) {
    return(&xmlSecXkmsServerRequestResultKlass);
}

static int 
xmlSecXkmsServerRequestResultNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    int ret;
    
    xmlSecAssert2(id == xmlSecXkmsServerRequestResultId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* set missing parameters (if any) */
    if(ctx->service == NULL) {
	ctx->service = xmlStrdup((ctx->expectedService != NULL) ? ctx->expectedService : BAD_CAST "");
	if(ctx->service == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlStrdup",
		        XMLSEC_ERRORS_R_MALLOC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    }
    
    /* first write the "parent" type */
    ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxResultTypeNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }

    return(0);
}

/******************************************************************** 
 *
 * StatusRequest/StatusResponse
 *
 *******************************************************************/
static int  		xmlSecXkmsServerRequestStatusNodeRead	(xmlSecXkmsServerRequestId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static int		xmlSecXkmsServerRequestStatusNodeWrite	(xmlSecXkmsServerRequestId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);

static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestStatusKlass = {
    xmlSecXkmsServerRequestStatusName,		/* const xmlChar* name; */
    xmlSecNodeStatusRequest,			/* const xmlChar* requestNodeName; */
    xmlSecXkmsNs,				/* const xmlChar* requestNodeNs; */
    xmlSecNodeStatusResult,			/* const xmlChar* responseNodeName; */
    xmlSecXkmsNs,				/* const xmlChar* responseNodeNs; */
    0,                                          /* xmlSecBitMask flags; */
    xmlSecXkmsServerRequestStatusNodeRead,	/* xmlSecXkmsServerRequestNodeReadMethod readNode; */
    xmlSecXkmsServerRequestStatusNodeWrite,	/* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */
    NULL,					/* xmlSecXkmsServerRequestExecuteMethod execute; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsServerRequestStatusGetKlass:
 *
 * The StatusRequest klass.
 *
 * Returns StatusRequest klass.
 */
EXPORT_C 
xmlSecXkmsServerRequestId	
xmlSecXkmsServerRequestStatusGetKlass(void) {
    return(&xmlSecXkmsServerRequestStatusKlass);
}

/**
 * 
 *  <xkms:StatusRequest Id Service Nonce? OriginalRequestId? ResponseLimit? ResponseId?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:ResponseMechanism>*
 *      <xkms:RespondWith>*
 *      <xkms:PendingNotification Mechanism Identifier>?
 *  
 * XML Schema:
 *    <!-- StatusRequest -->   
 *    <element name="StatusRequest" type="xkms:StatusRequestType"/>   
 *    <complexType name="StatusRequestType">      
 *        <complexContent>         
 *            <extension base="xkms:PendingRequestType"/>      
 *        </complexContent>   
 *    </complexType>   
 *    <!-- /StatusRequest -->
 */
static int  
xmlSecXkmsServerRequestStatusNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlNodePtr cur;
    int ret;
    
    xmlSecAssert2(id == xmlSecXkmsServerRequestStatusId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    cur = node;
    
    /* first read "parent" type */
    ret = xmlSecXkmsServerCtxPendingRequestNodeRead(ctx, &cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxPendingRequestNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* check that there is nothing after the last node */
    if(cur != NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    return(0);
}

/**
 * 
 *  <xkms:StatusResult Id Service Nonce? ResultMajor ResultMinor? RequestId? Success? Failure? Pending?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:RequestSignatureValue>*
 *
 * XML Schema:
 * 
 *    <!-- StatusResult -->   
 *    <element name="StatusResult" type="xkms:StatusResultType"/>   
 *    <complexType name="StatusResultType">      
 *        <complexContent>
 *            <extension base="xkms:ResultType">
 *                <attribute name="Success" type="integer" use="optional"/>
 *                <attribute name="Failure" type="integer" use="optional"/>
 *                <attribute name="Pending" type="integer" use="optional"/>
 *            </extension>
 *        </complexContent>
 *    </complexType>
 *    <!-- /StatusResult --> *
 */ 
static int 
xmlSecXkmsServerRequestStatusNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    int ret;

    xmlSecAssert2(id == xmlSecXkmsServerRequestStatusId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* first write the "parent" type */
    ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxResultTypeNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    return(0);
}

/******************************************************************** 
 *
 * CompoundRequest/CompoundResponse
 *
 *******************************************************************/
static int  		xmlSecXkmsServerRequestCompoundNodeRead	(xmlSecXkmsServerRequestId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static int		xmlSecXkmsServerRequestCompoundNodeWrite(xmlSecXkmsServerRequestId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static int 		xmlSecXkmsServerRequestCompoundExecute	(xmlSecXkmsServerRequestId id, 
								 xmlSecXkmsServerCtxPtr ctx);

static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestCompoundKlass = {
    xmlSecXkmsServerRequestCompoundName,	/* const xmlChar* name; */
    xmlSecNodeCompoundRequest,			/* const xmlChar* requestNodeName; */
    xmlSecXkmsNs,				/* const xmlChar* requestNodeNs; */
    xmlSecNodeCompoundResult,			/* const xmlChar* responseNodeName; */
    xmlSecXkmsNs,				/* const xmlChar* responseNodeNs; */
    0,                                          /* xmlSecBitMask flags; */
    xmlSecXkmsServerRequestCompoundNodeRead,	/* xmlSecXkmsServerRequestNodeReadMethod readNode; */
    xmlSecXkmsServerRequestCompoundNodeWrite,	/* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */
    xmlSecXkmsServerRequestCompoundExecute,	/* xmlSecXkmsServerRequestExecuteMethod execute; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsServerRequestCompoundGetKlass:
 *
 * The CompoundRequest klass.
 *
 * Returns CompoundRequest klass.
 */
EXPORT_C 
xmlSecXkmsServerRequestId	
xmlSecXkmsServerRequestCompoundGetKlass(void) {
    return(&xmlSecXkmsServerRequestCompoundKlass);
}

/**
 *  <xkms:CompoundRequest Id Service Nonce? OriginalRequestId? ResponseLimit?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:ResponseMechanism>*
 *      <xkms:RespondWith>*
 *      <xkms:PendingNotification Mechanism Identifier>?
 *      (
 *       <xkms:LocateRequest>?
 *       <xkms:ValidateRequest>?
 *       <xkms:RegisterRequest>?
 *       <xkms:ReissueRequest>?
 *       <xkms:RecoverRequest>?
 *       <xkms:RevokeRequest>?
 *      )*
 *       
 * XML Schema:
 *
 *    <!-- CompoundRequest -->   
 *    <element name="CompoundRequest" type="xkms:CompoundRequestType"/>   
 *    <complexType name="CompoundRequestType">      
 *        <complexContent>         
 *            <extension base="xkms:RequestAbstractType">            
 *                <choice maxOccurs="unbounded">               
 *                    <element ref="xkms:LocateRequest"/>               
 *                    <element ref="xkms:ValidateRequest"/>               
 *                    <element ref="xkms:RegisterRequest"/>               
 *                    <element ref="xkms:ReissueRequest"/>               
 *                    <element ref="xkms:RecoverRequest"/>               
 *                    <element ref="xkms:RevokeRequest"/>            
 *                </choice>         
 *            </extension>      
 *        </complexContent>   
 *    </complexType>   
 *    <!-- /CompoundRequest -->
 */
static int  
xmlSecXkmsServerRequestCompoundNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlSecPtrListPtr serverRequestIdsList;
    xmlNodePtr cur;
    int ret;
    
    xmlSecAssert2(id == xmlSecXkmsServerRequestCompoundId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    cur = node;
    
    /* first read "parent" type */
    ret = xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(ctx, &cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxRequestAbstractTypeNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* create list for compound requests */
    xmlSecAssert2(ctx->compoundRequestContexts == NULL, -1);
    ctx->compoundRequestContexts = xmlSecPtrListCreate(xmlSecXkmsServerCtxPtrListId);
    if(ctx->compoundRequestContexts == NULL) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListCreate",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* get the list of enabled or all request klasses */
    if(xmlSecPtrListGetSize(&(ctx->enabledServerRequestIds)) > 0) {
	serverRequestIdsList = &(ctx->enabledServerRequestIds);
    } else {
	serverRequestIdsList = xmlSecXkmsServerRequestIdsGet();
    }
    xmlSecAssert2(serverRequestIdsList != NULL, -1); 
    
    while(cur != NULL) {
        xmlSecXkmsServerCtxPtr ctxChild;    
        
        /* create a new context */
        ctxChild = xmlSecXkmsServerCtxCreate(ctx->keyInfoReadCtx.keysMngr);
        if(ctxChild == NULL) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerCtxCreate",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
        }

        /* copy all settings from us */
        ret = xmlSecXkmsServerCtxCopyUserPref(ctxChild, ctx);
        if(ret < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerCtxCopyUserPref",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
            xmlSecXkmsServerCtxDestroy(ctxChild);
	    return(-1);
        }

        /* add it to the list */
        ret = xmlSecPtrListAdd(ctx->compoundRequestContexts, ctxChild);
        if(ret < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecPtrListAdd",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        XMLSEC_ERRORS_NO_MESSAGE);
            xmlSecXkmsServerCtxDestroy(ctxChild);
	    return(-1);
        }

        /* and now process request from current node */
        ctxChild->requestId = xmlSecXkmsServerRequestIdListFindByNode(serverRequestIdsList, cur);
        if((ctxChild->requestId == xmlSecXkmsServerRequestIdUnknown) || 
           ((ctxChild->requestId->flags & XMLSEC_XKMS_SERVER_REQUEST_KLASS_ALLOWED_IN_COUMPOUND) == 0)) {
            xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerRequestIdListFindByNode",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "node=%s",
		        xmlSecErrorsSafeString(node->name));
	    xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorMessageNotSupported);
	    return(-1);
        }

        ret = xmlSecXkmsServerRequestNodeRead(ctxChild->requestId, ctxChild, cur);
        if(ret < 0) {
    	    xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecXkmsServerRequestNodeRead",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "request=%s",
		        xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctxChild->requestId)));
	    xmlSecXkmsServerCtxSetResult(ctxChild, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	    return(-1);
        }
        cur = xmlSecGetNextElementNode(cur->next);
    }

    /* check that there is nothing after the last node */
    if(cur != NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    return(0);
}

/**
 *  <xkms:CompoundResult Id Service Nonce? ResultMajor ResultMinor? RequestId?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:RequestSignatureValue>*
 *      (
 *       <xkms:LocateResult>?
 *       <xkms:ValidateResult>?
 *       <xkms:RegisterResult>?
 *       <xkms:ReissueResult>?
 *       <xkms:RecoverResult>?
 *       <xkms:RevokeResult>?
 *      )*
 *
 * 
 * XML Schema:
 *
 *    <!-- CompoundResponse -->   
 *    <element name="CompoundResult" type="xkms:CompoundResultType"/>   
 *    <complexType name="CompoundResultType">      
 *        <complexContent>         
 *            <extension base="xkms:ResultType">            
 *                <choice maxOccurs="unbounded">               
 *                    <element ref="xkms:LocateResult"/>
 *                    <element ref="xkms:ValidateResult"/>
 *                    <element ref="xkms:RegisterResult"/>
 *                    <element ref="xkms:ReissueResult"/>
 *                    <element ref="xkms:RecoverResult"/>
 *                    <element ref="xkms:RevokeResult"/>
 *                </choice>
 *            </extension>
 *        </complexContent>
 *   </complexType>
 *   <!-- /CompoundResponse -->
 */ 
static int 
xmlSecXkmsServerRequestCompoundNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    int ret;

    xmlSecAssert2(id == xmlSecXkmsServerRequestCompoundId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* walk thru the list of chilren and pickup first error */
    if(ctx->compoundRequestContexts != NULL) {
        xmlSecSize pos;

        for(pos = 0; pos < xmlSecPtrListGetSize(ctx->compoundRequestContexts); pos++) {
            xmlSecXkmsServerCtxPtr ctxChild;

            ctxChild = (xmlSecXkmsServerCtxPtr)xmlSecPtrListGetItem(ctx->compoundRequestContexts, pos);
            if(ctxChild == NULL) {
	        xmlSecError(XMLSEC_ERRORS_HERE,
		            NULL,
		            "xmlSecPtrListGetItem",
		            XMLSEC_ERRORS_R_XMLSEC_FAILED,
		            XMLSEC_ERRORS_NO_MESSAGE);
	        return(-1);  	
            }
	    
	    if(ctxChild->resultMajor != xmlSecXkmsResultMajorSuccess) {
	        xmlSecXkmsServerCtxSetResult(ctx, ctxChild->resultMajor, ctxChild->resultMinor);
		break;
	    }
	}
    }
    
    /* first write the "parent" type */
    ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxResultTypeNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    /* write compound result */
    if(ctx->compoundRequestContexts != NULL) {
        xmlSecSize pos;

        for(pos = 0; pos < xmlSecPtrListGetSize(ctx->compoundRequestContexts); pos++) {
            xmlSecXkmsServerCtxPtr ctxChild;
            xmlNodePtr cur;

            ctxChild = (xmlSecXkmsServerCtxPtr)xmlSecPtrListGetItem(ctx->compoundRequestContexts, pos);
            if(ctxChild == NULL) {
	        xmlSecError(XMLSEC_ERRORS_HERE,
		            NULL,
		            "xmlSecPtrListGetItem",
		            XMLSEC_ERRORS_R_XMLSEC_FAILED,
		            XMLSEC_ERRORS_NO_MESSAGE);
	        return(-1);  	
            }
            
            cur = xmlSecXkmsServerRequestNodeWrite(ctxChild->requestId, ctxChild, node->doc, node);
            if(cur == NULL) {
    	        xmlSecError(XMLSEC_ERRORS_HERE,
		            NULL,
		            "xmlSecXkmsServerRequestNodeWrite",
		            XMLSEC_ERRORS_R_XMLSEC_FAILED,
		            "request=%s",
		            xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctxChild->requestId)));
                return(-1);
            }
            
            if(xmlSecAddChildNode(node, cur) == NULL) {
	        xmlSecError(XMLSEC_ERRORS_HERE,
			    NULL,
			    "xmlSecAddChildNode",
			    XMLSEC_ERRORS_R_XMLSEC_FAILED,
			    XMLSEC_ERRORS_NO_MESSAGE);
                xmlFreeNode(cur);
                return(-1);
	    }
        }
    }

    return(0);
}

static int 
xmlSecXkmsServerRequestCompoundExecute(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx) {
    int ret;
    
    xmlSecAssert2(id == xmlSecXkmsServerRequestCompoundId, -1);
    xmlSecAssert2(ctx != NULL, -1);

    if(ctx->compoundRequestContexts != NULL) {
        xmlSecSize pos;

        for(pos = 0; pos < xmlSecPtrListGetSize(ctx->compoundRequestContexts); pos++) {
            xmlSecXkmsServerCtxPtr ctxChild;

            ctxChild = (xmlSecXkmsServerCtxPtr)xmlSecPtrListGetItem(ctx->compoundRequestContexts, pos);
            if(ctxChild == NULL) {
	        xmlSecError(XMLSEC_ERRORS_HERE,
		            NULL,
		            "xmlSecPtrListGetItem",
		            XMLSEC_ERRORS_R_XMLSEC_FAILED,
		            XMLSEC_ERRORS_NO_MESSAGE);
	        xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure);
	        continue;  	
            }
            
            ret = xmlSecXkmsServerRequestExecute(ctxChild->requestId, ctxChild);
            if(ret < 0) {
    	        xmlSecError(XMLSEC_ERRORS_HERE,
		            NULL,
		            "xmlSecXkmsServerRequestExecute",
		            XMLSEC_ERRORS_R_XMLSEC_FAILED,
		            "request=%s",
		            xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctxChild->requestId)));
	        xmlSecXkmsServerCtxSetResult(ctxChild, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure);
	        continue;  	
            }
        }
    }

    return(0);
}


/******************************************************************** 
 *
 * LocateRequest/LocateResponse
 *
 *******************************************************************/
static int  		xmlSecXkmsServerRequestLocateNodeRead	(xmlSecXkmsServerRequestId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static int		xmlSecXkmsServerRequestLocateNodeWrite	(xmlSecXkmsServerRequestId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static int 		xmlSecXkmsServerRequestLocateExecute	(xmlSecXkmsServerRequestId id, 
								 xmlSecXkmsServerCtxPtr ctx);

static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestLocateKlass = {
    xmlSecXkmsServerRequestLocateName,		/* const xmlChar* name; */
    xmlSecNodeLocateRequest,			/* const xmlChar* requestNodeName; */
    xmlSecXkmsNs,				/* const xmlChar* requestNodeNs; */
    xmlSecNodeLocateResult,			/* const xmlChar* responseNodeName; */
    xmlSecXkmsNs,				/* const xmlChar* responseNodeNs; */
    XMLSEC_XKMS_SERVER_REQUEST_KLASS_ALLOWED_IN_COUMPOUND,      /* xmlSecBitMask flags; */
    xmlSecXkmsServerRequestLocateNodeRead,	/* xmlSecXkmsServerRequestNodeReadMethod readNode; */
    xmlSecXkmsServerRequestLocateNodeWrite,	/* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */
    xmlSecXkmsServerRequestLocateExecute,	/* xmlSecXkmsServerRequestExecuteMethod execute; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsServerRequestLocateGetKlass:
 *
 * The LocateRequest klass.
 *
 * Returns LocateRequest klass.
 */
EXPORT_C 
xmlSecXkmsServerRequestId	
xmlSecXkmsServerRequestLocateGetKlass(void) {
    return(&xmlSecXkmsServerRequestLocateKlass);
}

/**
 *  <xkms:LocateRequest Id Service Nonce? OriginalRequestId? ResponseLimit?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:ResponseMechanism>*
 *      <xkms:RespondWith>*
 *      <xkms:PendingNotification Mechanism Identifier>?
 *      <xkms:QueryKeyBinding Id?>
 *          <ds:KeyInfo>?
 *          <xkms:KeyUsage>?
 *          <xkms:KeyUsage>?
 *          <xkms:KeyUsage>?
 *          <xkms:UseKeyWith Application Identifier>*    
 *          <xkms:TimeInstant Time>?
 *
 * XML Schema:
 *
 *    <!-- LocateRequest -->
 *    <element name="LocateRequest" type="xkms:LocateRequestType"/>
 *    <complexType name="LocateRequestType">
 *        <complexContent>
 *            <extension base="xkms:RequestAbstractType">
 *                <sequence>
 *                    <element ref="xkms:QueryKeyBinding"/>
 *                </sequence>
 *            </extension>
 *        </complexContent>
 *    </complexType>
 *    <!-- /LocateRequest -->
 */
static int  
xmlSecXkmsServerRequestLocateNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlNodePtr cur;
    int ret;
    
    xmlSecAssert2(id == xmlSecXkmsServerRequestLocateId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    cur = node;
    
    /* first read "parent" type */
    ret = xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(ctx, &cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxRequestAbstractTypeNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* now read required <xkms:QueryKeyBinding/> node */
    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeQueryKeyBinding, xmlSecXkmsNs))) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_INVALID_NODE,
		    "node=%s", 
		    xmlSecErrorsSafeString(xmlSecNodeQueryKeyBinding));
	return(-1);
    }
    
    /* read <xkms:QueryKeyBinding/> node */    
    ret = xmlSecXkmsServerCtxQueryKeyBindingNodeRead(ctx, cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxQueryKeyBindingNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    cur = xmlSecGetNextElementNode(cur->next);    

    /* check that there is nothing after the last node */
    if(cur != NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    return(0);
}

/**
 *  <xkms:LocateResult Id Service Nonce? ResultMajor ResultMinor? RequestId?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:RequestSignatureValue>*
 *      (<xkms:UnverifiedKeyBinding Id?>
 *          <ds:KeyInfo>?
 *          <xkms:KeyUsage>?
 *          <xkms:KeyUsage>?
 *          <xkms:KeyUsage>?
 *          <xkms:UseKeyWith Application Identifier>*    
 *          <xkms:ValidityInterval NotBefore NotOnOrAfter>?
 *      )*
 * 
 * XML Schema:
 *    <!-- LocateResult -->
 *    <element name="LocateResult" type="xkms:LocateResultType"/>
 *    <complexType name="LocateResultType">
 *         <complexContent>
 *	        <extension base="xkms:ResultType">
 *		     <sequence>
 *		         <element ref="xkms:UnverifiedKeyBinding" minOccurs="0" 
 *			          maxOccurs="unbounded"/>
 *		     </sequence>
 *		</extension>
 *	   </complexContent>
 *    </complexType>
 *    <!-- /LocateResult -->
 */ 
static int 
xmlSecXkmsServerRequestLocateNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlSecSize pos, size;
    xmlSecKeyPtr key;
    xmlNodePtr cur;
    int ret;

    xmlSecAssert2(id == xmlSecXkmsServerRequestLocateId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* first write the "parent" type */
    ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxResultTypeNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    /* write keys in <xkms:UnverifiedKeyBinding> nodes */
    size = xmlSecPtrListGetSize(&(ctx->keys));
    for(pos = 0; pos < size; ++pos) {
	key = (xmlSecKeyPtr)xmlSecPtrListGetItem(&(ctx->keys), pos);
	if(key == NULL) {
	    continue;
	}
            
	cur = xmlSecAddChild(node, xmlSecNodeUnverifiedKeyBinding, xmlSecXkmsNs);
	if(cur == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecAddChild",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"node=%s",
			xmlSecErrorsSafeString(xmlSecNodeUnverifiedKeyBinding));
	    return(-1);  	
    	}

	ret = xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite(ctx, cur, key);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);  	
	}
    }

    return(0);
}

static int 
xmlSecXkmsServerRequestLocateExecute(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx) {
    xmlSecKeyPtr key = NULL;
    int ret;
    
    xmlSecAssert2(id == xmlSecXkmsServerRequestLocateId, -1);
    xmlSecAssert2(ctx != NULL, -1);

    /* now we are ready to search for key */
    if((ctx->keyInfoReadCtx.keysMngr != NULL) && (ctx->keyInfoReadCtx.keysMngr->getKey != NULL)) {
	key = (ctx->keyInfoReadCtx.keysMngr->getKey)(ctx->keyInfoNode, &(ctx->keyInfoReadCtx));
    }
    
    /* check that we got what we needed */
    if((key == NULL) || (!xmlSecKeyMatch(key, NULL, &(ctx->keyInfoReadCtx.keyReq)))) {
	if(key != NULL) {
    	    xmlSecKeyDestroy(key);
	}
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorNoMatch);
	return(-1);
    } 
        
    xmlSecAssert2(key != NULL, -1);
    ret = xmlSecPtrListAdd(&(ctx->keys), key);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListAdd",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecKeyDestroy(key);
	return(-1);
    }
    
    return(0);
}


/******************************************************************** 
 *
 * ValidateRequest/ValidateResponse
 *
 *******************************************************************/
static int  		xmlSecXkmsServerRequestValidateNodeRead	(xmlSecXkmsServerRequestId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static int		xmlSecXkmsServerRequestValidateNodeWrite(xmlSecXkmsServerRequestId id,
								 xmlSecXkmsServerCtxPtr ctx,
								 xmlNodePtr node);
static int 		xmlSecXkmsServerRequestValidateExecute	(xmlSecXkmsServerRequestId id, 
								 xmlSecXkmsServerCtxPtr ctx);

static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestValidateKlass = {
    xmlSecXkmsServerRequestValidateName,	/* const xmlChar* name; */
    xmlSecNodeValidateRequest,			/* const xmlChar* requestNodeName; */
    xmlSecXkmsNs,				/* const xmlChar* requestNodeNs; */
    xmlSecNodeValidateResult,			/* const xmlChar* responseNodeName; */
    xmlSecXkmsNs,				/* const xmlChar* responseNodeNs; */
    XMLSEC_XKMS_SERVER_REQUEST_KLASS_ALLOWED_IN_COUMPOUND,      /* xmlSecBitMask flags; */
    xmlSecXkmsServerRequestValidateNodeRead,	/* xmlSecXkmsServerRequestNodeReadMethod readNode; */
    xmlSecXkmsServerRequestValidateNodeWrite,	/* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */
    xmlSecXkmsServerRequestValidateExecute,	/* xmlSecXkmsServerRequestExecuteMethod execute; */
    NULL,                                       /* void* reserved1; */
    NULL                                        /* void* reserved2; */
};

/**
 * xmlSecXkmsServerRequestValidateGetKlass:
 *
 * The ValidateRequest klass.
 *
 * Returns ValidateRequest klass.
 */
EXPORT_C 
xmlSecXkmsServerRequestId	
xmlSecXkmsServerRequestValidateGetKlass(void) {
    return(&xmlSecXkmsServerRequestValidateKlass);
}

/**
 *  <xkms:ValidateRequest Id Service Nonce? OriginalRequestId? ResponseLimit?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *          <xkms:OpaqueData>?
 *      )?
 *      <xkms:ResponseMechanism>*
 *      <xkms:RespondWith>*
 *      <xkms:PendingNotification Mechanism Identifier>?
 *      <xkms:QueryKeyBinding Id?>
 *          <ds:KeyInfo>?
 *          <xkms:KeyUsage>?
 *          <xkms:KeyUsage>?
 *          <xkms:KeyUsage>?
 *          <xkms:UseKeyWith Application Identifier>*    
 *          <xkms:TimeInstant Time>?
 * 
 * XML Schema:
 * 
 *    <!-- ValidateRequest -->   
 *    <element name="ValidateRequest" type="xkms:ValidateRequestType"/>   
 *    <complexType name="ValidateRequestType">      
 *        <complexContent>         
 *            <extension base="xkms:RequestAbstractType">
 *                <sequence>
 *                    <element ref="xkms:QueryKeyBinding"/>
 *                </sequence>
 *            </extension>						         
 *        </complexContent> 
 *    </complexType>
 *    <!-- /ValidateRequest -->							        
 */
static int  
xmlSecXkmsServerRequestValidateNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlNodePtr cur;
    int ret;
    
    xmlSecAssert2(id == xmlSecXkmsServerRequestValidateId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    cur = node;
    
    /* first read "parent" type */
    ret = xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(ctx, &cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxRequestAbstractTypeNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    /* now read required <xkms:QueryKeyBinding/> node */
    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeQueryKeyBinding, xmlSecXkmsNs))) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_INVALID_NODE,
		    "node=%s", 
		    xmlSecErrorsSafeString(xmlSecNodeQueryKeyBinding));
	return(-1);
    }
    
    /* read <xkms:QueryKeyBinding/> node */    
    ret = xmlSecXkmsServerCtxQueryKeyBindingNodeRead(ctx, cur);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxQueryKeyBindingNodeRead",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }
    cur = xmlSecGetNextElementNode(cur->next);    

    /* check that there is nothing after the last node */
    if(cur != NULL) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    return(0);
}

/**
 *  <xkms:ValidateResult Id Service Nonce? ResultMajor ResultMinor? RequestId?>
 *      <ds:Signature>?
 *      <xkms:MessageExtension>*
 *      (<xkms:OpaqueClientData>
 *           <xkms:OpaqueData>?
 *      )?
 *      <xkms:RequestSignatureValue>*
 *      (<xkms:KeyBinding Id?>
 *          <ds:KeyInfo>?
 *          <xkms:KeyUsage>?
 *          <xkms:KeyUsage>?
 *          <xkms:KeyUsage>?
 *          <xkms:UseKeyWith Application Identifier>*    
 *          <xkms:ValidityInterval NotBefore NotOnOrAfter>?
 *          <xkms:Status StatusValue>
 *              (<xkms:ValidReason>?
 *               <xkms:IndeterminateReason>?
 *               <xkms:InvalidReason>?
 *              )*
 *      )*
 * 
 * XML Schema:
 *
 *    <!-- ValidateResult -->   
 *    <element name="ValidateResult" type="xkms:ValidateResultType"/>
 *    <complexType name="ValidateResultType">
 *        <complexContent>
 *            <extension base="xkms:ResultType">
 *                <sequence>
 *                    <element ref="xkms:KeyBinding" minOccurs="0" 
 *				    maxOccurs="unbounded"/>
 *                </sequence>
 *            </extension>
 *        </complexContent>
 *    </complexType>
 *    <!-- /ValidateResult -->
 */ 
static int 
xmlSecXkmsServerRequestValidateNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) {
    xmlSecSize pos, size;
    xmlSecKeyPtr key;
    xmlNodePtr cur;
    int ret;

    xmlSecAssert2(id == xmlSecXkmsServerRequestValidateId, -1);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    /* first write the "parent" type */
    ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecXkmsServerCtxResultTypeNodeWrite",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);  	
    }
    
    /* write keys in <xkms:UnverifiedKeyBinding> nodes */
    size = xmlSecPtrListGetSize(&(ctx->keys));
    for(pos = 0; pos < size; ++pos) {
	key = (xmlSecKeyPtr)xmlSecPtrListGetItem(&(ctx->keys), pos);
	if(key == NULL) {
	    continue;
	}
            
	cur = xmlSecAddChild(node, xmlSecNodeUnverifiedKeyBinding, xmlSecXkmsNs);
	if(cur == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecAddChild",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"node=%s",
			xmlSecErrorsSafeString(xmlSecNodeUnverifiedKeyBinding));
	    return(-1);  	
    	}

	ret = xmlSecXkmsServerCtxKeyBindingNodeWrite(ctx, cur, key);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecXkmsServerCtxKeyBindingNodeWrite",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);  	
	}
    }

    return(0);
}

static int 
xmlSecXkmsServerRequestValidateExecute(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx) {
    xmlSecKeyPtr key = NULL;
    int ret;
    
    xmlSecAssert2(id == xmlSecXkmsServerRequestValidateId, -1);
    xmlSecAssert2(ctx != NULL, -1);

    /* now we are ready to search for key */
    if((ctx->keyInfoReadCtx.keysMngr != NULL) && (ctx->keyInfoReadCtx.keysMngr->getKey != NULL)) {
	key = (ctx->keyInfoReadCtx.keysMngr->getKey)(ctx->keyInfoNode, &(ctx->keyInfoReadCtx));
    }
    
    /* check that we got what we needed */
    if((key == NULL) || (!xmlSecKeyMatch(key, NULL, &(ctx->keyInfoReadCtx.keyReq)))) {
	if(key != NULL) {
    	    xmlSecKeyDestroy(key);
	}
	xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorNoMatch);
	return(-1);
    } 
        
    xmlSecAssert2(key != NULL, -1);
    ret = xmlSecPtrListAdd(&(ctx->keys), key);
    if(ret < 0) {
    	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecPtrListAdd",
		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecKeyDestroy(key);
	return(-1);
    }
    
    return(0);
}

#endif /* XMLSEC_NO_XKMS */