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