/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/keysdata_helpers.c
2 600 строк
86 KB
Javid Khan
return error from xmlSecKeyDataBinaryValueBinRead on key req mismatch (#1194)
30 май 2026, 22:14
Не верифицирован
30 май 2026, 22:14
6804eed
Код
Авторство
О чём код?
/** * 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 key data implementations. */ #include "globals.h" #include <stdlib.h> #include <string.h> #include <ctype.h> #include <libxml/tree.h> #include <xmlsec/xmlsec.h> #include <xmlsec/buffer.h> #include <xmlsec/xmltree.h> #include <xmlsec/keys.h> #include <xmlsec/keyinfo.h> #include <xmlsec/base64.h> #include <xmlsec/keyinfo.h> #include <xmlsec/membuf.h> #include <xmlsec/strings.h> #include <xmlsec/errors.h> #include <xmlsec/private.h> #include "cast_helpers.h" #include "keysdata_helpers.h" void xmlSecKeyDataDebugDumpImpl(xmlSecKeyDataPtr data, FILE* output) { xmlSecAssert(xmlSecKeyDataIsValid(data)); xmlSecAssert(data->id->name != NULL); xmlSecAssert(output != NULL); fprintf(output, "=== %s key: size = " XMLSEC_SIZE_FMT "\n", data->id->name, xmlSecKeyDataGetSize(data)); } void xmlSecKeyDataDebugXmlDumpImpl(xmlSecKeyDataPtr data, FILE* output) { xmlSecAssert(xmlSecKeyDataIsValid(data)); xmlSecAssert(data->id->name != NULL); xmlSecAssert(output != NULL); fprintf(output, "<%sKey size=\"" XMLSEC_SIZE_FMT "\"/>\n", data->id->dataNodeName != NULL ? data->id->dataNodeName : data->id->name, xmlSecKeyDataGetSize(data)); } /****************************************************************************** * * xmlSecKeyDataBinary methods * *****************************************************************************/ /** * @brief Initializes binary key data. * @param data the pointer to binary key data. * * @return 0 on success or a negative value otherwise. */ int xmlSecKeyDataBinaryValueInitialize(xmlSecKeyDataPtr data) { xmlSecBufferPtr buffer; int ret; xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize), -1); /* initialize buffer */ buffer = xmlSecKeyDataBinaryValueGetBuffer(data); xmlSecAssert2(buffer != NULL, -1); ret = xmlSecBufferInitialize(buffer, 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize", xmlSecKeyDataGetName(data)); return(-1); } return(0); } /** * @brief Copies binary key data from @p src to @p dst. * @param dst the pointer to destination binary key data. * @param src the pointer to source binary key data. * * @return 0 on success or a negative value otherwise. */ int xmlSecKeyDataBinaryValueDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { xmlSecBufferPtr buffer; int ret; xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecKeyDataBinarySize), -1); xmlSecAssert2(xmlSecKeyDataIsValid(src), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecKeyDataBinarySize), -1); buffer = xmlSecKeyDataBinaryValueGetBuffer(src); xmlSecAssert2(buffer != NULL, -1); /* copy data */ ret = xmlSecKeyDataBinaryValueSetBuffer(dst, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer)); if(ret < 0) { xmlSecInternalError("xmlSecKeyDataBinaryValueSetBuffer", xmlSecKeyDataGetName(dst)); return(-1); } return(0); } /** * @brief Cleans up binary key data. * @param data the pointer to binary key data. */ void xmlSecKeyDataBinaryValueFinalize(xmlSecKeyDataPtr data) { xmlSecBufferPtr buffer; xmlSecAssert(xmlSecKeyDataIsValid(data)); xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize)); /* initialize buffer */ buffer = xmlSecKeyDataBinaryValueGetBuffer(data); xmlSecAssert(buffer != NULL); xmlSecBufferFinalize(buffer); } /** * @brief Reads binary key data from an XML node (base64 decoded). * @details Reads binary key data from @p node to the key by base64 decoding the @p node content. * @param id the data klass. * @param key the pointer to destination key. * @param node the pointer to an XML node. * @param keyInfoCtx the pointer to <dsig:KeyInfo/> element processing context. * * @return 0 on success or a negative value otherwise. */ int xmlSecKeyDataBinaryValueXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { xmlChar* str = NULL; xmlSecKeyDataPtr data = NULL; xmlSecKeyDataPtr existingData; xmlSecSize decodedSize; int ret; int res = -1; xmlSecAssert2(id != xmlSecKeyDataIdUnknown, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); str = xmlSecGetNodeContentAndTrim(node); if(str == NULL) { xmlSecInvalidNodeContentError(node, xmlSecKeyDataKlassGetName(id), "empty"); goto done; } /* usual trick: decode into the same buffer */ decodedSize = 0; ret = xmlSecBase64DecodeInPlace(str, &decodedSize); if(ret < 0) { xmlSecInternalError("xmlSecBase64Decode_ex", xmlSecKeyDataKlassGetName(id)); goto done; } /* check do we have a key already; the returned pointer is owned by the * key, do not store it in `data` (which the `done:` cleanup destroys). */ existingData = xmlSecKeyGetValue(key); if(existingData != NULL) { xmlSecBufferPtr buffer; if(!xmlSecKeyDataCheckId(existingData, id)) { xmlSecOtherError2(XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, xmlSecKeyDataGetName(existingData), "id=%s", xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id))); goto done; } buffer = xmlSecKeyDataBinaryValueGetBuffer(existingData); if(buffer != NULL) { if(xmlSecBufferGetSize(buffer) != decodedSize) { xmlSecOtherError3(XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, xmlSecKeyDataGetName(existingData), "cur-data-size=" XMLSEC_SIZE_FMT "; new-data-size=" XMLSEC_SIZE_FMT, xmlSecBufferGetSize(buffer), decodedSize); goto done; } ret = xmlSecMemEqual(xmlSecBufferGetData(buffer), (const xmlSecByte*)str, decodedSize); if(ret < 0) { xmlSecInternalError("xmlSecMemEqual", xmlSecKeyDataGetName(existingData)); goto done; } if(ret == 0) { xmlSecOtherError(XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, xmlSecKeyDataGetName(existingData), "key already has a different value"); goto done; } /* we already have exactly the same key */ res = 0; goto done; } /* we have binary key value with empty buffer */ } data = xmlSecKeyDataCreate(id); if(data == NULL ) { xmlSecInternalError("xmlSecKeyDataCreate", xmlSecKeyDataKlassGetName(id)); goto done; } ret = xmlSecKeyDataBinaryValueSetBuffer(data, (xmlSecByte*)str, decodedSize); if(ret < 0) { xmlSecInternalError2("xmlSecKeyDataBinaryValueSetBuffer", xmlSecKeyDataKlassGetName(id), "size=" XMLSEC_SIZE_FMT, decodedSize); goto done; } if(xmlSecKeyReqMatchKeyValue(&(keyInfoCtx->keyReq), data) != 1) { xmlSecInternalError("xmlSecKeyReqMatchKeyValue", xmlSecKeyDataKlassGetName(id)); goto done; } ret = xmlSecKeySetValue(key, data); if(ret < 0) { xmlSecInternalError("xmlSecKeySetValue", xmlSecKeyDataKlassGetName(id)); goto done; } data = NULL; /* data is owned by key */ /* success */ res = 0; done: if(data != NULL) { xmlSecKeyDataDestroy(data); } if(str != NULL) { xmlFree(str); } return(res); } /** * @brief Base64 encodes key data and writes to an XML node. * @details Base64 encodes binary key data of klass @p id from the @p key and * sets to the @p node content. * @param id the data klass. * @param key the pointer to source key. * @param node the pointer to an XML node. * @param keyInfoCtx the pointer to <dsig:KeyInfo/> element processing context. * * @return 0 on success or a negative value otherwise. */ int xmlSecKeyDataBinaryValueXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { xmlSecBufferPtr buffer; xmlSecKeyDataPtr value; xmlChar* str; xmlSecAssert2(id != xmlSecKeyDataIdUnknown, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); if((xmlSecKeyDataTypeSymmetric & keyInfoCtx->keyReq.keyType) == 0) { /* we can have only symmetric key */ return(0); } value = xmlSecKeyGetValue(key); xmlSecAssert2(xmlSecKeyDataIsValid(value), -1); buffer = xmlSecKeyDataBinaryValueGetBuffer(value); xmlSecAssert2(buffer != NULL, -1); str = xmlSecBase64Encode(xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), keyInfoCtx->base64LineSize); if(str == NULL) { xmlSecInternalError("xmlSecBase64Encode", xmlSecKeyDataKlassGetName(id)); return(-1); } xmlNodeSetContent(node, str); xmlFree(str); return(0); } /** * @brief Reads binary key data from a binary buffer into a key. * @details Reads binary key data of the klass @p id from @p buf to the @p key. * @param id the data klass. * @param key the pointer to destination key. * @param buf the source binary buffer. * @param bufSize the source binary buffer size. * @param keyInfoCtx the pointer to <dsig:KeyInfo/> element processing context. * * @return 0 on success or a negative value otherwise. */ int xmlSecKeyDataBinaryValueBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, const xmlSecByte* buf, xmlSecSize bufSize, xmlSecKeyInfoCtxPtr keyInfoCtx) { xmlSecKeyDataPtr data; int ret; xmlSecAssert2(id != xmlSecKeyDataIdUnknown, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(bufSize > 0, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); /* check do we have a key already */ data = xmlSecKeyGetValue(key); if(data != NULL) { xmlSecBufferPtr buffer; if(!xmlSecKeyDataCheckId(data, id)) { xmlSecOtherError2(XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, xmlSecKeyDataGetName(data), "id=%s", xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id))); return(-1); } buffer = xmlSecKeyDataBinaryValueGetBuffer(data); if(buffer != NULL) { if(xmlSecBufferGetSize(buffer) != bufSize) { xmlSecOtherError3(XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, xmlSecKeyDataGetName(data), "cur-data-size=" XMLSEC_SIZE_FMT "; new-data-size=" XMLSEC_SIZE_FMT, xmlSecBufferGetSize(buffer), bufSize); return(-1); } ret = xmlSecMemEqual(xmlSecBufferGetData(buffer), buf, bufSize); if(ret < 0) { xmlSecInternalError("xmlSecMemEqual", xmlSecKeyDataGetName(data)); return(-1); } if(ret == 0) { xmlSecOtherError(XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, xmlSecKeyDataGetName(data), "key already has a different value"); return(-1); } /* we already have exactly the same key */ return(0); } /* we have binary key value with empty buffer */ } data = xmlSecKeyDataCreate(id); if(data == NULL ) { xmlSecInternalError("xmlSecKeyDataCreate", xmlSecKeyDataKlassGetName(id)); return(-1); } ret = xmlSecKeyDataBinaryValueSetBuffer(data, buf, bufSize); if(ret < 0) { xmlSecInternalError2("xmlSecKeyDataBinaryValueSetBuffer", xmlSecKeyDataKlassGetName(id), "size=" XMLSEC_SIZE_FMT, bufSize); xmlSecKeyDataDestroy(data); return(-1); } if(xmlSecKeyReqMatchKeyValue(&(keyInfoCtx->keyReq), data) != 1) { xmlSecInternalError("xmlSecKeyReqMatchKeyValue", xmlSecKeyDataKlassGetName(id)); xmlSecKeyDataDestroy(data); return(-1); } ret = xmlSecKeySetValue(key, data); if(ret < 0) { xmlSecInternalError("xmlSecKeySetValue", xmlSecKeyDataKlassGetName(id)); xmlSecKeyDataDestroy(data); return(-1); } return(0); } /** * @brief Writes binary key data from a key into a binary buffer. * @details Writes binary key data of klass @p id from the @p key to @p buf. * @param id the data klass. * @param key the pointer to source key. * @param buf the destination binary buffer. * @param bufSize the destination binary buffer size. * @param keyInfoCtx the pointer to <dsig:KeyInfo/> element processing context. * * @return 0 on success or a negative value otherwise. */ int xmlSecKeyDataBinaryValueBinWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlSecByte** buf, xmlSecSize* bufSize, xmlSecKeyInfoCtxPtr keyInfoCtx) { xmlSecKeyDataPtr value; xmlSecBufferPtr buffer; xmlSecAssert2(id != xmlSecKeyDataIdUnknown, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(bufSize != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); if((xmlSecKeyDataTypeSymmetric & keyInfoCtx->keyReq.keyType) == 0) { /* we can have only symmetric key */ return(0); } value = xmlSecKeyGetValue(key); xmlSecAssert2(xmlSecKeyDataIsValid(value), -1); buffer = xmlSecKeyDataBinaryValueGetBuffer(key->value); xmlSecAssert2(buffer != NULL, -1); (*bufSize) = xmlSecBufferGetSize(buffer); (*buf) = (xmlSecByte*) xmlMalloc((*bufSize)); if((*buf) == NULL) { xmlSecMallocError((*bufSize), xmlSecKeyDataKlassGetName(id)); return(-1); } memcpy((*buf), xmlSecBufferGetData(buffer), (*bufSize)); return(0); } /** * @brief Prints binary key data debug information. * @details Prints binary key data debug information to @p output. * @param data the pointer to binary key data. * @param output the pointer to output FILE. */ void xmlSecKeyDataBinaryValueDebugDump(xmlSecKeyDataPtr data, FILE* output) { xmlSecBufferPtr buffer; xmlSecAssert(xmlSecKeyDataIsValid(data)); xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize)); xmlSecAssert(data->id->dataNodeName != NULL); xmlSecAssert(output != NULL); buffer = xmlSecKeyDataBinaryValueGetBuffer(data); xmlSecAssert(buffer != NULL); /* print only size, everything else is sensitive */ fprintf(output, "=== %s: size=" XMLSEC_SIZE_FMT "\n", data->id->dataNodeName, xmlSecKeyDataGetSize(data)); } /** * @brief Prints binary key data debug information in XML format. * @details Prints binary key data debug information to @p output in XML format. * @param data the pointer to binary key data. * @param output the pointer to output FILE. */ void xmlSecKeyDataBinaryValueDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { xmlSecBufferPtr buffer; xmlSecAssert(xmlSecKeyDataIsValid(data)); xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize)); xmlSecAssert(data->id->dataNodeName != NULL); xmlSecAssert(output != NULL); buffer = xmlSecKeyDataBinaryValueGetBuffer(data); xmlSecAssert(buffer != NULL); /* print only size, everything else is sensitive */ fprintf(output, "<%s size=\"" XMLSEC_SIZE_FMT "\" />\n", data->id->dataNodeName, xmlSecKeyDataGetSize(data)); } /** * @brief Gets the binary key data size. * @param data the pointer to binary key data. * * @return binary key data size in bits. */ xmlSecSize xmlSecKeyDataBinaryValueGetSize(xmlSecKeyDataPtr data) { xmlSecBufferPtr buffer; xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize), 0); buffer = xmlSecKeyDataBinaryValueGetBuffer(data); xmlSecAssert2(buffer != NULL, 0); /* return size in bits */ return(8 * xmlSecBufferGetSize(buffer)); } /** * @brief Gets the binary key data buffer. * @param data the pointer to binary key data. * * @return pointer to binary key data buffer. */ xmlSecBufferPtr xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyDataPtr data) { xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL); xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize), NULL); return(&(((xmlSecKeyDataBinary *)data)->buffer)); } /** * @brief Sets the value of @p data to @p buf. * @param data the pointer to binary key data. * @param buf the pointer to binary buffer. * @param bufSize the binary buffer size. * * @return 0 on success or a negative value otherwise. */ int xmlSecKeyDataBinaryValueSetBuffer(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { xmlSecBufferPtr buffer; xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize), -1); xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(bufSize > 0, -1); buffer = xmlSecKeyDataBinaryValueGetBuffer(data); xmlSecAssert2(buffer != NULL, -1); return(xmlSecBufferSetData(buffer, buf, bufSize)); } #if !defined(XMLSEC_NO_EC) /****************************************************************************** * * Helper functions to read/write EC keys * *****************************************************************************/ #define XMLSEC_KEY_DATA_EC_INIT_BUF_SIZE 256 static int xmlSecKeyValueEcInitialize (xmlSecKeyValueEcPtr data); static void xmlSecKeyValueEcFinalize (xmlSecKeyValueEcPtr data); static int xmlSecKeyValueEcXmlRead (xmlSecKeyValueEcPtr data, xmlNodePtr node); static int xmlSecKeyValueEcXmlWrite (xmlSecKeyValueEcPtr data, xmlNodePtr node, int base64LineSize, int addLineBreaks); /** * @brief EC Key data method for reading XML node. * @param id the data id. * @param key the key. * @param node the pointer to data's value XML node. * @param keyInfoCtx the <dsig:KeyInfo/> node processing context. * @param readFunc the pointer to the function that converts * xmlSecKeyValueEc to xmlSecKeyData. * * @return 0 on success or a negative value if an error occurs. */ int xmlSecKeyDataEcXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx, xmlSecKeyDataEcRead readFunc) { xmlSecKeyDataPtr data = NULL; xmlSecKeyValueEc ecValue; int ecDataInitialized = 0; int res = -1; int ret; xmlSecAssert2(id != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecAssert2(readFunc != NULL, -1); if(xmlSecKeyGetValue(key) != NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_KEY_DATA, xmlSecKeyDataKlassGetName(id), "key already has a value"); goto done; } ret = xmlSecKeyValueEcInitialize(&ecValue); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueEcInitialize", xmlSecKeyDataKlassGetName(id)); goto done; } ecDataInitialized = 1; ret = xmlSecKeyValueEcXmlRead(&ecValue, node); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueEcXmlRead", xmlSecKeyDataKlassGetName(id)); goto done; } data = readFunc(id, &ecValue); if(data == NULL) { xmlSecInternalError("xmlSecKeyDataEcRead", xmlSecKeyDataKlassGetName(id)); goto done; } /* set key value */ ret = xmlSecKeySetValue(key, data); if(ret < 0) { xmlSecInternalError("xmlSecKeySetValue", xmlSecKeyDataGetName(data)); goto done; } data = NULL; /* data is owned by key now */ /* success */ res = 0; done: /* cleanup */ if(ecDataInitialized != 0) { xmlSecKeyValueEcFinalize(&ecValue); } if(data != NULL) { xmlSecKeyDataDestroy(data); } return(res); } /** * @brief EC Key data method for writing XML node. * @param id the data id. * @param key the key. * @param node the pointer to data's value XML node. * @param keyInfoCtx the <dsig:KeyInfo/> node processing context. * @param base64LineSize the base64 max line size. * @param addLineBreaks the flag indicating if we need to add line breaks around base64 output. * @param writeFunc the pointer to the function that converts * xmlSecKeyData to xmlSecKeyValueEc. * * @return 0 on success or a negative value if an error occurs. */ int xmlSecKeyDataEcXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx, int base64LineSize, int addLineBreaks, xmlSecKeyDataEcWrite writeFunc) { xmlSecKeyDataPtr data; xmlSecKeyValueEc ecValue; int ecDataInitialized = 0; int res = -1; int ret; xmlSecAssert2(id != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecAssert2(writeFunc != NULL, -1); xmlSecAssert2(base64LineSize > 0, -1); if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { /* we can have only private key or public key */ return(0); } data = xmlSecKeyGetValue(key); if(data == NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_KEY_DATA, xmlSecKeyDataKlassGetName(id), "key has no value"); goto done; } ret = xmlSecKeyValueEcInitialize(&ecValue); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueEcInitialize", xmlSecKeyDataKlassGetName(id)); goto done; } ecDataInitialized = 1; ret = writeFunc(id, data, &ecValue); if(ret < 0) { xmlSecInternalError("xmlSecKeyDataEcWrite", xmlSecKeyDataKlassGetName(id)); goto done; } ret = xmlSecKeyValueEcXmlWrite(&ecValue, node, base64LineSize, addLineBreaks); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueEcXmlWrite", xmlSecKeyDataKlassGetName(id)); goto done; } /* success */ res = 0; done: /* cleanup */ if(ecDataInitialized != 0) { xmlSecKeyValueEcFinalize(&ecValue); } return(res); } static int xmlSecKeyValueEcInitialize(xmlSecKeyValueEcPtr data) { int ret; xmlSecAssert2(data != NULL, -1); memset(data, 0, sizeof(xmlSecKeyValueEc)); ret = xmlSecBufferInitialize(&(data->pubkey), XMLSEC_KEY_DATA_EC_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(pubkey)", NULL); xmlSecKeyValueEcFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->pub_x), XMLSEC_KEY_DATA_EC_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(pub_x)", NULL); xmlSecKeyValueEcFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->pub_y), XMLSEC_KEY_DATA_EC_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(pub_y)", NULL); xmlSecKeyValueEcFinalize(data); return(-1); } return(0); } static void xmlSecKeyValueEcFinalize(xmlSecKeyValueEcPtr data) { xmlSecAssert(data != NULL); if(data->curve != NULL) { xmlFree(data->curve); } xmlSecBufferFinalize(&(data->pubkey)); xmlSecBufferFinalize(&(data->pub_x)); xmlSecBufferFinalize(&(data->pub_y)); memset(data, 0, sizeof(xmlSecKeyValueEc)); } /* * The PublicKey element contains a Base64 encoding of a binary representation of the x and y coordinates of * the point. Its value is computed as follows: * 1/ Convert the elliptic curve point (x,y) to an octet string by first converting the field elements * x and y to octet strings as specified in Section 6.2 of [ECC-ALGS] (note), and then prepend the * concatenated result of the conversion with 0x04. Support for Elliptic-Curve-Point-to-Octet-String * conversion without point compression is REQUIRED. * 2/ Base64 encode the octet string resulting from the conversion in Step 1. */ #define XMLSEC_ECKEYVALYU_ECPOINT_MAGIC_BYTE 0x04 int xmlSecKeyDataEcPublicKeySplitComponents (xmlSecKeyValueEcPtr ecValue) { xmlSecSize size; xmlSecByte* data; int ret; xmlSecAssert2(ecValue != NULL, -1); /* check size and magic number */ data = xmlSecBufferGetData(&(ecValue->pubkey)); size = xmlSecBufferGetSize(&(ecValue->pubkey)); if((data == NULL) || (size <= 1) || ((size % 2) != 1)) { xmlSecInvalidSizeDataError("PublicKey", size, "ECPoint data should have an odd size > 1 ", NULL); return(-1); } if(data[0] != XMLSEC_ECKEYVALYU_ECPOINT_MAGIC_BYTE) { xmlSecInvalidDataError("PublicKey must start from a magic number", NULL); return(-1); } ++data; size = (size - 1) / 2; /* set pub_y */ ret = xmlSecBufferSetData(&(ecValue->pub_x), data, size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetData(pub_x)", NULL, "size=" XMLSEC_SIZE_FMT, size); return(-1); } /* set pub_y */ ret = xmlSecBufferSetData(&(ecValue->pub_y), data + size, size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetData(pub_y)", NULL, "size=" XMLSEC_SIZE_FMT, size); return(-1); } /* done */ return(0); } int xmlSecKeyDataEcPublicKeyCombineComponents (xmlSecKeyValueEcPtr ecValue) { xmlSecByte * dataX, * dataY, * data; xmlSecSize sizeX, sizeY, sizeKey, size; int ret; xmlSecAssert2(ecValue != NULL, -1); dataX = xmlSecBufferGetData(&(ecValue->pub_x)); sizeX = xmlSecBufferGetSize(&(ecValue->pub_x)); dataY = xmlSecBufferGetData(&(ecValue->pub_y)); sizeY = xmlSecBufferGetSize(&(ecValue->pub_y)); xmlSecAssert2(dataX != NULL, -1); xmlSecAssert2(dataY != NULL, -1); xmlSecAssert2(sizeX > 0, -1); xmlSecAssert2(sizeY > 0, -1); /* max of the two sizes (prepend 0s if needed) */ sizeKey = (sizeX >= sizeY) ? sizeX : sizeY; size = 1 + 2 * sizeKey; /* <magic byte> || x || y */ ret = xmlSecBufferSetSize(&(ecValue->pubkey), size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetSize(pubkeyy)", NULL, "size=" XMLSEC_SIZE_FMT, size); return(-1); } data = xmlSecBufferGetData(&(ecValue->pubkey)); xmlSecAssert2(data != NULL, -1); /* <magic byte> || x || y, prepend 0s if needed */ memset(data, 0, size); data[0] = XMLSEC_ECKEYVALYU_ECPOINT_MAGIC_BYTE; memcpy(data + 1 + sizeKey - sizeX, dataX, sizeX); memcpy(data + 1 + sizeKey + sizeKey - sizeY, dataY, sizeY); /* done */ return(0); } /* See https://www.w3.org/TR/xmldsig-core/#sec-ECKeyValue * * <!-- targetNamespace="http://www.w3.org/2009/xmldsig11#" --> * * <element name="ECKeyValue" type="dsig11:ECKeyValueType" /> * * <complexType name="ECKeyValueType"> * <sequence> * <choice> * <element name="ECParameters" type="dsig11:ECParametersType" /> * <element name="NamedCurve" type="dsig11:NamedCurveType" /> * </choice> * <element name="PublicKey" type="dsig11:ECPointType" /> * </sequence> * <attribute name="Id" type="ID" use="optional" /> * </complexType> * * <complexType name="NamedCurveType"> * <attribute name="URI" type="anyURI" use="required" /> * </complexType> * * <simpleType name="ECPointType"> * <restriction base="ds:CryptoBinary" /> * </simpleType> * * Note that ECParameters node is not supported for now (https://github.com/lsh123/xmlsec/issues/516). * */ #define XMLSEC_KEYVALUE_EC_OID_PREFIX (BAD_CAST "urn:oid:") static int xmlSecKeyValueEcXmlRead(xmlSecKeyValueEcPtr data, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(data->curve == NULL, -1); xmlSecAssert2(node != NULL, -1); cur = xmlSecGetNextElementNode(node->children); /* first is NamedCurve node with a required URI parameter (ECParameters is not supported)*/ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeNamedCurve, xmlSecDSig11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodeNamedCurve, NULL); return(-1); } data->curve = xmlGetProp(cur, xmlSecAttrURI); if(data->curve == NULL) { xmlSecInvalidNodeAttributeError(cur, xmlSecAttrURI, NULL, "empty"); return(-1); } /* remove the oid prefix if needed */ if((xmlStrncmp(data->curve, XMLSEC_KEYVALUE_EC_OID_PREFIX, xmlStrlen(XMLSEC_KEYVALUE_EC_OID_PREFIX)) == 0)) { xmlChar * curve = xmlStrdup(data->curve + xmlStrlen(XMLSEC_KEYVALUE_EC_OID_PREFIX)); if(curve == NULL) { xmlSecStrdupError(data->curve, NULL); return(-1); } xmlFree(data->curve); data->curve = curve; } cur = xmlSecGetNextElementNode(cur->next); /* second node is PublicKey node: read the "combined" public key only since many * crypto libraries don't need a split into (x, y) pair */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodePublicKey, xmlSecDSig11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodePublicKey, NULL); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(data->pubkey), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(pubkey)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* we are done, any other node is not expected */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* success */ return(0); } static int xmlSecKeyValueEcXmlWrite(xmlSecKeyValueEcPtr data, xmlNodePtr node, int base64LineSize, int addLineBreaks) { xmlNodePtr cur; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(data->curve != NULL, -1); xmlSecAssert2(node != NULL, -1); /* first is NamedCurve node */ cur = xmlSecAddChild(node, xmlSecNodeNamedCurve, xmlSecDSig11Ns); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(NamedCurve)", NULL); return(-1); } /* add the oid prefix if needed */ if((xmlStrncmp(data->curve, XMLSEC_KEYVALUE_EC_OID_PREFIX, xmlStrlen(XMLSEC_KEYVALUE_EC_OID_PREFIX)) != 0)) { xmlSecSize size; xmlChar * curve; int len; len = xmlStrlen(XMLSEC_KEYVALUE_EC_OID_PREFIX) + xmlStrlen(data->curve) + 1; XMLSEC_SAFE_CAST_INT_TO_SIZE(len, size, return(-1), NULL); curve = (xmlChar *)xmlMalloc(size); if(curve == NULL) { xmlSecMallocError(size, NULL); return(-1); } ret = xmlStrPrintf(curve, len, "%s%s", XMLSEC_KEYVALUE_EC_OID_PREFIX, data->curve); if(ret < 0) { xmlSecXmlError("xmlStrPrintf", NULL); xmlFree(curve); return(-1); } xmlSetProp(cur, xmlSecAttrURI, curve); xmlFree(curve); } else { xmlSetProp(cur, xmlSecAttrURI, data->curve); } /* second node is PublicKey node */ cur = xmlSecAddChild(node, xmlSecNodePublicKey, xmlSecDSig11Ns); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(PublicKey)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->pubkey), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(q)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } /* done */ return(0); } #endif /* !defined(XMLSEC_NO_EC) */ #if !defined(XMLSEC_NO_DH) /****************************************************************************** * * Helper functions to read/write DH keys * * <element name="DHKeyValue" type="xenc:DHKeyValueType"/> * <complexType name="DHKeyValueType"> * <sequence> * <sequence minOccurs="0"> * <element name="P" type="ds:CryptoBinary"/> * <element name="Q" type="ds:CryptoBinary"/> * <element name="Generator"type="ds:CryptoBinary"/> * </sequence> * <element name="Public" type="ds:CryptoBinary"/> * <sequence minOccurs="0"> * <element name="seed" type="ds:CryptoBinary"/> * <element name="pgenCounter" type="ds:CryptoBinary"/> * </sequence> * </sequence> * </complexType> * *****************************************************************************/ #define XMLSEC_KEY_DATA_DH_INIT_BUF_SIZE 512 static int xmlSecKeyValueDhInitialize (xmlSecKeyValueDhPtr data); static void xmlSecKeyValueDhFinalize (xmlSecKeyValueDhPtr data); static int xmlSecKeyValueDhXmlRead (xmlSecKeyValueDhPtr data, xmlNodePtr node); static int xmlSecKeyValueDhXmlWrite (xmlSecKeyValueDhPtr data, xmlNodePtr node, int base64LineSize, int addLineBreaks); /** * @brief DH Key data method for reading XML node. * @param id the data id. * @param key the key. * @param node the pointer to data's value XML node. * @param keyInfoCtx the <dsig:KeyInfo/> node processing context. * @param readFunc the pointer to the function that converts * xmlSecKeyValueDh to xmlSecKeyData. * * @return 0 on success or a negative value if an error occurs. */ int xmlSecKeyDataDhXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx, xmlSecKeyDataDhRead readFunc ) { xmlSecKeyDataPtr data = NULL; xmlSecKeyValueDh dhValue; int dhDataInitialized = 0; int res = -1; int ret; xmlSecAssert2(id != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecAssert2(readFunc != NULL, -1); if(xmlSecKeyGetValue(key) != NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_KEY_DATA, xmlSecKeyDataKlassGetName(id), "key already has a value"); goto done; } ret = xmlSecKeyValueDhInitialize(&dhValue); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueDhInitialize", xmlSecKeyDataKlassGetName(id)); goto done; } dhDataInitialized = 1; ret = xmlSecKeyValueDhXmlRead(&dhValue, node); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueDhXmlRead", xmlSecKeyDataKlassGetName(id)); goto done; } data = readFunc(id, &dhValue); if(data == NULL) { xmlSecInternalError("xmlSecKeyDataDhRead", xmlSecKeyDataKlassGetName(id)); goto done; } /* set key value */ ret = xmlSecKeySetValue(key, data); if(ret < 0) { xmlSecInternalError("xmlSecKeySetValue", xmlSecKeyDataGetName(data)); goto done; } data = NULL; /* data is owned by key now */ /* success */ res = 0; done: /* cleanup */ if(dhDataInitialized != 0) { xmlSecKeyValueDhFinalize(&dhValue); } if(data != NULL) { xmlSecKeyDataDestroy(data); } return(res); } /** * @brief DH Key data method for writing XML node. * @param id the data id. * @param key the key. * @param node the pointer to data's value XML node. * @param keyInfoCtx the <dsig:KeyInfo/> node processing context. * @param base64LineSize the base64 max line size. * @param addLineBreaks the flag indicating if we need to add line breaks around base64 output. * @param writeFunc the pointer to the function that converts * xmlSecKeyData to xmlSecKeyValueDh. * * @return 0 on success or a negative value if an error occurs. */ int xmlSecKeyDataDhXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx, int base64LineSize, int addLineBreaks, xmlSecKeyDataDhWrite writeFunc ) { xmlSecKeyDataPtr data; xmlSecKeyValueDh dhValue; int dhDataInitialized = 0; int res = -1; int ret; xmlSecAssert2(id != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecAssert2(writeFunc != NULL, -1); xmlSecAssert2(base64LineSize > 0, -1); if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { /* we can have only private key or public key */ return(0); } data = xmlSecKeyGetValue(key); if(data == NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_KEY_DATA, xmlSecKeyDataKlassGetName(id), "key has no value"); goto done; } ret = xmlSecKeyValueDhInitialize(&dhValue); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueDhInitialize", xmlSecKeyDataKlassGetName(id)); goto done; } dhDataInitialized = 1; ret = writeFunc(id, data, &dhValue, 0 /* writePrivateKey is not supported */); if(ret < 0) { xmlSecInternalError("xmlSecKeyDataDhWrite", xmlSecKeyDataKlassGetName(id)); goto done; } ret = xmlSecKeyValueDhXmlWrite(&dhValue, node, base64LineSize, addLineBreaks); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueDhXmlWrite", xmlSecKeyDataKlassGetName(id)); goto done; } /* success */ res = 0; done: /* cleanup */ if(dhDataInitialized != 0) { xmlSecKeyValueDhFinalize(&dhValue); } return(res); } static int xmlSecKeyValueDhInitialize(xmlSecKeyValueDhPtr data) { int ret; xmlSecAssert2(data != NULL, -1); memset(data, 0, sizeof(xmlSecKeyValueDh)); ret = xmlSecBufferInitialize(&(data->p), XMLSEC_KEY_DATA_DH_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(p)", NULL); xmlSecKeyValueDhFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->q), XMLSEC_KEY_DATA_DH_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(q)", NULL); xmlSecKeyValueDhFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->generator), XMLSEC_KEY_DATA_DH_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(generator)", NULL); xmlSecKeyValueDhFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->public), XMLSEC_KEY_DATA_DH_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(public)", NULL); xmlSecKeyValueDhFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->seed), XMLSEC_KEY_DATA_DH_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(seed)", NULL); xmlSecKeyValueDhFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->pgenCounter), XMLSEC_KEY_DATA_DH_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(pgenCounter)", NULL); xmlSecKeyValueDhFinalize(data); return(-1); } return(0); } static void xmlSecKeyValueDhFinalize(xmlSecKeyValueDhPtr data) { xmlSecAssert(data != NULL); xmlSecBufferFinalize(&(data->p)); xmlSecBufferFinalize(&(data->q)); xmlSecBufferFinalize(&(data->generator)); xmlSecBufferFinalize(&(data->public)); xmlSecBufferFinalize(&(data->seed)); xmlSecBufferFinalize(&(data->pgenCounter)); memset(data, 0, sizeof(xmlSecKeyValueDh)); } static int xmlSecKeyValueDhXmlRead(xmlSecKeyValueDhPtr data, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(node != NULL, -1); cur = xmlSecGetNextElementNode(node->children); /* first is P node. It is OPTIONAL */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDHP, xmlSecEncNs))) { ret = xmlSecBufferBase64NodeContentRead(&(data->p), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(p)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* next is Q node. It is OPTIONAL */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDHQ, xmlSecEncNs))) { ret = xmlSecBufferBase64NodeContentRead(&(data->q), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(q)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* next is Generator node. It is OPTIONAL */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDHGenerator, xmlSecEncNs))) { ret = xmlSecBufferBase64NodeContentRead(&(data->generator), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(generator)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* next is Public node. It is REQUIRED */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDHPublic, xmlSecEncNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeDHPublic, NULL); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(data->public), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(public)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* next is seed node. It is OPTIONAL */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDHSeed, xmlSecEncNs))) { ret = xmlSecBufferBase64NodeContentRead(&(data->seed), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(seed)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* next is pgenCounter node. It is OPTIONAL */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDHPgenCounter, xmlSecEncNs))) { ret = xmlSecBufferBase64NodeContentRead(&(data->pgenCounter), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(pgenCounter)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } /* nothing else is expected */ if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* success */ return(0); } static int xmlSecKeyValueDhXmlWrite(xmlSecKeyValueDhPtr data, xmlNodePtr node, int base64LineSize, int addLineBreaks) { xmlNodePtr cur; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(node != NULL, -1); /* first is optional P node */ if(xmlSecBufferGetSize(&(data->p)) > 0) { cur = xmlSecAddChild(node, xmlSecNodeDHP, xmlSecEncNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(NodeDHP)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->p), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(p)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } } /* next is optional Q node. */ if(xmlSecBufferGetSize(&(data->q)) > 0) { cur = xmlSecAddChild(node, xmlSecNodeDHQ, xmlSecEncNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(NodeDHQ)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->q), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(q)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } } /* next is optional Generator node. */ if(xmlSecBufferGetSize(&(data->generator)) > 0) { cur = xmlSecAddChild(node, xmlSecNodeDHGenerator, xmlSecEncNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(NodeDHGenerator)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->generator), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(g)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } } /* next is required Public node. */ cur = xmlSecAddChild(node, xmlSecNodeDHPublic, xmlSecEncNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(xmlSecNodeDHPublic)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->public), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(g)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } /* next is optional seed node. */ if(xmlSecBufferGetSize(&(data->seed)) > 0) { cur = xmlSecAddChild(node, xmlSecNodeDHSeed, xmlSecEncNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(xmlSecNodeDHSeed)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->seed), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(g)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } } /* next is optional pgenCounter node. */ if(xmlSecBufferGetSize(&(data->pgenCounter)) > 0) { cur = xmlSecAddChild(node, xmlSecNodeDHPgenCounter, xmlSecEncNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(xmlSecNodeDHPgenCounter)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->pgenCounter), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(g)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } } /* success */ return(0); } #endif /* !defined(XMLSEC_NO_DH) */ #if !defined(XMLSEC_NO_DSA) /****************************************************************************** * * Helper functions to read/write DSA keys * *****************************************************************************/ #define XMLSEC_KEY_DATA_DSA_INIT_BUF_SIZE 512 static int xmlSecKeyValueDsaInitialize (xmlSecKeyValueDsaPtr data); static void xmlSecKeyValueDsaFinalize (xmlSecKeyValueDsaPtr data); static int xmlSecKeyValueDsaXmlRead (xmlSecKeyValueDsaPtr data, xmlNodePtr node); static int xmlSecKeyValueDsaXmlWrite (xmlSecKeyValueDsaPtr data, xmlNodePtr node, int writePrivateKey, int base64LineSize, int addLineBreaks); /** * @brief DSA Key data method for reading XML node. * @param id the data id. * @param key the key. * @param node the pointer to data's value XML node. * @param keyInfoCtx the <dsig:KeyInfo/> node processing context. * @param readFunc the pointer to the function that converts * xmlSecKeyValueDsa to xmlSecKeyData. * * @return 0 on success or a negative value if an error occurs. */ int xmlSecKeyDataDsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx, xmlSecKeyDataDsaRead readFunc) { xmlSecKeyDataPtr data = NULL; xmlSecKeyValueDsa dsaValue; int dsaDataInitialized = 0; int res = -1; int ret; xmlSecAssert2(id != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecAssert2(readFunc != NULL, -1); if(xmlSecKeyGetValue(key) != NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_KEY_DATA, xmlSecKeyDataKlassGetName(id), "key already has a value"); goto done; } ret = xmlSecKeyValueDsaInitialize(&dsaValue); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueDsaInitialize", xmlSecKeyDataKlassGetName(id)); goto done; } dsaDataInitialized = 1; ret = xmlSecKeyValueDsaXmlRead(&dsaValue, node); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueDsaXmlRead", xmlSecKeyDataKlassGetName(id)); goto done; } data = readFunc(id, &dsaValue); if(data == NULL) { xmlSecInternalError("xmlSecKeyDataDsaRead", xmlSecKeyDataKlassGetName(id)); goto done; } /* set key value */ ret = xmlSecKeySetValue(key, data); if(ret < 0) { xmlSecInternalError("xmlSecKeySetValue", xmlSecKeyDataGetName(data)); goto done; } data = NULL; /* data is owned by key now */ /* success */ res = 0; done: /* cleanup */ if(dsaDataInitialized != 0) { xmlSecKeyValueDsaFinalize(&dsaValue); } if(data != NULL) { xmlSecKeyDataDestroy(data); } return(res); } /** * @brief DSA Key data method for writing XML node. * @param id the data id. * @param key the key. * @param node the pointer to data's value XML node. * @param keyInfoCtx the <dsig:KeyInfo/> node processing context. * @param base64LineSize the base64 max line size. * @param addLineBreaks the flag indicating if we need to add line breaks around base64 output. * @param writeFunc the pointer to the function that converts * xmlSecKeyData to xmlSecKeyValueDsa. * * @return 0 on success or a negative value if an error occurs. */ int xmlSecKeyDataDsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx, int base64LineSize, int addLineBreaks, xmlSecKeyDataDsaWrite writeFunc) { xmlSecKeyDataPtr data; xmlSecKeyValueDsa dsaValue; int dsaDataInitialized = 0; int writePrivateKey = 0; int res = -1; int ret; xmlSecAssert2(id != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecAssert2(writeFunc != NULL, -1); xmlSecAssert2(base64LineSize > 0, -1); if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { /* we can have only private key or public key */ return(0); } if((keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePrivate) != 0) { writePrivateKey = 1; } data = xmlSecKeyGetValue(key); if(data == NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_KEY_DATA, xmlSecKeyDataKlassGetName(id), "key has no value"); goto done; } ret = xmlSecKeyValueDsaInitialize(&dsaValue); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueDsaInitialize", xmlSecKeyDataKlassGetName(id)); goto done; } dsaDataInitialized = 1; ret = writeFunc(id, data, &dsaValue, writePrivateKey); if(ret < 0) { xmlSecInternalError("xmlSecKeyDataDsaWrite", xmlSecKeyDataKlassGetName(id)); goto done; } ret = xmlSecKeyValueDsaXmlWrite(&dsaValue, node, writePrivateKey, base64LineSize, addLineBreaks); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueDsaXmlWrite", xmlSecKeyDataKlassGetName(id)); goto done; } /* success */ res = 0; done: /* cleanup */ if(dsaDataInitialized != 0) { xmlSecKeyValueDsaFinalize(&dsaValue); } return(res); } static int xmlSecKeyValueDsaInitialize(xmlSecKeyValueDsaPtr data) { int ret; xmlSecAssert2(data != NULL, -1); memset(data, 0, sizeof(xmlSecKeyValueDsa)); ret = xmlSecBufferInitialize(&(data->p), XMLSEC_KEY_DATA_DSA_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(p)", NULL); xmlSecKeyValueDsaFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->q), XMLSEC_KEY_DATA_DSA_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(q)", NULL); xmlSecKeyValueDsaFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->g), XMLSEC_KEY_DATA_DSA_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(g)", NULL); xmlSecKeyValueDsaFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->x), XMLSEC_KEY_DATA_DSA_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(x)", NULL); xmlSecKeyValueDsaFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->y), XMLSEC_KEY_DATA_DSA_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(y)", NULL); xmlSecKeyValueDsaFinalize(data); return(-1); } return(0); } static void xmlSecKeyValueDsaFinalize(xmlSecKeyValueDsaPtr data) { xmlSecAssert(data != NULL); xmlSecBufferFinalize(&(data->p)); xmlSecBufferFinalize(&(data->q)); xmlSecBufferFinalize(&(data->g)); xmlSecBufferFinalize(&(data->x)); xmlSecBufferFinalize(&(data->y)); memset(data, 0, sizeof(xmlSecKeyValueDsa)); } static int xmlSecKeyValueDsaXmlRead(xmlSecKeyValueDsaPtr data, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(node != NULL, -1); cur = xmlSecGetNextElementNode(node->children); /* first is P node. It is REQUIRED because we do not support Seed and PgenCounter*/ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAP, xmlSecDSigNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeDSAP, NULL); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(data->p), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(p)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* next is Q node. It is REQUIRED because we do not support Seed and PgenCounter*/ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAQ, xmlSecDSigNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeDSAQ, NULL); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(data->q), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(q)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* next is G node. It is REQUIRED because we do not support Seed and PgenCounter*/ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAG, xmlSecDSigNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeDSAG, NULL); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(data->g), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(g)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAX, xmlSecNs))) { /* next is X node. It is REQUIRED for private key but * we are not sure exactly what do we read */ ret = xmlSecBufferBase64NodeContentRead(&(data->x), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(x)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } else { /* make sure it's empty */ ret = xmlSecBufferSetSize(&(data->x), 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetSize(0)", NULL); return(-1); } } /* next is Y node. */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAY, xmlSecDSigNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeDSAY, NULL); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(data->y), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(y)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAJ, xmlSecDSigNs))) { xmlSecNotImplementedError("DSA key value J parameter is not supported"); cur = xmlSecGetNextElementNode(cur->next); } if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSASeed, xmlSecDSigNs))) { xmlSecNotImplementedError("DSA key value seed parameter is not supported"); cur = xmlSecGetNextElementNode(cur->next); } if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAPgenCounter, xmlSecDSigNs))) { xmlSecNotImplementedError("DSA key value pgencounter parameter is not supported"); cur = xmlSecGetNextElementNode(cur->next); } if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* success */ return(0); } static int xmlSecKeyValueDsaXmlWrite(xmlSecKeyValueDsaPtr data, xmlNodePtr node, int writePrivateKey, int base64LineSize, int addLineBreaks) { xmlNodePtr cur; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(node != NULL, -1); /* first is P node */ cur = xmlSecAddChild(node, xmlSecNodeDSAP, xmlSecDSigNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(NodeDSAP)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->p), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(p)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } /* next is Q node. */ cur = xmlSecAddChild(node, xmlSecNodeDSAQ, xmlSecDSigNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(NodeDSAQ)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->q), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(q)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } /* next is G node. */ cur = xmlSecAddChild(node, xmlSecNodeDSAG, xmlSecDSigNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(NodeDSAG)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->g), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(g)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } /* next is X node: write it ONLY for private keys and ONLY if it is requested */ if((writePrivateKey != 0) && (xmlSecBufferGetSize(&(data->x)) > 0)) { cur = xmlSecAddChild(node, xmlSecNodeDSAX, xmlSecNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(NodeDSAX)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->x), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(x)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } } /* next is Y node. */ cur = xmlSecAddChild(node, xmlSecNodeDSAY, xmlSecDSigNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(NodeDSAY)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->y), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(y)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } return(0); } #endif /* !defined(XMLSEC_NO_DSA) */ #if !defined(XMLSEC_NO_RSA) /****************************************************************************** * * Helper functions to read/write RSA keys * *****************************************************************************/ #define XMLSEC_KEY_DATA_RSA_INIT_BUF_SIZE 512 static int xmlSecKeyValueRsaInitialize (xmlSecKeyValueRsaPtr data); static void xmlSecKeyValueRsaFinalize (xmlSecKeyValueRsaPtr data); static int xmlSecKeyValueRsaXmlRead (xmlSecKeyValueRsaPtr data, xmlNodePtr node); static int xmlSecKeyValueRsaXmlWrite (xmlSecKeyValueRsaPtr data, xmlNodePtr node, int writePrivateKey, int base64LineSize, int addLineBreaks); /** * @brief RSA Key data method for reading XML node. * @param id the data id. * @param key the key. * @param node the pointer to data's value XML node. * @param keyInfoCtx the <dsig:KeyInfo/> node processing context. * @param readFunc the pointer to the function that converts * xmlSecKeyValueRsa to xmlSecKeyData. * * @return 0 on success or a negative value if an error occurs. */ int xmlSecKeyDataRsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx, xmlSecKeyDataRsaRead readFunc) { xmlSecKeyDataPtr data = NULL; xmlSecKeyValueRsa rsaValue; int rsaDataInitialized = 0; int res = -1; int ret; xmlSecAssert2(id != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecAssert2(readFunc != NULL, -1); if(xmlSecKeyGetValue(key) != NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_KEY_DATA, xmlSecKeyDataKlassGetName(id), "key already has a value"); goto done; } ret = xmlSecKeyValueRsaInitialize(&rsaValue); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueRsaInitialize", xmlSecKeyDataKlassGetName(id)); goto done; } rsaDataInitialized = 1; ret = xmlSecKeyValueRsaXmlRead(&rsaValue, node); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueRsaXmlRead", xmlSecKeyDataKlassGetName(id)); goto done; } data = readFunc(id, &rsaValue); if(data == NULL) { xmlSecInternalError("xmlSecKeyDataRsaRead", xmlSecKeyDataKlassGetName(id)); goto done; } /* set key value */ ret = xmlSecKeySetValue(key, data); if(ret < 0) { xmlSecInternalError("xmlSecKeySetValue", xmlSecKeyDataGetName(data)); goto done; } data = NULL; /* data is owned by key now */ /* success */ res = 0; done: /* cleanup */ if(rsaDataInitialized != 0) { xmlSecKeyValueRsaFinalize(&rsaValue); } if(data != NULL) { xmlSecKeyDataDestroy(data); } return(res); } /** * @brief RSA Key data method for writing XML node. * @param id the data id. * @param key the key. * @param node the pointer to data's value XML node. * @param keyInfoCtx the <dsig:KeyInfo/> node processing context. * @param base64LineSize the base64 max line size. * @param addLineBreaks the flag indicating if we need to add line breaks around base64 output. * @param writeFunc the pointer to the function that converts * xmlSecKeyData to xmlSecKeyValueRsa. * * @return 0 on success or a negative value if an error occurs. */ int xmlSecKeyDataRsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx, int base64LineSize, int addLineBreaks, xmlSecKeyDataRsaWrite writeFunc) { xmlSecKeyDataPtr data; xmlSecKeyValueRsa rsaValue; int rsaDataInitialized = 0; int writePrivateKey = 0; int res = -1; int ret; xmlSecAssert2(id != NULL, -1); xmlSecAssert2(key != NULL, -1); xmlSecAssert2(node != NULL, -1); xmlSecAssert2(keyInfoCtx != NULL, -1); xmlSecAssert2(writeFunc != NULL, -1); xmlSecAssert2(base64LineSize > 0, -1); if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { /* we can only write private key or public key */ return(0); } if((keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePrivate) != 0) { writePrivateKey = 1; } data = xmlSecKeyGetValue(key); if(data == NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_KEY_DATA, xmlSecKeyDataKlassGetName(id), "key has no value"); goto done; } ret = xmlSecKeyValueRsaInitialize(&rsaValue); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueRsaInitialize", xmlSecKeyDataKlassGetName(id)); goto done; } rsaDataInitialized = 1; ret = writeFunc(id, data, &rsaValue, writePrivateKey); if(ret < 0) { xmlSecInternalError("xmlSecKeyDataRsaWrite", xmlSecKeyDataKlassGetName(id)); goto done; } ret = xmlSecKeyValueRsaXmlWrite(&rsaValue, node, writePrivateKey, base64LineSize, addLineBreaks); if(ret < 0) { xmlSecInternalError("xmlSecKeyValueRsaXmlWrite", xmlSecKeyDataKlassGetName(id)); goto done; } /* success */ res = 0; done: /* cleanup */ if(rsaDataInitialized != 0) { xmlSecKeyValueRsaFinalize(&rsaValue); } return(res); } static int xmlSecKeyValueRsaInitialize(xmlSecKeyValueRsaPtr data) { int ret; xmlSecAssert2(data != NULL, -1); memset(data, 0, sizeof(xmlSecKeyValueRsa)); ret = xmlSecBufferInitialize(&(data->modulus), XMLSEC_KEY_DATA_RSA_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(modulus)", NULL); xmlSecKeyValueRsaFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->publicExponent), XMLSEC_KEY_DATA_RSA_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(q)", NULL); xmlSecKeyValueRsaFinalize(data); return(-1); } ret = xmlSecBufferInitialize(&(data->privateExponent), XMLSEC_KEY_DATA_RSA_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(g)", NULL); xmlSecKeyValueRsaFinalize(data); return(-1); } return(0); } static void xmlSecKeyValueRsaFinalize(xmlSecKeyValueRsaPtr data) { xmlSecAssert(data != NULL); xmlSecBufferFinalize(&(data->modulus)); xmlSecBufferFinalize(&(data->publicExponent)); xmlSecBufferFinalize(&(data->privateExponent)); memset(data, 0, sizeof(xmlSecKeyValueRsa)); } static int xmlSecKeyValueRsaXmlRead(xmlSecKeyValueRsaPtr data, xmlNodePtr node) { xmlNodePtr cur; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(node != NULL, -1); cur = xmlSecGetNextElementNode(node->children); /* first is REQUIRED Modulus node. */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAModulus, xmlSecDSigNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeDSAP, NULL); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(data->modulus), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(p)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* next is REQUIRED Exponent node. */ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAExponent, xmlSecDSigNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeDSAQ, NULL); return(-1); } ret = xmlSecBufferBase64NodeContentRead(&(data->publicExponent), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(q)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); /* next is PrivateExponent node. It is REQUIRED for private key but * we are not sure exactly what are we reading */ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeRSAPrivateExponent, xmlSecNs))) { ret = xmlSecBufferBase64NodeContentRead(&(data->privateExponent), cur); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentRead(x)", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); } else { /* make sure it's empty */ ret = xmlSecBufferSetSize(&(data->privateExponent), 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetSize(0)", NULL); return(-1); } } if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } /* success */ return(0); } static int xmlSecKeyValueRsaXmlWrite(xmlSecKeyValueRsaPtr data, xmlNodePtr node, int writePrivateKey, int base64LineSize, int addLineBreaks) { xmlNodePtr cur; int ret; xmlSecAssert2(data != NULL, -1); xmlSecAssert2(node != NULL, -1); /* first is Modulus node */ cur = xmlSecAddChild(node, xmlSecNodeRSAModulus, xmlSecDSigNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(Modulus)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->modulus), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(modulus)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } /* next is Exponent node. */ cur = xmlSecAddChild(node, xmlSecNodeRSAExponent, xmlSecDSigNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(Exponent)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->publicExponent), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(exponent)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } /* next is PrivateExponent node: write it ONLY for private keys and ONLY if it is requested */ if((writePrivateKey != 0) && (xmlSecBufferGetSize(&(data->privateExponent)) > 0)) { cur = xmlSecAddChild(node, xmlSecNodeRSAPrivateExponent, xmlSecNs); if(cur == NULL) { xmlSecInternalError("xmlSecAddChild(PrivateExponent)", NULL); return(-1); } if(addLineBreaks) { xmlNodeSetContent(cur, xmlSecGetDefaultLineFeed()); } else { xmlNodeSetContent(cur, xmlSecStringEmpty); } ret = xmlSecBufferBase64NodeContentWrite(&(data->privateExponent), cur, base64LineSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferBase64NodeContentWrite(privateExponent)", NULL); return(-1); } if(addLineBreaks) { xmlNodeAddContent(cur, xmlSecGetDefaultLineFeed()); } } return(0); } #endif /* !defined(XMLSEC_NO_RSA) */ /****************************************************************************** * * xmlSecKeyDataKAM klass - internal cache for key agreement params * * Holds the originator and recipient keys after a successful Execute so that * the write path can reuse them without re-parsing the AgreementMethod node. * *****************************************************************************/ /** @brief Size of the internal xmlSecKeyDataKAM struct. */ #define xmlSecKeyDataKAMSize (sizeof(xmlSecKeyDataKAM)) static int xmlSecKeyDataKAMInitialize (xmlSecKeyDataPtr data); static int xmlSecKeyDataKAMDuplicate (xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src); static void xmlSecKeyDataKAMFinalize (xmlSecKeyDataPtr data); static xmlSecKeyDataKlass xmlSecKeyDataKAMKlass = { sizeof(xmlSecKeyDataKlass), /* xmlSecSize klassSize */ xmlSecKeyDataKAMSize, /* xmlSecSize objSize */ /* data */ BAD_CAST "ka-params", /* const xmlChar* name; */ xmlSecKeyDataUsageUnknown, /* xmlSecKeyDataUsage usage; */ NULL, /* const xmlChar* href; */ NULL, /* const xmlChar* dataNodeName; */ NULL, /* const xmlChar* dataNodeNs; */ /* constructors/destructor */ xmlSecKeyDataKAMInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ xmlSecKeyDataKAMDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ xmlSecKeyDataKAMFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ NULL, /* xmlSecKeyDataGenerateMethod generate; */ /* get info */ NULL, /* xmlSecKeyDataGetTypeMethod getType; */ NULL, /* xmlSecKeyDataGetSizeMethod getSize; */ NULL, /* DEPRECATED xmlSecKeyDataGetIdentifier getIdentifier; */ /* read/write */ NULL, /* xmlSecKeyDataXmlReadMethod xmlRead; */ NULL, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ NULL, /* xmlSecKeyDataBinReadMethod binRead; */ NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ /* debug */ xmlSecKeyDataDebugDumpImpl, /* xmlSecKeyDataDebugDumpMethod debugDump; */ xmlSecKeyDataDebugXmlDumpImpl, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ /* reserved for the future */ NULL, /* void* reserved0; */ NULL, /* void* reserved1; */ }; static int xmlSecKeyDataKAMInitialize(xmlSecKeyDataPtr data) { xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataKAMSize), -1); /* keyOriginator and keyRecipient already NULL (memory zeroed by xmlSecKeyDataCreate) */ return(0); } static int xmlSecKeyDataKAMDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { xmlSecKeyDataKAM* dstData; xmlSecKeyDataKAM* srcData; xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecKeyDataKAMSize), -1); xmlSecAssert2(xmlSecKeyDataIsValid(src), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecKeyDataKAMSize), -1); dstData = (xmlSecKeyDataKAM*)dst; srcData = (xmlSecKeyDataKAM*)src; /* copy originator key */ if(dstData->keyOriginator != NULL) { xmlSecKeyDestroy(dstData->keyOriginator); dstData->keyOriginator = NULL; } if(srcData->keyOriginator != NULL) { dstData->keyOriginator = xmlSecKeyDuplicate(srcData->keyOriginator); if(dstData->keyOriginator == NULL) { xmlSecInternalError("xmlSecKeyDuplicate(keyOriginator)", xmlSecKeyDataGetName(src)); return(-1); } } /* copy recipient key */ if(dstData->keyRecipient != NULL) { xmlSecKeyDestroy(dstData->keyRecipient); dstData->keyRecipient = NULL; } if(srcData->keyRecipient != NULL) { dstData->keyRecipient = xmlSecKeyDuplicate(srcData->keyRecipient); if(dstData->keyRecipient == NULL) { xmlSecInternalError("xmlSecKeyDuplicate(keyRecipient)", xmlSecKeyDataGetName(src)); return(-1); } } return(0); } static void xmlSecKeyDataKAMFinalize(xmlSecKeyDataPtr data) { xmlSecKeyDataKAM* kamData; xmlSecAssert(xmlSecKeyDataIsValid(data)); xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecKeyDataKAMSize)); kamData = (xmlSecKeyDataKAM*)data; if(kamData->keyOriginator != NULL) { xmlSecKeyDestroy(kamData->keyOriginator); kamData->keyOriginator = NULL; } if(kamData->keyRecipient != NULL) { xmlSecKeyDestroy(kamData->keyRecipient); kamData->keyRecipient = NULL; } } /** * @brief Returns the KA params key data klass. * @return KA params key data klass. */ xmlSecKeyDataId xmlSecKeyDataKAMGetKlass(void) { return(&xmlSecKeyDataKAMKlass); } #ifndef XMLSEC_NO_MLKEM /****************************************************************************** * * xmlSecKeyDataKEM klass - internal helper for KEM ciphertext * * Holds both the recipient key (public for encrypt, private for decrypt) and * the KEM ciphertext exchanged via enc:CipherData/enc:CipherValue. * *****************************************************************************/ #define XMLSEC_KEY_DATA_KEM_CIPHER_VALUE_INIT_BUF_SIZE 256 #define xmlSecKeyDataKEMSize (sizeof(xmlSecKeyDataKEM)) static int xmlSecKeyDataKEMInitialize (xmlSecKeyDataPtr data); static int xmlSecKeyDataKEMDuplicate (xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src); static void xmlSecKeyDataKEMFinalize (xmlSecKeyDataPtr data); static xmlSecKeyDataKlass xmlSecKeyDataKEMKlass = { sizeof(xmlSecKeyDataKlass), /* xmlSecSize klassSize */ xmlSecKeyDataKEMSize, /* xmlSecSize objSize */ /* data */ BAD_CAST "kem-cipher-value", /* const xmlChar* name; */ xmlSecKeyDataUsageUnknown, /* xmlSecKeyDataUsage usage; */ NULL, /* const xmlChar* href; */ NULL, /* const xmlChar* dataNodeName; */ NULL, /* const xmlChar* dataNodeNs; */ /* constructors/destructor */ xmlSecKeyDataKEMInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ xmlSecKeyDataKEMDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ xmlSecKeyDataKEMFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ NULL, /* xmlSecKeyDataGenerateMethod generate; */ /* get info */ NULL, /* xmlSecKeyDataGetTypeMethod getType; */ NULL, /* xmlSecKeyDataGetSizeMethod getSize; */ NULL, /* DEPRECATED xmlSecKeyDataGetIdentifier getIdentifier; */ /* read/write */ NULL, /* xmlSecKeyDataXmlReadMethod xmlRead; */ NULL, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ NULL, /* xmlSecKeyDataBinReadMethod binRead; */ NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ /* debug */ xmlSecKeyDataDebugDumpImpl, /* xmlSecKeyDataDebugDumpMethod debugDump; */ xmlSecKeyDataDebugXmlDumpImpl, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ /* reserved for the future */ NULL, /* void* reserved0; */ NULL, /* void* reserved1; */ }; static int xmlSecKeyDataKEMInitialize(xmlSecKeyDataPtr data) { xmlSecKeyDataKEM* kemData; int ret; xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataKEMSize), -1); kemData = (xmlSecKeyDataKEM*)data; /* recipientKey is already NULL since xmlSecKeyDataCreate zeroes memory */ ret = xmlSecBufferInitialize(&(kemData->ciphertext), XMLSEC_KEY_DATA_KEM_CIPHER_VALUE_INIT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(ciphertext)", xmlSecKeyDataGetName(data)); return(-1); } return(0); } static int xmlSecKeyDataKEMDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { xmlSecKeyDataKEM* dstData; xmlSecKeyDataKEM* srcData; int ret; xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecKeyDataKEMSize), -1); xmlSecAssert2(xmlSecKeyDataIsValid(src), -1); xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecKeyDataKEMSize), -1); dstData = (xmlSecKeyDataKEM*)dst; srcData = (xmlSecKeyDataKEM*)src; /* copy recipient key */ if(dstData->encapsulationKey != NULL) { xmlSecKeyDestroy(dstData->encapsulationKey); dstData->encapsulationKey = NULL; } if(srcData->encapsulationKey != NULL) { dstData->encapsulationKey = xmlSecKeyDuplicate(srcData->encapsulationKey); if(dstData->encapsulationKey == NULL) { xmlSecInternalError("xmlSecKeyDuplicate", xmlSecKeyDataGetName(src)); return(-1); } } /* copy ciphertext */ ret = xmlSecBufferSetData(&(dstData->ciphertext), xmlSecBufferGetData(&(srcData->ciphertext)), xmlSecBufferGetSize(&(srcData->ciphertext))); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetData(ciphertext)", xmlSecKeyDataGetName(src)); return(-1); } return(0); } static void xmlSecKeyDataKEMFinalize(xmlSecKeyDataPtr data) { xmlSecKeyDataKEM* kemData; xmlSecAssert(xmlSecKeyDataIsValid(data)); xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecKeyDataKEMSize)); kemData = (xmlSecKeyDataKEM*)data; if(kemData->encapsulationKey != NULL) { xmlSecKeyDestroy(kemData->encapsulationKey); kemData->encapsulationKey = NULL; } xmlSecBufferFinalize(&(kemData->ciphertext)); } /** * @brief Returns the KEM cipher value key data klass. * * @return KEM cipher value key data klass. */ xmlSecKeyDataId xmlSecKeyDataKEMGetKlass(void) { return(&xmlSecKeyDataKEMKlass); } /** * @brief Gets the recipient key from KEM cipher value key data. * @param data the pointer to KEM cipher value key data. * * @return pointer to the recipient key or NULL if not set. */ xmlSecKeyPtr xmlSecKeyDataKEMGetRecipientKey(xmlSecKeyDataPtr data) { xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecKeyDataKEMId), NULL); return(((xmlSecKeyDataKEM*)data)->encapsulationKey); } /** * @brief Gets the KEM ciphertext buffer from KEM cipher value key data. * @param data the pointer to KEM cipher value key data. * * @return pointer to the ciphertext buffer or NULL if an error occurs. */ xmlSecBufferPtr xmlSecKeyDataKEMGetCiphertext(xmlSecKeyDataPtr data) { xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecKeyDataKEMId), NULL); return(&(((xmlSecKeyDataKEM*)data)->ciphertext)); } /** * @brief Sets the KEM ciphertext in KEM cipher value key data. * @param data the pointer to KEM cipher value key data. * @param buf the pointer to the ciphertext bytes. * @param bufSize the size of the ciphertext buffer. * * @return 0 on success or a negative value if an error occurs. */ int xmlSecKeyDataKEMSetCiphertext(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecKeyDataKEMId), -1); xmlSecAssert2(buf != NULL, -1); return(xmlSecBufferSetData(&(((xmlSecKeyDataKEM*)data)->ciphertext), buf, bufSize)); } #endif /* XMLSEC_NO_MLKEM */