/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/transform_helpers.c
1 941 строка
64 KB
lsh123
(xmlsec-core) Added xmlSecMemEqual to compare two buffers in constant time and upgraded the code to use it (#1191)
30 май 2026, 05:26
Не верифицирован
30 май 2026, 05:26
0fb64f6
Код
Авторство
О чём код?
/** * XML Security Library (http://www.aleksey.com/xmlsec). * * This is free software; see the Copyright file in the source distribution for precise wording. * * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. */ /** * @brief Helper functions for transform implementations. */ #include "globals.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stddef.h> #include <libxml/tree.h> #include <libxml/xpath.h> #include <libxml/xpointer.h> #include <xmlsec/xmlsec.h> #include <xmlsec/buffer.h> #include <xmlsec/xmltree.h> #include <xmlsec/keysdata.h> #include <xmlsec/keys.h> #include <xmlsec/keyinfo.h> #include <xmlsec/keysmngr.h> #include <xmlsec/transforms.h> #include <xmlsec/base64.h> #include <xmlsec/io.h> #include <xmlsec/membuf.h> #include <xmlsec/parser.h> #include <xmlsec/errors.h> #include "cast_helpers.h" #include "keysdata_helpers.h" #include "transform_helpers.h" /****************************************************************************** * * Helper transform functions * *****************************************************************************/ #ifndef XMLSEC_NO_CONCATKDF #define XMLSEC_TRANSFORM_CONCATKDF_DEFAULT_BUF_SIZE 64 /* reads optional attribute and decodes it as bit string (https://www.w3.org/TR/xmlenc-core1/#sec-ConcatKDF): * * 1/ The bitstring is divided into octets using big-endian encoding. If the length of the bitstring is not * a multiple of 8 then add padding bits (value 0) as necessary to the last octet to make it a multiple of 8. * 2/ Prepend one octet to the octets string from step 1. This octet shall identify (in a big-endian representation) * the number of padding bits added to the last octet in step 1. * 3/ Encode the octet string resulting from step 2 as a hexBinary string. * * Example: the bitstring 11011, which is 5 bits long, gets 3 additional padding bits to become the bitstring * 11011000 (or D8 in hex). This bitstring is then prepended with one octet identifying the number of padding bits * to become the octet string (in hex) 03D8, which then finally is encoded as a hexBinary string value of "03D8". * * While any bit string can be used with ConcatKDF, it is RECOMMENDED to keep byte aligned for greatest interoperability. * * TODO: only bit aligned bit strings are supported (https://github.com/lsh123/xmlsec/issues/514) */ static int xmlSecTransformConcatKdfParamsReadsBitsAttr(xmlSecBufferPtr buf, xmlNodePtr node, const xmlChar* attrName) { xmlChar * attrValue; xmlSecByte* data; xmlSecSize size; int ret; xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(node!= NULL, -1); xmlSecAssert2(attrName != NULL, -1); attrValue = xmlGetProp(node, attrName); if(attrValue == NULL) { xmlSecBufferEmpty(buf); return(0); } ret = xmlSecBufferHexRead(buf, attrValue); if(ret < 0) { xmlSecInternalError("xmlSecBufferHexRead", NULL); xmlFree(attrValue); return(-1); } xmlFree(attrValue); data = xmlSecBufferGetData(buf); size = xmlSecBufferGetSize(buf); if((data == NULL) || (size <= 0)) { /* xmlSecInvalidSizeDataError("size", size, "at least one byte is expected", NULL); */ /* ignore empty buffer */ return(0); } /* only byte aligned bit strings are supported */ if(data[0] != 0) { xmlSecInvalidDataError("First bit string byte should be 0 (only byte aligned bit strings are supported)", NULL); return (-1); } ret = xmlSecBufferRemoveHead(buf, 1); if(ret < 0) { xmlSecInternalError("xmlSecBufferHexRead", NULL); return(-1); } /* done */ return(0); } int xmlSecTransformConcatKdfParamsInitialize(xmlSecTransformConcatKdfParamsPtr params) { int ret; xmlSecAssert2(params != NULL, -1); memset(params, 0, sizeof(*params)); ret = xmlSecBufferInitialize(&(params->bufAlgorithmID), XMLSEC_TRANSFORM_CONCATKDF_DEFAULT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(bufAlgorithmID)", NULL); xmlSecTransformConcatKdfParamsFinalize(params); return(-1); } ret = xmlSecBufferInitialize(&(params->bufPartyUInfo), XMLSEC_TRANSFORM_CONCATKDF_DEFAULT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(bufPartyUInfo)", NULL); xmlSecTransformConcatKdfParamsFinalize(params); return(-1); } ret = xmlSecBufferInitialize(&(params->bufPartyVInfo), XMLSEC_TRANSFORM_CONCATKDF_DEFAULT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(bufPartyVInfo)", NULL); xmlSecTransformConcatKdfParamsFinalize(params); return(-1); } ret = xmlSecBufferInitialize(&(params->bufSuppPubInfo), XMLSEC_TRANSFORM_CONCATKDF_DEFAULT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(bufSuppPubInfo)", NULL); xmlSecTransformConcatKdfParamsFinalize(params); return(-1); } ret = xmlSecBufferInitialize(&(params->bufSuppPrivInfo), XMLSEC_TRANSFORM_CONCATKDF_DEFAULT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(bufSuppPrivInfo)", NULL); xmlSecTransformConcatKdfParamsFinalize(params); return(-1); } /* done */ return(0); } void xmlSecTransformConcatKdfParamsFinalize(xmlSecTransformConcatKdfParamsPtr params) { xmlSecAssert(params != NULL); if(params->digestMethod != NULL) { xmlFree(params->digestMethod); } xmlSecBufferFinalize(&(params->bufAlgorithmID)); xmlSecBufferFinalize(&(params->bufPartyUInfo)); xmlSecBufferFinalize(&(params->bufPartyVInfo)); xmlSecBufferFinalize(&(params->bufSuppPubInfo)); xmlSecBufferFinalize(&(params->bufSuppPrivInfo)); memset(params, 0, sizeof(*params)); } int xmlSecTransformConcatKdfParamsRead(xmlSecTransformConcatKdfParamsPtr params, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(params != NULL, -1); xmlSecAssert2(node != NULL, -1); /* first (and only) node is required DigestMethod */ cur = xmlSecGetNextElementNode(node->children); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDigestMethod, xmlSecDSigNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeDigestMethod, NULL); return(-1); } params->digestMethod = xmlGetProp(cur, xmlSecAttrAlgorithm); if(params->digestMethod == NULL) { xmlSecInvalidNodeAttributeError(cur, xmlSecAttrAlgorithm, NULL, "empty"); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* if we have something else then it's an error */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* now read all attributes */ ret = xmlSecTransformConcatKdfParamsReadsBitsAttr(&(params->bufAlgorithmID), node, xmlSecNodeConcatKDFAttrAlgorithmID); if(ret < 0) { xmlSecInternalError("xmlSecTransformConcatKdfParamsReadsBitsAttr(AlgorithmID)", NULL); return(-1); } ret = xmlSecTransformConcatKdfParamsReadsBitsAttr(&(params->bufPartyUInfo), node, xmlSecNodeConcatKDFAttrPartyUInfo); if(ret < 0) { xmlSecInternalError("xmlSecTransformConcatKdfParamsReadsBitsAttr(PartyUInfo)", NULL); return(-1); } ret = xmlSecTransformConcatKdfParamsReadsBitsAttr(&(params->bufPartyVInfo), node, xmlSecNodeConcatKDFAttrPartyVInfo); if(ret < 0) { xmlSecInternalError("xmlSecTransformConcatKdfParamsReadsBitsAttr(PartyVInfo)", NULL); return(-1); } ret = xmlSecTransformConcatKdfParamsReadsBitsAttr(&(params->bufSuppPubInfo), node, xmlSecNodeConcatKDFAttrSuppPubInfo); if(ret < 0) { xmlSecInternalError("xmlSecTransformConcatKdfParamsReadsBitsAttr(SuppPubInfo)", NULL); return(-1); } ret = xmlSecTransformConcatKdfParamsReadsBitsAttr(&(params->bufSuppPrivInfo), node, xmlSecNodeConcatKDFAttrSuppPrivInfo); if(ret < 0) { xmlSecInternalError("xmlSecTransformConcatKdfParamsReadsBitsAttr(ASuppPrivInfo)", NULL); return(-1); } /* done! */ return(0); } /* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar3.pdf * For this format, FixedInfo is a bit string equal to the following concatenation: * * AlgorithmID || PartyUInfo || PartyVInfo {|| SuppPubInfo }{|| SuppPrivInfo } */ int xmlSecTransformConcatKdfParamsGetFixedInfo(xmlSecTransformConcatKdfParamsPtr params, xmlSecBufferPtr bufFixedInfo) { xmlSecSize size; int ret; xmlSecAssert2(params != NULL, -1); xmlSecAssert2(bufFixedInfo != NULL, -1); size = xmlSecBufferGetSize(&(params->bufAlgorithmID)) + xmlSecBufferGetSize(&(params->bufPartyUInfo)) + xmlSecBufferGetSize(&(params->bufPartyVInfo)) + xmlSecBufferGetSize(&(params->bufSuppPubInfo)) + xmlSecBufferGetSize(&(params->bufSuppPrivInfo)); ret = xmlSecBufferSetMaxSize(bufFixedInfo, size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetMaxSize", NULL, "size=" XMLSEC_SIZE_FMT, size); return (-1); } ret = xmlSecBufferSetData(bufFixedInfo, xmlSecBufferGetData(&(params->bufAlgorithmID)), xmlSecBufferGetSize(&(params->bufAlgorithmID))); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetData(AlgorithmID)", NULL); return (-1); } ret = xmlSecBufferAppend(bufFixedInfo, xmlSecBufferGetData(&(params->bufPartyUInfo)), xmlSecBufferGetSize(&(params->bufPartyUInfo))); if(ret < 0) { xmlSecInternalError("xmlSecBufferAppend(PartyUInfo)", NULL); return (-1); } ret = xmlSecBufferAppend(bufFixedInfo, xmlSecBufferGetData(&(params->bufPartyVInfo)), xmlSecBufferGetSize(&(params->bufPartyVInfo))); if(ret < 0) { xmlSecInternalError("xmlSecBufferAppend(PartyVInfo)", NULL); return (-1); } ret = xmlSecBufferAppend(bufFixedInfo, xmlSecBufferGetData(&(params->bufSuppPubInfo)), xmlSecBufferGetSize(&(params->bufSuppPubInfo))); if(ret < 0) { xmlSecInternalError("xmlSecBufferAppend(SuppPubInfo)", NULL); return (-1); } ret = xmlSecBufferAppend(bufFixedInfo, xmlSecBufferGetData(&(params->bufSuppPrivInfo)), xmlSecBufferGetSize(&(params->bufSuppPrivInfo))); if(ret < 0) { xmlSecInternalError("xmlSecBufferAppend(SuppPrivInfo)", NULL); return (-1); } /* done */ return(0); } #endif /* XMLSEC_NO_CONCATKDF */ xmlSecKeyPtr xmlSecTransformReadKeyInfoNode(xmlSecKeyDataType keyType, xmlNodePtr node, xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) { xmlSecKeyInfoCtx keyInfoCtx; xmlSecKeysMngrPtr keysMngr; xmlSecKeyPtr key = NULL; xmlSecKeyPtr res = NULL; int ret; xmlSecAssert2(node != NULL, NULL); xmlSecAssert2(transform != NULL, NULL); xmlSecAssert2(transformCtx != NULL, NULL); xmlSecAssert2(transformCtx->parentKeyInfoCtx != NULL, NULL); keysMngr = transformCtx->parentKeyInfoCtx->keysMngr; xmlSecAssert2(keysMngr != NULL, NULL); xmlSecAssert2(keysMngr->getKey != NULL, NULL); /* create keyinfo ctx */ ret = xmlSecKeyInfoCtxInitialize(&keyInfoCtx, keysMngr); if(ret < 0) { xmlSecInternalError("xmlSecKeyInfoCtxInitialize(recipient)", xmlSecNodeGetName(node)); return(NULL); } ret = xmlSecKeyInfoCtxCopyUserPref(&keyInfoCtx, transformCtx->parentKeyInfoCtx); if(ret < 0) { xmlSecInternalError("xmlSecKeyInfoCtxCopyUserPref(recipient)", xmlSecNodeGetName(node)); goto done; } keyInfoCtx.mode = xmlSecKeyInfoModeRead; ret = xmlSecTransformSetKeyReq(transform, &(keyInfoCtx.keyReq)); if(ret < 0) { xmlSecInternalError("xmlSecTransformSetKeyReq(originator)", xmlSecNodeGetName(node)); goto done; } keyInfoCtx.keyReq.keyType = keyType; key = (keysMngr->getKey)(node, &keyInfoCtx); if(key == NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_KEY_NOT_FOUND, xmlSecNodeGetName(node), "key not found"); goto done; } if(!xmlSecKeyMatch(key, NULL, &(keyInfoCtx.keyReq))) { xmlSecOtherError(XMLSEC_ERRORS_R_KEY_NOT_FOUND, xmlSecNodeGetName(node), "key doesn't match requiremetns"); goto done; } /* success */ res = key; key = NULL; done: if(key != NULL) { xmlSecKeyDestroy(key); } xmlSecKeyInfoCtxFinalize(&keyInfoCtx); return(res); } int xmlSecTransformWriteKeyInfoNode(xmlSecKeyPtr key, xmlNodePtr node, xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) { xmlSecKeyInfoCtx keyInfoCtx; int ret; int res = -1; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(transform != NULL, -1); xmlSecAssert2(transformCtx != NULL, -1); xmlSecAssert2(transformCtx->parentKeyInfoCtx != NULL, -1); /* create keyinfo ctx */ ret = xmlSecKeyInfoCtxInitialize(&keyInfoCtx, NULL); if(ret < 0) { xmlSecInternalError("xmlSecKeyInfoCtxInitialize(recipient)", xmlSecNodeGetName(node)); return(-1); } ret = xmlSecKeyInfoCtxCopyUserPref(&keyInfoCtx, transformCtx->parentKeyInfoCtx); if(ret < 0) { xmlSecInternalError("xmlSecKeyInfoCtxCopyUserPref(recipient)", xmlSecNodeGetName(node)); goto done; } keyInfoCtx.mode = xmlSecKeyInfoModeWrite; keyInfoCtx.keyReq.keyType = xmlSecKeyDataTypePublic; /* write public keys only */ /* write node */ ret = xmlSecKeyInfoNodeWrite(node, key, &(keyInfoCtx)); if(ret < 0) { xmlSecInternalError("xmlSecKeyInfoNodeWrite", NULL); goto done; } /* success */ res = 0; done: xmlSecKeyInfoCtxFinalize(&keyInfoCtx); return(res); } /****************************************************************************** * * Key Agreement Method (KAM) Transform * https://www.w3.org/TR/xmlenc-core1/#sec-AgreementMethod: * * @code{.xml} * <element name="AgreementMethod" type="xenc:AgreementMethodType"/> * <complexType name="AgreementMethodType" mixed="true"> * <sequence> * <element name="KA-Nonce" minOccurs="0" type="base64Binary"/> * <!-- <element ref="ds:DigestMethod" minOccurs="0"/> --> * <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/> * <element name="OriginatorKeyInfo" minOccurs="0" type="ds:KeyInfoType"/> * <element name="RecipientKeyInfo" minOccurs="0" type="ds:KeyInfoType"/> * </sequence> * <attribute name="Algorithm" type="anyURI" use="required"/> * </complexType> * @endcode * *****************************************************************************/ int xmlSecTransformKAMInitialize(xmlSecTransformKAMPtr params) { int ret; xmlSecAssert2(params != NULL, -1); memset(params, 0, sizeof(*params)); ret = xmlSecKeyInfoCtxInitialize(&(params->kdfKeyInfoCtx), NULL); /* no keys manager needed */ if(ret < 0) { xmlSecInternalError("xmlSecKeyInfoCtxInitialize", NULL); xmlSecTransformKAMFinalize(params); return(-1); } /* done */ return(0); } void xmlSecTransformKAMFinalize(xmlSecTransformKAMPtr params) { xmlSecAssert(params != NULL); xmlSecKeyInfoCtxFinalize(&(params->kdfKeyInfoCtx)); if(params->kdfTransform != NULL) { xmlSecTransformDestroy(params->kdfTransform); } if(params->memBufTransform != NULL) { xmlSecTransformDestroy(params->memBufTransform); } /* cleanup */ memset(params, 0, sizeof(*params)); } int xmlSecTransformKAMRead(xmlSecTransformKAMPtr params, xmlNodePtr node, xmlSecTransformPtr kamTransform, xmlSecTransformCtxPtr transformCtx) { xmlSecKeyDataPtr kamKeyData; xmlSecKeyDataKAM* kamData; xmlSecKeyDataType originatorKeyType, recipientKeyType; xmlNodePtr cur; int ret; xmlSecAssert2(params != NULL, -1); xmlSecAssert2(params->kdfTransform == NULL, -1); xmlSecAssert2(params->memBufTransform == NULL, -1); xmlSecAssert2(transformCtx != NULL, -1); xmlSecAssert2(transformCtx->parentKeyInfoCtx != NULL, -1); xmlSecAssert2(kamTransform != NULL, -1); xmlSecAssert2(node != NULL, -1); if(transformCtx->parentKeyInfoCtx->operation == xmlSecTransformOperationEncrypt) { /* we are encrypting on originator side which needs private key */ originatorKeyType = xmlSecKeyDataTypePrivate; recipientKeyType = xmlSecKeyDataTypePublic; } else { /* we are decrypting on recipient side which needs private key */ originatorKeyType = xmlSecKeyDataTypePublic; recipientKeyType = xmlSecKeyDataTypePrivate; } /* get or create kamKeyData in transformCtx and set originator/recipient keys */ kamKeyData = xmlSecTransformCtxExtraKeyDataEnsure(transformCtx, xmlSecKeyDataKAMId); if(kamKeyData == NULL) { xmlSecInternalError("xmlSecTransformCtxExtraKeyDataEnsure(kamKeyData)", xmlSecNodeGetName(node)); return(-1); } xmlSecAssert2(xmlSecKeyDataCheckId(kamKeyData, xmlSecKeyDataKAMId), -1); kamData = (xmlSecKeyDataKAM*)kamKeyData; /* start with the first child element of the node */ cur = xmlSecGetNextElementNode(node->children); /* first is required KeyDerivationMethod */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeKeyDerivationMethod, xmlSecEnc11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodeKeyDerivationMethod, NULL); return(-1); } params->kdfTransform = xmlSecTransformNodeRead(cur, xmlSecTransformUsageKeyDerivationMethod, transformCtx); if(params->kdfTransform == NULL) { xmlSecInternalError("xmlSecTransformNodeRead", xmlSecNodeGetName(node)); return(-1); } ret = xmlSecTransformSetKeyReq(params->kdfTransform, &(params->kdfKeyInfoCtx.keyReq)); if(ret < 0) { xmlSecInternalError("xmlSecTransformSetKeyReq", xmlSecNodeGetName(node)); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* next node is required OriginatorKeyInfo (we need public key) */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeOriginatorKeyInfo, xmlSecEncNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeOriginatorKeyInfo, NULL); return(-1); } /* only lookup key if not already present in kamData */ if(kamData->keyOriginator == NULL) { kamData->keyOriginator = xmlSecTransformReadKeyInfoNode(originatorKeyType, cur, kamTransform, transformCtx); if(kamData->keyOriginator == NULL) { xmlSecInternalError("xmlSecTransformReadKeyInfoNode(OriginatorKeyInfo)", xmlSecNodeGetName(node)); return(-1); } } cur = xmlSecGetNextElementNode(cur->next); /* next node is required RecipientKeyInfo (we need private key) */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRecipientKeyInfo, xmlSecEncNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeRecipientKeyInfo, NULL); return(-1); } /* only lookup key if not already present in kamData */ if(kamData->keyRecipient == NULL) { kamData->keyRecipient = xmlSecTransformReadKeyInfoNode(recipientKeyType, cur, kamTransform, transformCtx); if(kamData->keyRecipient == NULL) { xmlSecInternalError("xmlSecTransformReadKeyInfoNode(RecipientKeyInfo)", xmlSecNodeGetName(node)); return(-1); } } cur = xmlSecGetNextElementNode(cur->next); /* if there is something left than it's an error */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* append MemBuf transform after kdf transform to collect results */ params->memBufTransform = xmlSecTransformCreate(xmlSecTransformMemBufId); if(!xmlSecTransformIsValid(params->memBufTransform )) { xmlSecInternalError("xmlSecTransformCreate(MemBufId)", xmlSecNodeGetName(node)); return(-1); } params->kdfTransform->next = params->memBufTransform; params->memBufTransform->prev = params->kdfTransform; /* success */ return(0); } int xmlSecTransformKAMWrite(xmlSecTransformKAMPtr params, xmlNodePtr node, xmlSecTransformPtr kamTransform, xmlSecTransformCtxPtr transformCtx) { xmlSecKeyDataKAM* kamData; xmlNodePtr cur; int ret; int res = -1; xmlSecAssert2(params != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(kamTransform != NULL, -1); xmlSecAssert2(transformCtx != NULL, -1); xmlSecAssert2(transformCtx->parentKeyInfoCtx != NULL, -1); { xmlSecKeyDataPtr kamKeyData = xmlSecTransformCtxExtraKeyDataGet(transformCtx, xmlSecKeyDataKAMId); xmlSecAssert2(kamKeyData != NULL, -1); xmlSecAssert2(xmlSecKeyDataCheckId(kamKeyData, xmlSecKeyDataKAMId), -1); kamData = (xmlSecKeyDataKAM*)kamKeyData; } /* start with the first child element of the node */ cur = xmlSecGetNextElementNode(node->children); /* first is required KeyDerivationMethod */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeKeyDerivationMethod, xmlSecEnc11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodeKeyDerivationMethod, NULL); goto done; } /* do nothing for KeyDerivationMethod for now */ cur = xmlSecGetNextElementNode(cur->next); /* next node is required OriginatorKeyInfo */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeOriginatorKeyInfo, xmlSecEncNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeOriginatorKeyInfo, NULL); goto done; } if(kamData->keyOriginator != NULL) { ret = xmlSecTransformWriteKeyInfoNode(kamData->keyOriginator, cur, kamTransform, transformCtx); if(ret < 0) { xmlSecInternalError("xmlSecTransformWriteKeyInfoNode(OriginatorKeyInfo)", xmlSecNodeGetName(node)); goto done; } } cur = xmlSecGetNextElementNode(cur->next); /* next node is required RecipientKeyInfo */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRecipientKeyInfo, xmlSecEncNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeRecipientKeyInfo, NULL); goto done; } if(kamData->keyRecipient != NULL) { ret = xmlSecTransformWriteKeyInfoNode(kamData->keyRecipient, cur, kamTransform, transformCtx); if(ret < 0) { xmlSecInternalError("xmlSecTransformWriteKeyInfoNode(RecipientKeyInfo)", xmlSecNodeGetName(node)); goto done; } } cur = xmlSecGetNextElementNode(cur->next); /* if there is something left than it's an error */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); goto done; } /* success */ res = 0; done: return(res); } static xmlSecKeyPtr xmlSecTransformKAMCreateKdfKey(xmlSecTransformKAMPtr params, xmlSecBufferPtr secret) { xmlSecKeyPtr key = NULL; xmlSecKeyDataId keyId; xmlSecByte * secretData; xmlSecSize secretSize; int ret; xmlSecAssert2(params != NULL, NULL); xmlSecAssert2(secret != NULL, NULL); secretData = xmlSecBufferGetData(secret); secretSize = xmlSecBufferGetSize(secret); xmlSecAssert2(secretData != NULL, NULL); xmlSecAssert2(secretSize > 0, NULL); /* get keyId from kdfTransform's keyReq */ keyId = params->kdfKeyInfoCtx.keyReq.keyId; key = xmlSecKeyCreate(); if(key == NULL) { xmlSecInternalError("xmlSecKeyCreate", xmlSecKeyDataKlassGetName(keyId)); return(NULL); } ret = xmlSecKeyDataBinRead(keyId, key, secretData, secretSize, &(params->kdfKeyInfoCtx)); if(ret < 0) { xmlSecInternalError("xmlSecKeyDataBinRead", xmlSecKeyDataKlassGetName(keyId)); xmlSecKeyDestroy(key); return(NULL); } /* done */ return(key); } int xmlSecTransformKAMExecuteKdf(xmlSecTransformKAMPtr params, xmlSecTransformOperation operation, xmlSecBufferPtr secret, xmlSecBufferPtr out, xmlSecSize expectedOutputSize, xmlSecTransformCtxPtr transformCtx) { xmlSecKeyPtr secretKey = NULL; xmlSecBufferPtr memBuf; int ret; int res = -1; xmlSecAssert2(params != NULL, -1); xmlSecAssert2(params->kdfTransform != NULL, -1); xmlSecAssert2(params->memBufTransform != NULL, -1); xmlSecAssert2(secret != NULL, -1); xmlSecAssert2(out != NULL, -1); params->kdfTransform->operation = operation; params->kdfTransform->expectedOutputSize = expectedOutputSize; secretKey = xmlSecTransformKAMCreateKdfKey(params, secret); if(secretKey == NULL) { xmlSecInternalError("xmlSecTransformKAMCreateKdfKey", NULL); goto done; } ret = xmlSecTransformSetKey(params->kdfTransform, secretKey); if(ret < 0) { xmlSecInternalError("xmlSecTransformSetKey", NULL); goto done; } ret = xmlSecTransformPushBin(params->kdfTransform, NULL, 0, 1, transformCtx); if(ret < 0) { xmlSecInternalError("xmlSecTransformPushBin", NULL); goto done; } memBuf = xmlSecTransformMemBufGetBuffer(params->memBufTransform); if(memBuf == NULL) { xmlSecInternalError("xmlSecTransformMemBufGetBuffer", NULL); goto done; } xmlSecBufferSwap(out, memBuf); res = 0; done: if(secretKey != NULL) { xmlSecKeyDestroy(secretKey); } return(res); } /****************************************************************************** * * Key Encapsulation Method (KEM) Transform * * Note that CipherReference node is not currently supported * * @code{.xml} * <as:EncapsulationMechanism xmlns:as="XMLSEC_ALKESEY_EXPERIMENTAL_2025_12"Algorithm="some uri"> * <ds:KeyInfo/> * <enc:CipherData> * <enc:CipherValue/> * </enc:CipherData> * </as:EncapsulationMechanism> * @endcode * *****************************************************************************/ #ifndef XMLSEC_NO_MLKEM int xmlSecTransformKEMRead(xmlNodePtr node, xmlSecTransformPtr kemTransform, xmlSecTransformCtxPtr transformCtx) { xmlSecKeyDataPtr kemKeyData; xmlSecKeyDataKEM* kemData; xmlNodePtr cur; xmlSecKeyDataType keyType; int ret; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(kemTransform != NULL, -1); xmlSecAssert2(transformCtx != NULL, -1); xmlSecAssert2(transformCtx->parentKeyInfoCtx != NULL, -1); /* get or create kemKeyData in transformCtx */ kemKeyData = xmlSecTransformCtxExtraKeyDataEnsure(transformCtx, xmlSecKeyDataKEMId); if(kemKeyData == NULL) { xmlSecInternalError("xmlSecTransformCtxExtraKeyDataEnsure(kemKeyData)", xmlSecNodeGetName(node)); return(-1); } xmlSecAssert2(xmlSecKeyDataCheckId(kemKeyData, xmlSecKeyDataKEMId), -1); kemData = (xmlSecKeyDataKEM*)kemKeyData; /* on decrypt the recipient uses their private key to decapsulate */ switch(transformCtx->parentKeyInfoCtx->operation) { case xmlSecTransformOperationSign: case xmlSecTransformOperationEncrypt: keyType = xmlSecKeyDataTypePublic; break; case xmlSecTransformOperationVerify: case xmlSecTransformOperationDecrypt: keyType = xmlSecKeyDataTypePrivate; break; default: xmlSecInternalError2("invalid operation", NULL, "operation=%u", transformCtx->parentKeyInfoCtx->operation); return(-1); } /* start with the first child element of the node */ cur = xmlSecGetNextElementNode(node->children); /* first is required ds:KeyInfo containing the encapsulation key */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeKeyInfo, NULL); return(-1); } /* only lookup key if not already present in kemData */ if(kemData->encapsulationKey == NULL) { kemData->encapsulationKey = xmlSecTransformReadKeyInfoNode(keyType, cur, kemTransform, transformCtx); if(kemData->encapsulationKey == NULL) { xmlSecInternalError("xmlSecTransformReadKeyInfoNode(KeyInfo)", xmlSecNodeGetName(node)); return(-1); } } cur = xmlSecGetNextElementNode(cur->next); /* next is required enc:CipherData containing the KEM ciphertext (might be empty during encryption) */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeCipherData, xmlSecEncNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeCipherData, NULL); return(-1); } /* only read it if we don't have it already */ if(xmlSecBufferIsEmpty(&(kemData->ciphertext))) { xmlNodePtr cipherValueNode; /* find CipherValue inside CipherData */ cipherValueNode = xmlSecGetNextElementNode(cur->children); if((cipherValueNode == NULL) || (!xmlSecCheckNodeName(cipherValueNode, xmlSecNodeCipherValue, xmlSecEncNs))) { xmlSecInvalidNodeError(cipherValueNode, xmlSecNodeCipherValue, xmlSecNodeGetName(node)); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(kemData->ciphertext), cipherValueNode); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(CipherValue)", xmlSecNodeGetName(node)); return(-1); } } cur = xmlSecGetNextElementNode(cur->next); /* if there is something left then it's an error */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* done */ return(0); } int xmlSecTransformKEMWrite(xmlNodePtr node, xmlSecTransformPtr kemTransform, xmlSecTransformCtxPtr transformCtx) { xmlSecKeyDataKEM* kemData; xmlNodePtr cur; int ret; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(kemTransform != NULL, -1); xmlSecAssert2(transformCtx != NULL, -1); xmlSecAssert2(transformCtx->parentKeyInfoCtx != NULL, -1); { xmlSecKeyDataPtr kemKeyData = xmlSecTransformCtxExtraKeyDataGet(transformCtx, xmlSecKeyDataKEMId); xmlSecAssert2(kemKeyData != NULL, -1); xmlSecAssert2(xmlSecKeyDataCheckId(kemKeyData, xmlSecKeyDataKEMId), -1); kemData = (xmlSecKeyDataKEM*)kemKeyData; } /* start with the first child element of the node */ cur = xmlSecGetNextElementNode(node->children); /* first is required ds:KeyInfo: write recipient's public key */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeKeyInfo, NULL); return(-1); } if(kemData->encapsulationKey != NULL) { ret = xmlSecTransformWriteKeyInfoNode(kemData->encapsulationKey, cur, kemTransform, transformCtx); if(ret < 0) { xmlSecInternalError("xmlSecTransformWriteKeyInfoNode(KeyInfo)", xmlSecNodeGetName(node)); return(-1); } } cur = xmlSecGetNextElementNode(cur->next); /* next is required enc:CipherData containing the KEM ciphertext (might be empty during encryption) */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeCipherData, xmlSecEncNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeCipherData, NULL); return(-1); } /* only write if not empty */ if(!xmlSecBufferIsEmpty(&(kemData->ciphertext))) { xmlNodePtr cipherValueNode; cipherValueNode = xmlSecGetNextElementNode(cur->children); if((cipherValueNode == NULL) || (!xmlSecCheckNodeName(cipherValueNode, xmlSecNodeCipherValue, xmlSecEncNs))) { xmlSecInvalidNodeError(cipherValueNode, xmlSecNodeCipherValue, xmlSecNodeGetName(node)); return(-1); } ret = xmlSecBufferBase64NodeContentWrite(&(kemData->ciphertext), cipherValueNode, xmlSecBase64GetDefaultLineSize()); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(CipherValue)", xmlSecNodeGetName(node)); return(-1); } } cur = xmlSecGetNextElementNode(cur->next); /* if there is something left then it's an error */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* done */ return(0); } #endif /* !defined(XMLSEC_NO_MLKEM) */ #ifndef XMLSEC_NO_HMAC /* min output for hmac transform in bits */ static xmlSecSize g_xmlsec_transform_hmac_min_output_bits_size = 80; /** * @brief Gets the minimum size in bits for HMAC output. * * @return the min HMAC output size in bits. */ xmlSecSize xmlSecTransformHmacGetMinOutputBitsSize(void) { return(g_xmlsec_transform_hmac_min_output_bits_size); } /** * @brief Sets the min HMAC output size in bits. * @details Sets the min HMAC output size in bits. Low value for min output size * might create a security vulnerability and is not recommended. * @param val the new min hmac output size in bits. */ void xmlSecTransformHmacSetMinOutputBitsSize(xmlSecSize val) { g_xmlsec_transform_hmac_min_output_bits_size = val; } /* * HMAC (http://www.w3.org/TR/xmldsig-core/#sec-HMAC): * * The HMAC algorithm (RFC2104 [HMAC]) takes the truncation length in bits * as a parameter; if the parameter is not specified then all the bits of the * hash are output. An example of an HMAC SignatureMethod element: * <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"> * <HMACOutputLength>128</HMACOutputLength> * </SignatureMethod> * * Schema Definition: * * <simpleType name="HMACOutputLengthType"> * <restriction base="integer"/> * </simpleType> * * DTD: * * <!ELEMENT HMACOutputLength (#PCDATA)> */ int xmlSecTransformHmacReadOutputBitsSize(xmlNodePtr node, xmlSecSize defaultSize, xmlSecSize* res) { xmlNodePtr cur; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(res != NULL, -1); cur = xmlSecGetNextElementNode(node->children); if ((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHMACOutputLength, xmlSecDSigNs)) { xmlSecSize minSize; int ret; ret = xmlSecGetNodeContentAsSize(cur, defaultSize, res); if (ret != 0) { xmlSecInternalError("xmlSecGetNodeContentAsSize(HMACOutputLength)", NULL); return(-1); } /* Ensure that HMAC length is greater than min specified. Otherwise, an attacker can set this length to 0 or very small value */ minSize = xmlSecTransformHmacGetMinOutputBitsSize(); if ((*res) < minSize) { xmlSecInvalidNodeContentError3(cur, NULL, "HMAC output length=" XMLSEC_SIZE_FMT "; HMAC min output length=" XMLSEC_SIZE_FMT, (*res), minSize); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* no other nodes expected */ if (cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } return(0); } static xmlSecByte g_hmac_last_byte_masks[] = { 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; int xmlSecTransformHmacWriteOutput(const xmlSecByte * hmac, xmlSecSize hmacSizeInBits, xmlSecSize hmacMaxSizeInBytes, xmlSecBufferPtr out) { xmlSecSize hmacSize; xmlSecByte lastByteMask; xmlSecByte* outData; int ret; xmlSecAssert2(hmac != NULL, -1); xmlSecAssert2(hmacSizeInBits > 0, -1); xmlSecAssert2(out != NULL, -1); hmacSize = (hmacSizeInBits + 7) / 8; xmlSecAssert2(hmacSize > 0, -1); xmlSecAssert2(hmacSize <= hmacMaxSizeInBytes, -1); ret = xmlSecBufferAppend(out, hmac, hmacSize); if(ret < 0) { xmlSecInternalError2("xmlSecBufferAppend", NULL, "size=" XMLSEC_SIZE_FMT, hmacSize); return(-1); } /* fix up last byte */ lastByteMask = g_hmac_last_byte_masks[hmacSizeInBits % 8]; outData = xmlSecBufferGetData(out); if(outData == NULL) { xmlSecInternalError("xmlSecBufferGetData", NULL); return(-1); } outData[hmacSize - 1] &= lastByteMask; /* success */ return(0); } /* Returns 1 for match, 0 for no match, <0 for errors. */ int xmlSecTransformHmacVerify(const xmlSecByte* data, xmlSecSize dataSize, const xmlSecByte * hmac, xmlSecSize hmacSizeInBits, xmlSecSize hmacMaxSizeInBytes) { xmlSecSize hmacSize; xmlSecByte lastByteMask; xmlSecByte lastByteDiff; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(dataSize > 0, -1); xmlSecAssert2(hmac != NULL, -1); xmlSecAssert2(hmacSizeInBits > 0, -1); hmacSize = (hmacSizeInBits + 7) / 8; xmlSecAssert2(hmacSize > 0, -1); xmlSecAssert2(hmacSize <= hmacMaxSizeInBytes, -1); if(dataSize != hmacSize){ xmlSecInvalidSizeError("HMAC digest", dataSize, hmacSize, NULL); return(0); } /* compare in constant time so the number of matching leading bytes is not * leaked through timing; the last byte is masked for truncated HMAC output */ lastByteMask = g_hmac_last_byte_masks[hmacSizeInBits % 8]; lastByteDiff = (xmlSecByte)((hmac[hmacSize - 1] & lastByteMask) ^ (data[dataSize - 1] & lastByteMask)); ret = xmlSecMemEqual(hmac, data, hmacSize - 1); if(ret < 0) { xmlSecInternalError("xmlSecMemEqual", NULL); return(-1); } if((ret == 0) || (lastByteDiff != 0)) { xmlSecOtherError(XMLSEC_ERRORS_R_DATA_NOT_MATCH, NULL, "data and digest do not match"); return(0); } /* success */ return(1); } #endif /* XMLSEC_NO_HMAC */ /* ML-DSA */ #ifndef XMLSEC_NO_MLDSA /* * THIS IS EXPERIMENTAL AND NON-STANDARD * * <SignatureMethod Algorithm="XMLSEC_ALKESEY_EXPERIMENTAL_2025_12#ml-dsa-44"> * <mldsa:MLDSAContextString>base64 encoded context string</mldsa:MLDSAContextString> * </SignatureMethod> */ int xmlSecTransformMLDSAReadContextString(xmlNodePtr node, xmlSecBufferPtr res) { xmlNodePtr cur; int ret; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(res != NULL, -1); cur = xmlSecGetNextElementNode(node->children); if ((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeMLDSAContextString, xmlSecMLDSANs)) { ret = xmlSecBufferBase64NodeContentRead(res, cur); if (ret != 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(MLDSAContextString)", NULL); return(-1); } /* ensure length is not exceeded */ if (xmlSecBufferGetSize(res) > XMLSEC_MLDSA_MAX_SIZE) { xmlSecInvalidNodeContentError3(cur, NULL, "MLDSA context string length=" XMLSEC_SIZE_FMT " exceeds max expected length =" XMLSEC_SIZE_FMT, xmlSecBufferGetSize(res), XMLSEC_MLDSA_MAX_SIZE); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* no other nodes expected */ if (cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } return(0); } #endif /* XMLSEC_NO_MLDSA */ /* SLH-DSA */ #ifndef XMLSEC_NO_SLHDSA /* * THIS IS EXPERIMENTAL AND NON-STANDARD * * <SignatureMethod Algorithm="XMLSEC_ALKESEY_EXPERIMENTAL_2025_12#slh-dsa-44"> * <slhdsa:SLHDSAContextString>base64 encoded context string</slhdsa:SLHDSAContextString> * </SignatureMethod> */ int xmlSecTransformSLHDSAReadContextString(xmlNodePtr node, xmlSecBufferPtr res) { xmlNodePtr cur; int ret; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(res != NULL, -1); cur = xmlSecGetNextElementNode(node->children); if ((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeSLHDSAContextString, xmlSecSLHDSANs)) { ret = xmlSecBufferBase64NodeContentRead(res, cur); if (ret != 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(SLHDSAContextString)", NULL); return(-1); } /* ensure length is not exceeded */ if (xmlSecBufferGetSize(res) > XMLSEC_SLHDSA_MAX_SIZE) { xmlSecInvalidNodeContentError3(cur, NULL, "SLHDSA context string length=" XMLSEC_SIZE_FMT " exceeds max expected length =" XMLSEC_SIZE_FMT, xmlSecBufferGetSize(res), XMLSEC_SLHDSA_MAX_SIZE); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* no other nodes expected */ if (cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } return(0); } #endif /* XMLSEC_NO_SLHDSA */ /* EdDSA */ #ifndef XMLSEC_NO_EDDSA /* * THIS IS EXPERIMENTAL AND NON-STANDARD * * <SignatureMethod Algorithm="http://www.w3.org/2021/04/xmldsig-more#eddsa-ed25519ctx"> * <eddsa:EdDSAContextString>base64 encoded context string</eddsa:EdDSAContextString> * </SignatureMethod> */ int xmlSecTransformEdDSAReadContextString(xmlNodePtr node, xmlSecBufferPtr res) { xmlNodePtr cur; int ret; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(res != NULL, -1); cur = xmlSecGetNextElementNode(node->children); if ((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeEdDSAContextString, xmlSecEdDSANs)) { ret = xmlSecBufferBase64NodeContentRead(res, cur); if (ret != 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(EdDSAContextString)", NULL); return(-1); } /* ensure length is not exceeded */ if (xmlSecBufferGetSize(res) > XMLSEC_EDDSA_MAX_SIZE) { xmlSecInvalidNodeContentError3(cur, NULL, "EdDSA context string length=" XMLSEC_SIZE_FMT " exceeds max expected length =" XMLSEC_SIZE_FMT, xmlSecBufferGetSize(res), XMLSEC_EDDSA_MAX_SIZE); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* no other nodes expected */ if (cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } return(0); } #endif /* XMLSEC_NO_EDDSA */ /* PBKDF2 */ #ifndef XMLSEC_NO_PBKDF2 #define XMLSEC_TRANSFORM_PBKDF2_DEFAULT_BUF_SIZE 64 int xmlSecTransformPbkdf2ParamsInitialize(xmlSecTransformPbkdf2ParamsPtr params) { int ret; xmlSecAssert2(params != NULL, -1); memset(params, 0, sizeof(*params)); ret = xmlSecBufferInitialize(&(params->salt), XMLSEC_TRANSFORM_PBKDF2_DEFAULT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(bufAlgorithmID)", NULL); xmlSecTransformPbkdf2ParamsFinalize(params); return(-1); } /* done */ return(0); } void xmlSecTransformPbkdf2ParamsFinalize(xmlSecTransformPbkdf2ParamsPtr params) { xmlSecAssert(params != NULL); if(params->prfAlgorithmHref != NULL) { xmlFree(params->prfAlgorithmHref); } xmlSecBufferFinalize(&(params->salt)); memset(params, 0, sizeof(*params)); } /* * https://www.w3.org/TR/xmlenc-core1/#sec-PBKDF2 * * <element name="PBKDF2-params" type="xenc11:PBKDF2ParameterType"/> * <complexType name="PBKDF2ParameterType"> * <sequence> * <element name="Salt"> * <complexType> * <choice> * <element name="Specified" type="base64Binary"/> * <element name="OtherSource" type="xenc11:AlgorithmIdentifierType"/> * </choice> * </complexType> * </element> * <element name="IterationCount" type="positiveInteger"/> * <element name="KeyLength" type="positiveInteger"/> * <element name="PRF" type="xenc11:PRFAlgorithmIdentifierType"/> * </sequence> * </complexType> * * <complexType name="AlgorithmIdentifierType"> * <sequence> * <element name="Parameters" type="anyType" minOccurs="0"/> * </sequence> * <attribute name="Algorithm" type="anyURI"/> * </complexType> * * <complexType name="PRFAlgorithmIdentifierType"> * <complexContent> * <restriction base="xenc11:AlgorithmIdentifierType"> * <attribute name="Algorithm" type="anyURI"/> * </restriction> * </complexContent> * </complexType> * * - Salt / OtherSource is not supported * - PRF algorithm parameters are not supported */ static int xmlSecTransformPbkdf2ParamsReadSalt(xmlSecTransformPbkdf2ParamsPtr params, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(params != NULL, -1); xmlSecAssert2(node != NULL, -1); /* first and onluy node is required Salt / Specified (Salt / OtherSource is not supported)*/ cur = xmlSecGetNextElementNode(node->children); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodePbkdf2SaltSpecified, xmlSecEnc11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodePbkdf2SaltSpecified, NULL); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(params->salt), cur); if((ret < 0) || (xmlSecBufferGetSize(&(params->salt)) <= 0)) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(Salt)", NULL); return(-1); } /* if we have something else then it's an error */ cur = xmlSecGetNextElementNode(cur->next); if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* done! */ return(0); } int xmlSecTransformPbkdf2ParamsRead(xmlSecTransformPbkdf2ParamsPtr params, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(params != NULL, -1); xmlSecAssert2(params->prfAlgorithmHref == NULL, -1); xmlSecAssert2(node != NULL, -1); /* first node is required Salt */ cur = xmlSecGetNextElementNode(node->children); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodePbkdf2Salt, xmlSecEnc11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodePbkdf2Salt, NULL); return(-1); } ret = xmlSecTransformPbkdf2ParamsReadSalt(params, cur); if(ret < 0) { xmlSecInternalError("xmlSecTransformPbkdf2ParamsReadSalt", NULL); return(-1); } /* next is required IterationCount */ cur = xmlSecGetNextElementNode(cur->next); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodePbkdf2IterationCount, xmlSecEnc11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodePbkdf2IterationCount, NULL); return(-1); } ret = xmlSecGetNodeContentAsSize(cur, 0, &(params->iterationCount)); if((ret < 0) || (params->iterationCount <= 0)) { xmlSecInternalError("xmlSecGetNodeContentAsSize(iterationCount)", NULL); return(-1); } /* next is required KeyLength */ cur = xmlSecGetNextElementNode(cur->next); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodePbkdf2KeyLength, xmlSecEnc11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodePbkdf2KeyLength, NULL); return(-1); } ret = xmlSecGetNodeContentAsSize(cur, 0, &(params->keyLength)); if((ret < 0) || (params->keyLength <= 0)) { xmlSecInternalError("xmlSecGetNodeContentAsSize(keyLength)", NULL); return(-1); } /* next is required PRF */ cur = xmlSecGetNextElementNode(cur->next); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodePbkdf2PRF, xmlSecEnc11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodePbkdf2PRF, NULL); return(-1); } params->prfAlgorithmHref = xmlGetProp(cur, xmlSecAttrAlgorithm); if(params->prfAlgorithmHref == NULL) { xmlSecInvalidNodeAttributeError(cur, xmlSecAttrAlgorithm, NULL, "empty"); return(-1); } /* PRF algorithm parameters are not supported */ /* if we have something else then it's an error */ cur = xmlSecGetNextElementNode(cur->next); if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* done! */ return(0); } #endif /* XMLSEC_NO_CONCATKDF */ #ifndef XMLSEC_NO_HKDF /****************************************************************************** * * HKDF params * *****************************************************************************/ int xmlSecTransformHkdfParamsInitialize(xmlSecTransformHkdfParamsPtr params) { int ret; xmlSecAssert2(params != NULL, -1); memset(params, 0, sizeof(xmlSecTransformHkdfParams)); ret = xmlSecBufferInitialize(&(params->salt), 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(salt)", NULL); return(-1); } ret = xmlSecBufferInitialize(&(params->info), 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(info)", NULL); xmlSecBufferFinalize(&(params->salt)); return(-1); } return(0); } void xmlSecTransformHkdfParamsFinalize(xmlSecTransformHkdfParamsPtr params) { xmlSecAssert(params != NULL); if(params->prfAlgorithmHref != NULL) { xmlFree(params->prfAlgorithmHref); } xmlSecBufferFinalize(&(params->salt)); xmlSecBufferFinalize(&(params->info)); memset(params, 0, sizeof(xmlSecTransformHkdfParams)); } int xmlSecTransformHkdfParamsRead(xmlSecTransformHkdfParamsPtr params, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(params != NULL, -1); xmlSecAssert2(node != NULL, -1); /* iterate over child nodes */ cur = xmlSecGetNextElementNode(node->children); /* required: PRF */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeHkdfPRF, xmlSecXmldsig2021MoreNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeHkdfPRF, NULL); return(-1); } params->prfAlgorithmHref = xmlGetProp(cur, xmlSecAttrAlgorithm); if(params->prfAlgorithmHref == NULL) { xmlSecInvalidNodeAttributeError(cur, xmlSecAttrAlgorithm, NULL, "empty"); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* optional: Salt */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeHkdfSalt, xmlSecXmldsig2021MoreNs))) { ret = xmlSecBufferBase64NodeContentRead(&(params->salt), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(salt)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* optional: Info */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeHkdfInfo, xmlSecXmldsig2021MoreNs))) { ret = xmlSecBufferBase64NodeContentRead(&(params->info), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(info)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* optional: KeyLength */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeHkdfKeyLength, xmlSecXmldsig2021MoreNs))) { ret = xmlSecGetNodeContentAsSize(cur, 1, &(params->keyLength)); if(ret < 0) { xmlSecInternalError("xmlSecGetNodeContentAsSize(KeyLength)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* no more nodes allowed */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } return(0); } #endif /* XMLSEC_NO_HKDF */ /* ChaCha20 */ #ifndef XMLSEC_NO_CHACHA20 /* * https://www.w3.org/TR/draft-eastlake-rfc9231bis-xmlsec-uris-06/#sec-ChaCha20 * * <xenc:EncryptionMethod Algorithm="...#chacha20"> * <dsig-more:Nonce>0123456789abcdef01234567</dsig-more:Nonce> * <dsig-more:Counter>fedcba09</dsig-more:Counter> * </xenc:EncryptionMethod> */ /* IV: 16 bytes: 4 byte counter + 12 byte nonce */ int xmlSecTransformChaCha20ParamsRead(xmlNodePtr node, xmlSecByte *iv, xmlSecSize ivSize, xmlSecSize *ivSizeOut, int *noncePresent) { xmlSecBuffer buf; xmlSecByte* bufData; xmlSecSize bufSize; xmlNodePtr cur; int ret; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(iv != NULL, -1); xmlSecAssert2(ivSize >= XMLSEC_CHACHA20_IV_SIZE, -1); xmlSecAssert2(ivSizeOut != NULL, -1); xmlSecAssert2(noncePresent != NULL, -1); /* prep output params */ memset(iv, 0, XMLSEC_CHACHA20_IV_SIZE); (*ivSizeOut) = 0; (*noncePresent) = 0; ret = xmlSecBufferInitialize(&buf, XMLSEC_CHACHA20_IV_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecGetNodeContentAsHex(Nonce)", NULL); return(-1); } /* first optional Nonce node (12 bytes, hex-encoded) */ cur = xmlSecGetNextElementNode(node->children); if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs))) { ret = xmlSecGetNodeContentAsHex(cur, &buf); if(ret < 0) { xmlSecInternalError("xmlSecGetNodeContentAsHex(Nonce)", NULL); xmlSecBufferFinalize(&buf); return(-1); } bufData = xmlSecBufferGetData(&buf); bufSize = xmlSecBufferGetSize(&buf); if((bufData == NULL) || (bufSize != XMLSEC_CHACHA20_NONCE_SIZE)) { xmlSecInvalidSizeDataError("Nonce", bufSize, "12 bytes", NULL); xmlSecBufferFinalize(&buf); return(-1); } memcpy(iv + XMLSEC_CHACHA20_COUNTER_SIZE, bufData, bufSize); xmlSecBufferEmpty(&buf); (*noncePresent) = 1; cur = xmlSecGetNextElementNode(cur->next); } /* second is required Counter node (4 bytes, hex-encoded) */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Counter, xmlSecXmldsig2021MoreNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeChaCha20Counter, NULL); xmlSecBufferFinalize(&buf); return(-1); } ret = xmlSecGetNodeContentAsHex(cur, &buf); if(ret < 0) { xmlSecInternalError("xmlSecGetNodeContentAsHex(Counter)", NULL); xmlSecBufferFinalize(&buf); return(-1); } bufData = xmlSecBufferGetData(&buf); bufSize = xmlSecBufferGetSize(&buf); if((bufData == NULL) || (bufSize != XMLSEC_CHACHA20_COUNTER_SIZE)) { xmlSecInvalidSizeDataError("Counter", bufSize, "4 bytes", NULL); xmlSecBufferFinalize(&buf); return(-1); } memcpy(iv, bufData, bufSize); xmlSecBufferEmpty(&buf); cur = xmlSecGetNextElementNode(cur->next); /* nothing else is expected */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); xmlSecBufferFinalize(&buf); return(-1); } /* done */ (*ivSizeOut) = XMLSEC_CHACHA20_IV_SIZE; xmlSecBufferFinalize(&buf); return(0); } int xmlSecTransformChaCha20ParamsWrite(xmlNodePtr node, const xmlSecByte *iv, xmlSecSize ivSize) { xmlNodePtr cur; int ret; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(iv != NULL, -1); xmlSecAssert2(ivSize >= XMLSEC_CHACHA20_IV_SIZE, -1); /* add nonce node if needed */ cur = xmlSecGetNextElementNode(node->children); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs))) { xmlNodePtr nonceNode; /* add nonce node */ if (cur != NULL) { nonceNode = xmlSecAddPrevSibling(cur, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs); } else { nonceNode = xmlSecAddChild(node, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs); } if(nonceNode == NULL) { xmlSecInternalError2("xmlSecAddChild or xmlSecAddPrevSibling", NULL, "node=%s", xmlSecErrorsSafeString(xmlSecNodeChaCha20Nonce)); return(-1); } cur = nonceNode; } xmlSecAssert2(cur != NULL, -1); xmlSecAssert2(xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs), -1); /* set nonce content */ ret = xmlSecSetNodeContentAsHex(cur, iv + XMLSEC_CHACHA20_COUNTER_SIZE, XMLSEC_CHACHA20_NONCE_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecSetNodeContentAsHex(Nonce)", NULL); return(-1); } /* add counter node if needed */ cur = xmlSecGetNextElementNode(cur->next); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Counter, xmlSecXmldsig2021MoreNs))) { xmlNodePtr counterNode; /* add counter node */ if (cur != NULL) { counterNode = xmlSecAddPrevSibling(cur, xmlSecNodeChaCha20Counter, xmlSecXmldsig2021MoreNs); } else { counterNode = xmlSecAddChild(node, xmlSecNodeChaCha20Counter, xmlSecXmldsig2021MoreNs); } if(counterNode == NULL) { xmlSecInternalError2("xmlSecAddChild or xmlSecAddPrevSibling", NULL, "node=%s", xmlSecErrorsSafeString(xmlSecNodeChaCha20Counter)); return(-1); } cur = counterNode; } xmlSecAssert2(cur != NULL, -1); xmlSecAssert2(xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Counter, xmlSecXmldsig2021MoreNs), -1); /* set counter content */ ret = xmlSecSetNodeContentAsHex(cur, iv, XMLSEC_CHACHA20_COUNTER_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecSetNodeContentAsHex(Counter)", NULL); return(-1); } /* nothing else is expected */ cur = xmlSecGetNextElementNode(cur->next); if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* done */ return(0); } /* * https://www.w3.org/TR/draft-eastlake-rfc9231bis-xmlsec-uris-06/#sec-ChaCha20-Poly1305 * * <xenc:EncryptionMethod Algorithm="...#chacha20poly1305"> * <dsig-more:Nonce>0123456789abcdef01234567</dsig-more:Nonce> * <dsig-more:AAD>optional additional authenticated data</dsig-more:AAD> * </xenc:EncryptionMethod> */ int xmlSecTransformChaCha20Poly1305ParamsRead(xmlNodePtr node, xmlSecBufferPtr aad, xmlSecByte *iv, xmlSecSize ivSize, xmlSecSize *ivSizeOut, int *noncePresent) { xmlSecBuffer buf; xmlSecByte* bufData; xmlSecSize bufSize; xmlNodePtr cur; int ret; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(aad != NULL, -1); xmlSecAssert2(iv != NULL, -1); xmlSecAssert2(ivSize >= XMLSEC_CHACHA20_NONCE_SIZE, -1); xmlSecAssert2(ivSizeOut != NULL, -1); xmlSecAssert2(noncePresent != NULL, -1); /* prep output params */ memset(iv, 0, XMLSEC_CHACHA20_NONCE_SIZE); xmlSecBufferEmpty(aad); (*ivSizeOut) = 0; (*noncePresent) = 0; ret = xmlSecBufferInitialize(&buf, XMLSEC_CHACHA20_NONCE_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecGetNodeContentAsHex(Nonce)", NULL); return(-1); } /* first optional Nonce node (12 bytes, hex-encoded) */ cur = xmlSecGetNextElementNode(node->children); if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs))) { ret = xmlSecGetNodeContentAsHex(cur, &buf); if(ret < 0) { xmlSecInternalError("xmlSecGetNodeContentAsHex(Nonce)", NULL); xmlSecBufferFinalize(&buf); return(-1); } bufData = xmlSecBufferGetData(&buf); bufSize = xmlSecBufferGetSize(&buf); if((bufData == NULL) || (bufSize != XMLSEC_CHACHA20_NONCE_SIZE)) { xmlSecInvalidSizeDataError("Nonce", bufSize, "12 bytes", NULL); xmlSecBufferFinalize(&buf); return(-1); } memcpy(iv, bufData, bufSize); xmlSecBufferEmpty(&buf); (*noncePresent) = 1; cur = xmlSecGetNextElementNode(cur->next); } /* second optional AAD node (plain text string) */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Poly1305AAD, xmlSecXmldsig2021MoreNs))) { xmlChar* aadContent = xmlNodeGetContent(cur); if(aadContent != NULL) { int aadContentLen = xmlStrlen(aadContent); if(aadContentLen > 0) { ret = xmlSecBufferSetData(aad, aadContent, (xmlSecSize)aadContentLen); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetData(aad)", NULL); xmlFree(aadContent); xmlSecBufferFinalize(&buf); return(-1); } } xmlFree(aadContent); } cur = xmlSecGetNextElementNode(cur->next); } /* nothing else is expected */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); xmlSecBufferFinalize(&buf); return(-1); } /* done */ (*ivSizeOut) = XMLSEC_CHACHA20_NONCE_SIZE; xmlSecBufferFinalize(&buf); return(0); } int xmlSecTransformChaCha20Poly1305ParamsWrite(xmlNodePtr node, const xmlSecByte *iv, xmlSecSize ivSize) { xmlNodePtr cur; int ret; xmlSecAssert2(node != NULL, -1); xmlSecAssert2(iv != NULL, -1); xmlSecAssert2(ivSize >= XMLSEC_CHACHA20_NONCE_SIZE, -1); /* add nonce node if needed */ cur = xmlSecGetNextElementNode(node->children); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs))) { xmlNodePtr nonceNode; /* add nonce node */ if (cur != NULL) { nonceNode = xmlSecAddPrevSibling(cur, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs); } else { nonceNode = xmlSecAddChild(node, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs); } if(nonceNode == NULL) { xmlSecInternalError2("xmlSecAddChild or xmlSecAddPrevSibling", NULL, "node=%s", xmlSecErrorsSafeString(xmlSecNodeChaCha20Nonce)); return(-1); } cur = nonceNode; } xmlSecAssert2(cur != NULL, -1); xmlSecAssert2(xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Nonce, xmlSecXmldsig2021MoreNs), -1); /* set nonce content */ ret = xmlSecSetNodeContentAsHex(cur, iv, XMLSEC_CHACHA20_NONCE_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecSetNodeContentAsHex(Nonce)", NULL); return(-1); } /* next is optional AAD node (plain text string) */ cur = xmlSecGetNextElementNode(cur->next); if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeChaCha20Poly1305AAD, xmlSecXmldsig2021MoreNs))) { cur = xmlSecGetNextElementNode(cur->next); } /* nothing else is expected */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* done */ return(0); } #endif /* XMLSEC_NO_CHACHA20 */ #ifndef XMLSEC_NO_RSA #ifndef XMLSEC_NO_RSA_OAEP int xmlSecTransformRsaOaepParamsInitialize(xmlSecTransformRsaOaepParamsPtr oaepParams) { int ret; xmlSecAssert2(oaepParams != NULL, -1); memset(oaepParams, 0, sizeof(xmlSecTransformRsaOaepParams)); ret = xmlSecBufferInitialize(&(oaepParams->oaepParams), 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize", NULL); return(-1); } return(0); } void xmlSecTransformRsaOaepParamsFinalize(xmlSecTransformRsaOaepParamsPtr oaepParams) { xmlSecAssert(oaepParams != NULL); xmlSecBufferFinalize(&(oaepParams->oaepParams)); if(oaepParams->digestAlgorithm != NULL) { xmlFree(oaepParams->digestAlgorithm); } if(oaepParams->mgf1DigestAlgorithm != NULL) { xmlFree(oaepParams->mgf1DigestAlgorithm); } memset(oaepParams, 0, sizeof(xmlSecTransformRsaOaepParams)); } /* * See https://www.w3.org/TR/xmlenc-core1/#sec-RSA-OAEP * <EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#rsa-oaep"> * <OAEPparams>9lWu3Q==</OAEPparams> * <xenc11:MGF Algorithm="http://www.w3.org/2001/04/xmlenc#MGF1withSHA1" /> * <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> * <EncryptionMethod> */ int xmlSecTransformRsaOaepParamsRead(xmlSecTransformRsaOaepParamsPtr oaepParams, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(oaepParams != NULL, -1); xmlSecAssert2(xmlSecBufferGetSize(&(oaepParams->oaepParams)) == 0, -1); xmlSecAssert2(oaepParams->digestAlgorithm == NULL, -1); xmlSecAssert2(oaepParams->mgf1DigestAlgorithm == NULL, -1); xmlSecAssert2(node != NULL, -1); cur = xmlSecGetNextElementNode(node->children); while (cur != NULL) { if (xmlSecCheckNodeName(cur, xmlSecNodeRsaOAEPparams, xmlSecEncNs)) { ret = xmlSecBufferBase64NodeContentRead(&(oaepParams->oaepParams), cur); if (ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead", NULL); return(-1); } } else if (xmlSecCheckNodeName(cur, xmlSecNodeDigestMethod, xmlSecDSigNs)) { /* digest algorithm attribute is required; free any previously * stored value to avoid a leak if the node appears more than once */ if (oaepParams->digestAlgorithm != NULL) { xmlFree(oaepParams->digestAlgorithm); oaepParams->digestAlgorithm = NULL; } oaepParams->digestAlgorithm = xmlGetProp(cur, xmlSecAttrAlgorithm); if (oaepParams->digestAlgorithm == NULL) { xmlSecInvalidNodeAttributeError(cur, xmlSecAttrAlgorithm, NULL, "empty"); return(-1); } } else if (xmlSecCheckNodeName(cur, xmlSecNodeRsaMGF, xmlSecEnc11Ns)) { /* mgf1 digest algorithm attribute is required; free any previously * stored value to avoid a leak if the node appears more than once */ if (oaepParams->mgf1DigestAlgorithm != NULL) { xmlFree(oaepParams->mgf1DigestAlgorithm); oaepParams->mgf1DigestAlgorithm = NULL; } oaepParams->mgf1DigestAlgorithm = xmlGetProp(cur, xmlSecAttrAlgorithm); if (oaepParams->mgf1DigestAlgorithm == NULL) { xmlSecInvalidNodeAttributeError(cur, xmlSecAttrAlgorithm, NULL, "empty"); return(-1); } } else { /* node not recognized */ xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* next node */ cur = xmlSecGetNextElementNode(cur->next); } /* done */ return(0); } #endif /* XMLSEC_NO_RSA_OAEP */ #endif /* XMLSEC_NO_RSA */