/** * 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-2016 Aleksey Sanin . All Rights Reserved. */ #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", (int)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) { ret = xmlSecKeySetName(key, newName); if(ret < 0) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), "xmlSecKeySetName", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); xmlFree(newName); return(-1); } } 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 */