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