/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
1.3.11
src/buffer.c
730 строк
19 KB
lsh123
Added tests for XML debug output (#1134)
16 апр 2026, 00:26
Не верифицирован
16 апр 2026, 00:26
080a881
Код
Авторство
О чём код?
/** * 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. */ /** * @addtogroup xmlsec_core_buffer * @brief Binary memory buffer functions. */ #include "globals.h" #include <stdlib.h> #include <string.h> #include <ctype.h> #include <libxml/tree.h> #include <xmlsec/xmlsec.h> #include <xmlsec/xmltree.h> #include <xmlsec/base64.h> #include <xmlsec/buffer.h> #include <xmlsec/errors.h> #include "cast_helpers.h" /****************************************************************************** * * xmlSecBuffer * *****************************************************************************/ static xmlSecAllocMode gAllocMode = xmlSecAllocModeDouble; static xmlSecSize gInitialSize = 1024; /** * @brief Sets the default buffer allocation mode. * @details Sets new global default allocation mode and minimal intial size. * @param defAllocMode the new default buffer allocation mode. * @param defInitialSize the new default buffer minimal intial size. */ void xmlSecBufferSetDefaultAllocMode(xmlSecAllocMode defAllocMode, xmlSecSize defInitialSize) { xmlSecAssert(defInitialSize > 0); gAllocMode = defAllocMode; gInitialSize = defInitialSize; } /** * @brief Allocates and initializes a new memory buffer. * @details Allocates and initializes new memory buffer with given size. * Caller is responsible for calling #xmlSecBufferDestroy function * to free the buffer. * @param size the intial size. * @return pointer to newly allocated buffer or NULL if an error occurs. */ xmlSecBufferPtr xmlSecBufferCreate(xmlSecSize size) { xmlSecBufferPtr buf; int ret; buf = (xmlSecBufferPtr)xmlMalloc(sizeof(xmlSecBuffer)); if(buf == NULL) { xmlSecMallocError(sizeof(xmlSecBuffer), NULL); return(NULL); } ret = xmlSecBufferInitialize(buf, size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferInitialize", NULL, "size=" XMLSEC_SIZE_FMT, size); xmlSecBufferDestroy(buf); return(NULL); } return(buf); } /** * @brief Destroys a buffer object. * @details Destroys buffer object created with #xmlSecBufferCreate function. * @param buf the pointer to buffer object. */ void xmlSecBufferDestroy(xmlSecBufferPtr buf) { xmlSecAssert(buf != NULL); xmlSecBufferFinalize(buf); xmlFree(buf); } /** * @brief Initializes a buffer object. * @details Initializes buffer object @p buf. Caller is responsible for calling * #xmlSecBufferFinalize function to free allocated resources. * @param buf the pointer to buffer object. * @param size the initial buffer size. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferInitialize(xmlSecBufferPtr buf, xmlSecSize size) { xmlSecAssert2(buf != NULL, -1); buf->data = NULL; buf->size = buf->maxSize = 0; buf->allocMode = gAllocMode; return(xmlSecBufferSetMaxSize(buf, size)); } /** * @brief Frees resources for an initialized buffer. * @details Frees allocated resource for a buffer initialized with #xmlSecBufferInitialize * function. * @param buf the pointer to buffer object. */ void xmlSecBufferFinalize(xmlSecBufferPtr buf) { xmlSecAssert(buf != NULL); xmlSecBufferEmpty(buf); if(buf->data != 0) { xmlFree(buf->data); } buf->data = NULL; buf->size = buf->maxSize = 0; } /** * @brief Empties the buffer. * @param buf the pointer to buffer object. */ void xmlSecBufferEmpty(xmlSecBufferPtr buf) { xmlSecAssert(buf != NULL); if(buf->data != 0) { xmlSecAssert(buf->maxSize > 0); memset(buf->data, 0, buf->maxSize); } buf->size = 0; } /** * @brief Checks if the buffer is empty. * @details Checks if the @p buf is empty (@p buf is null or @p buf's data is null or @p buf's size is zero). * @param buf the pointer to buffer object. * @return 1 if buffer is empty or 0 otherwise. */ int xmlSecBufferIsEmpty(xmlSecBufferPtr buf) { return (((buf == NULL) || (buf->data == NULL) || (buf->size <= 0)) ? 1 : 0); } /** * @brief Gets pointer to buffer's data. * @param buf the pointer to buffer object. * @return pointer to buffer's data. */ xmlSecByte* xmlSecBufferGetData(xmlSecBufferPtr buf) { xmlSecAssert2(buf != NULL, NULL); return(buf->data); } /** * @brief Sets the value of the buffer to @p data. * @param buf the pointer to buffer object. * @param data the data. * @param size the data size. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferSetData(xmlSecBufferPtr buf, const xmlSecByte* data, xmlSecSize size) { int ret; xmlSecAssert2(buf != NULL, -1); xmlSecBufferEmpty(buf); if(size > 0) { xmlSecAssert2(data != NULL, -1); ret = xmlSecBufferSetMaxSize(buf, size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetMaxSize", NULL, "size=" XMLSEC_SIZE_FMT, size); return(-1); } memcpy(buf->data, data, size); } buf->size = size; return(0); } /** * @brief Gets the current buffer data size. * @param buf the pointer to buffer object. * @return the current data size. */ xmlSecSize xmlSecBufferGetSize(xmlSecBufferPtr buf) { xmlSecAssert2(buf != NULL, 0); return(buf->size); } /** * @brief Sets new buffer data size. * @details Sets new buffer data size. If necessary, buffer grows to * have at least @p size bytes. * @param buf the pointer to buffer object. * @param size the new data size. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferSetSize(xmlSecBufferPtr buf, xmlSecSize size) { int ret; xmlSecAssert2(buf != NULL, -1); ret = xmlSecBufferSetMaxSize(buf, size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetMaxSize", NULL, "size=" XMLSEC_SIZE_FMT, size); return(-1); } buf->size = size; return(0); } /** * @brief Gets the maximum (allocated) buffer size. * @param buf the pointer to buffer object. * @return the maximum (allocated) buffer size. */ xmlSecSize xmlSecBufferGetMaxSize(xmlSecBufferPtr buf) { xmlSecAssert2(buf != NULL, 0); return(buf->maxSize); } /** * @brief Sets new buffer maximum size. * @details Sets new buffer maximum size. If necessary, buffer grows to * have at least @p size bytes. * @param buf the pointer to buffer object. * @param size the new maximum size. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferSetMaxSize(xmlSecBufferPtr buf, xmlSecSize size) { xmlSecByte* newData; xmlSecSize newSize = 0; xmlSecAssert2(buf != NULL, -1); if(size <= buf->maxSize) { return(0); } switch(buf->allocMode) { case xmlSecAllocModeExact: newSize = size + 8; break; case xmlSecAllocModeDouble: newSize = 2 * size + 32; break; } if(newSize < gInitialSize) { newSize = gInitialSize; } if(buf->data != NULL) { newData = (xmlSecByte*)xmlRealloc(buf->data, newSize); } else { newData = (xmlSecByte*)xmlMalloc(newSize); } if(newData == NULL) { xmlSecMallocError(newSize, NULL); return(-1); } buf->data = newData; buf->maxSize = newSize; if(buf->size < buf->maxSize) { xmlSecAssert2(buf->data != NULL, -1); memset(buf->data + buf->size, 0, buf->maxSize - buf->size); } return(0); } #define SWAP(type, a, b) do { type tmp = (a); (a) = (b); (b) = tmp; } while (0) /** * @brief Swaps the content of the two buffers. * @param buf1 the pointer to the first buffer object. * @param buf2 the pointer to the second buffer object. */ void xmlSecBufferSwap(xmlSecBufferPtr buf1, xmlSecBufferPtr buf2) { xmlSecAssert(buf1 != NULL); xmlSecAssert(buf2 != NULL); SWAP(xmlSecByte*, buf1->data, buf2->data); SWAP(xmlSecSize, buf1->size, buf2->size); SWAP(xmlSecSize, buf1->maxSize, buf2->maxSize); SWAP(xmlSecAllocMode, buf1->allocMode, buf2->allocMode); } /** * @brief Appends data to the end of the buffer. * @details Appends the @p data after the current data stored in the buffer. * @param buf the pointer to buffer object. * @param data the data. * @param size the data size. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferAppend(xmlSecBufferPtr buf, const xmlSecByte* data, xmlSecSize size) { int ret; xmlSecAssert2(buf != NULL, -1); if(size > 0) { xmlSecAssert2(data != NULL, -1); ret = xmlSecBufferSetMaxSize(buf, buf->size + size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetMaxSize", NULL, "size=" XMLSEC_SIZE_FMT, (buf->size + size)); return(-1); } memcpy(buf->data + buf->size, data, size); buf->size += size; } return(0); } /** * @brief Prepends data to the beginning of the buffer. * @details Prepends the @p data before the current data stored in the buffer. * @param buf the pointer to buffer object. * @param data the data. * @param size the data size. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferPrepend(xmlSecBufferPtr buf, const xmlSecByte* data, xmlSecSize size) { int ret; xmlSecAssert2(buf != NULL, -1); if(size > 0) { xmlSecAssert2(data != NULL, -1); ret = xmlSecBufferSetMaxSize(buf, buf->size + size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetMaxSize", NULL, "size=" XMLSEC_SIZE_FMT, (buf->size + size)); return(-1); } memmove(buf->data + size, buf->data, buf->size); memcpy(buf->data, data, size); buf->size += size; } return(0); } /** * @brief Removes bytes from the beginning of the buffer. * @details Removes @p size bytes from the beginning of the current buffer. * @param buf the pointer to buffer object. * @param size the number of bytes to be removed. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferRemoveHead(xmlSecBufferPtr buf, xmlSecSize size) { xmlSecAssert2(buf != NULL, -1); if(size < buf->size) { xmlSecAssert2(buf->data != NULL, -1); buf->size -= size; memmove(buf->data, buf->data + size, buf->size); } else { buf->size = 0; } if(buf->size < buf->maxSize) { xmlSecAssert2(buf->data != NULL, -1); memset(buf->data + buf->size, 0, buf->maxSize - buf->size); } return(0); } /** * @brief Removes bytes from the end of the buffer. * @details Removes @p size bytes from the end of current buffer. * @param buf the pointer to buffer object. * @param size the number of bytes to be removed. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferRemoveTail(xmlSecBufferPtr buf, xmlSecSize size) { xmlSecAssert2(buf != NULL, -1); if(size < buf->size) { buf->size -= size; } else { buf->size = 0; } if(buf->size < buf->maxSize) { xmlSecAssert2(buf->data != NULL, -1); memset(buf->data + buf->size, 0, buf->maxSize - buf->size); } return(0); } /** * @brief Reverses order of bytes in the buffer @p buf. * @param buf the pointer to buffer object. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferReverse(xmlSecBufferPtr buf) { xmlSecByte* pp; xmlSecByte* qq; xmlSecSize size; xmlSecByte ch; xmlSecAssert2(buf != NULL, -1); /* trivial case */ size = xmlSecBufferGetSize(buf); if (size <= 1) { return(0); } pp = xmlSecBufferGetData(buf); xmlSecAssert2(pp != NULL, -1); for (qq = pp + size - 1; pp < qq; ++pp, --qq) { ch = *(pp); *(pp) = *(qq); *(qq) = ch; } return(0); } /** * @brief Reads the content of a file into the buffer. * @details Reads the content of the file @p filename in the buffer. * @param buf the pointer to buffer object. * @param filename the filename. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferReadFile(xmlSecBufferPtr buf, const char* filename) { xmlSecByte buffer[1024]; FILE* f = NULL; xmlSecSize size; size_t len; int ret; int res = -1; xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(filename != NULL, -1); #ifndef _MSC_VER f = fopen(filename, "rb"); #else fopen_s(&f, filename, "rb"); #endif /* _MSC_VER */ if(f == NULL) { xmlSecIOError("fopen", filename, NULL); goto done; } while(!feof(f)) { len = fread(buffer, 1, sizeof(buffer), f); if(ferror(f)) { xmlSecIOError("fread", filename, NULL); goto done; } XMLSEC_SAFE_CAST_SIZE_T_TO_SIZE(len, size, goto done, NULL); ret = xmlSecBufferAppend(buf, buffer, size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferAppend", NULL, "size=" XMLSEC_SIZE_T_FMT, len); goto done; } } /* success */ res = 0; done: if(f != NULL) { fclose(f); } return(res); } /** * @brief Reads and base64-decodes a node's content into the buffer. * @details Reads the content of the @p node, base64 decodes it and stores the * result in the buffer. * @param buf the pointer to buffer object. * @param node the pointer to node. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferBase64NodeContentRead(xmlSecBufferPtr buf, xmlNodePtr node) { xmlChar* content = NULL; xmlSecSize outWritten; int ret; int res = -1; xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(node != NULL, -1); content = xmlSecGetNodeContentAndTrim(node); if(content == NULL) { xmlSecInvalidNodeContentError(node, NULL, "empty"); goto done; } /* base64 decode size is less than input size */ ret = xmlSecBufferSetMaxSize(buf, xmlSecStrlen(content)); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetMaxSize", NULL); goto done; } ret = xmlSecBase64Decode_ex(content, xmlSecBufferGetData(buf), xmlSecBufferGetMaxSize(buf), &outWritten); if(ret < 0) { xmlSecInternalError("xmlSecBase64Decode_ex", NULL); goto done; } ret = xmlSecBufferSetSize(buf, outWritten); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetSize", NULL, "size=" XMLSEC_SIZE_FMT, outWritten); goto done; } /* success */ res = 0; done: if(content != NULL) { xmlFree(content); } return(res); } /** * @brief Sets node content to the base64-encoded buffer data. * @details Sets the content of the @p node to the base64 encoded buffer data. * @param buf the pointer to buffer object. * @param node the pointer to a node. * @param columns the max line size for base64 encoded data. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferBase64NodeContentWrite(xmlSecBufferPtr buf, xmlNodePtr node, int columns) { xmlChar* content; xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(node != NULL, -1); content = xmlSecBase64Encode(xmlSecBufferGetData(buf), xmlSecBufferGetSize(buf), columns); if(content == NULL) { xmlSecInternalError("xmlSecBase64Encode", NULL); return(-1); } xmlNodeAddContent(node, content); xmlFree(content); return(0); } /** * @brief Reads hex-encoded string into the buffer. * @details Reads content of hex encoded @p hexStr into @p buf. * @param buf the pointer to buffer object. * @param hexStr the hex string. * @return 0 on success or a negative value if an error occurs. */ int xmlSecBufferHexRead(xmlSecBufferPtr buf, const xmlChar* hexStr) { xmlSecSize hexStrSize, bufSize; xmlSecByte * data; xmlChar ch1, ch2; int ret; xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(hexStr != NULL, -1); /* trivial case */ hexStrSize = xmlSecStrlen(hexStr); if(hexStrSize <= 0) { xmlSecBufferEmpty(buf); return(0); } /* we expect each byte to be represented by 2 chars */ if((hexStrSize % 2) != 0) { xmlSecInvalidSizeDataError("hexStrSize", hexStrSize, "even", NULL); return(-1); } bufSize = hexStrSize / 2; ret = xmlSecBufferSetSize(buf, bufSize); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetSize", NULL, "bufSize=" XMLSEC_SIZE_FMT, bufSize); return (-1); } data = xmlSecBufferGetData(buf); xmlSecAssert2(data != NULL, -1); for( ; (*hexStr) != '\0'; ++data) { ch1 = *(hexStr++); ch2 = *(hexStr++); if(!xmlSecIsHex(ch1) || !xmlSecIsHex(ch2)) { xmlSecInvalidDataError("Unexpected character (not hex)", NULL); return (-1); } (*data) = xmlSecFromHex2(ch1, ch2); } /* sucess */ return(0); } /** * @brief Writes the content of the buffer as hex string to the output. * @details Writes the content of the @p buf as hex string to the @p output (no more than 32 bytes per line). * @param buf the pointer to buffer object. * @param output the pointer to output FILE. */ void xmlSecBufferDebugHexDump(xmlSecBufferPtr buf, FILE* output) { const xmlSecByte * data; xmlSecSize ii, size; xmlSecAssert(buf != NULL); xmlSecAssert(output != NULL); data = xmlSecBufferGetData(buf); size = xmlSecBufferGetSize(buf); for(ii = 0; ii < size; ++ii) { fprintf(output, "%02x", data[ii]); if((ii + 1) % 32 == 0) { fprintf(output, "\n"); } } } /****************************************************************************** * * IO buffer * *****************************************************************************/ static int xmlSecBufferIOWrite (xmlSecBufferPtr buf, const xmlSecByte *data, int len); static int xmlSecBufferIOClose (xmlSecBufferPtr buf); /** * @brief Creates a LibXML output buffer to store data in @p buf. * @details Creates new LibXML output buffer to store data in the @p buf. Caller is * responsible for destroying @p buf when processing is done. * @param buf the pointer to buffer. * @return pointer to newly allocated output buffer or NULL if an error * occurs. */ xmlOutputBufferPtr xmlSecBufferCreateOutputBuffer(xmlSecBufferPtr buf) { return(xmlOutputBufferCreateIO((xmlOutputWriteCallback)xmlSecBufferIOWrite, (xmlOutputCloseCallback)xmlSecBufferIOClose, buf, NULL)); } static int xmlSecBufferIOWrite(xmlSecBufferPtr buf, const xmlSecByte *data, int len) { xmlSecSize size; int ret; xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(data != NULL, -1); xmlSecAssert2(len >= 0, -1); XMLSEC_SAFE_CAST_INT_TO_SIZE(len, size, return(-1), NULL); ret = xmlSecBufferAppend(buf, data, size); if(ret < 0) { xmlSecInternalError2("xmlSecBufferAppend", NULL, "size=" XMLSEC_SIZE_FMT, size); return(-1); } /* we appended the whole input buffer */ return(len); } static int xmlSecBufferIOClose(xmlSecBufferPtr buf) { xmlSecAssert2(buf != NULL, -1); /* just do nothing */ return(0); }