/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
1.3.7
src/base64.c
958 строк
32 KB
lsh123
Update copyright (#817)
12 июл 2024, 17:09
Не верифицирован
12 июл 2024, 17:09
c1f4524
Код
Авторство
О чём код?
/* * XML Security Library (http://www.aleksey.com/xmlsec). * * * This is free software; see Copyright file in the source * distribution for preciese wording. * * Copyright (C) 2002-2024 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. */ /** * SECTION:base64 * @Short_description: Base64 encoding/decoding functions and base64 transform implementation. * @Stability: Stable * */ #include "globals.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #include <libxml/tree.h> #include <xmlsec/xmlsec.h> #include <xmlsec/keys.h> #include <xmlsec/transforms.h> #include <xmlsec/base64.h> #include <xmlsec/errors.h> #include "cast_helpers.h" /* * the table to map numbers to base64 */ static const xmlSecByte base64[] = { /* 0 1 2 3 4 5 6 7 */ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 0 */ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 1 */ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 2 */ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 3 */ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 4 */ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 5 */ 'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 6 */ '4', '5', '6', '7', '8', '9', '+', '/' /* 7 */ }; /* few macros to simplify the code */ #define xmlSecBase64Encode1(a) (((a) >> 2) & 0x3F) #define xmlSecBase64Encode2(a, b) ((((a) << 4) & 0x30) + (((b) >> 4) & 0x0F)) #define xmlSecBase64Encode3(b, c) ((((b) << 2) & 0x3c) + (((c) >> 6) & 0x03)) #define xmlSecBase64Encode4(c) ((c) & 0x3F) #define xmlSecBase64Decode1(a, b) ((xmlSecByte)(((a) << 2) | (((b) & 0x3F) >> 4))) #define xmlSecBase64Decode2(b, c) ((xmlSecByte)(((b) << 4) | (((c) & 0x3F) >> 2))) #define xmlSecBase64Decode3(c, d) ((xmlSecByte)(((c) << 6) | ((d) & 0x3F))) #define xmlSecIsBase64Char(ch) ((((ch) >= 'A') && ((ch) <= 'Z')) || \ (((ch) >= 'a') && ((ch) <= 'z')) || \ (((ch) >= '0') && ((ch) <= '9')) || \ ((ch) == '+') || ((ch) == '/')) #define xmlSecIsBase64Space(ch) (((ch) == ' ') || ((ch) == '\t') || \ ((ch) == '\x0d') || ((ch) == '\x0a')) /*********************************************************************** * * Base64 Context * ***********************************************************************/ typedef enum { xmlSecBase64StatusConsumeAndNext = 0, xmlSecBase64StatusConsumeAndRepeat, xmlSecBase64StatusNext, xmlSecBase64StatusDone, xmlSecBase64StatusFailed } xmlSecBase64Status; struct _xmlSecBase64Ctx { int encode; xmlSecSize columns; int inByte; xmlSecSize inPos; xmlSecSize linePos; int finished; }; static xmlSecBase64Status xmlSecBase64CtxEncodeByte (xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte); static xmlSecBase64Status xmlSecBase64CtxEncodeByteFinal (xmlSecBase64CtxPtr ctx, xmlSecByte* outByte); static xmlSecBase64Status xmlSecBase64CtxDecodeByte (xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte); static int xmlSecBase64CtxEncode (xmlSecBase64CtxPtr ctx, const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize, xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize); static int xmlSecBase64CtxEncodeFinal (xmlSecBase64CtxPtr ctx, xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize); static int xmlSecBase64CtxDecode (xmlSecBase64CtxPtr ctx, const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize, xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize); static int xmlSecBase64CtxDecodeIsFinished (xmlSecBase64CtxPtr ctx); static int g_xmlsec_base64_default_line_size = XMLSEC_BASE64_LINESIZE; /** * xmlSecBase64GetDefaultLineSize: * * Gets the current default line size. * * Returns: the current default line size. */ int xmlSecBase64GetDefaultLineSize(void) { return g_xmlsec_base64_default_line_size; } /** * xmlSecBase64SetDefaultLineSize: * @columns: number of columns * * Sets the current default line size. */ void xmlSecBase64SetDefaultLineSize(int columns) { g_xmlsec_base64_default_line_size = columns; } /** * xmlSecBase64CtxCreate: * @encode: the encode/decode flag (1 - encode, 0 - decode) * @columns: the max line length. * * Allocates and initializes new base64 context. * * Returns: a pointer to newly created #xmlSecBase64Ctx structure * or NULL if an error occurs. */ xmlSecBase64CtxPtr xmlSecBase64CtxCreate(int encode, int columns) { xmlSecBase64CtxPtr ctx; int ret; /* * Allocate a new xmlSecBase64CtxPtr and fill the fields. */ ctx = (xmlSecBase64CtxPtr) xmlMalloc(sizeof(xmlSecBase64Ctx)); if (ctx == NULL) { xmlSecMallocError(sizeof(xmlSecBase64Ctx), NULL); return(NULL); } ret = xmlSecBase64CtxInitialize(ctx, encode, columns); if(ret < 0) { xmlSecInternalError("xmlSecBase64CtxInitialize", NULL); xmlSecBase64CtxDestroy(ctx); return(NULL); } return(ctx); } /** * xmlSecBase64CtxDestroy: * @ctx: the pointer to #xmlSecBase64Ctx structure. * * Destroys base64 context. */ void xmlSecBase64CtxDestroy(xmlSecBase64CtxPtr ctx) { xmlSecAssert(ctx != NULL); xmlSecBase64CtxFinalize(ctx); xmlFree(ctx); } /** * xmlSecBase64CtxInitialize: * @ctx: the pointer to #xmlSecBase64Ctx structure, * @encode: the encode/decode flag (1 - encode, 0 - decode) * @columns: the max line length. * * Initializes new base64 context. * * Returns: 0 on success and a negative value otherwise. */ int xmlSecBase64CtxInitialize(xmlSecBase64CtxPtr ctx, int encode, int columns) { xmlSecAssert2(ctx != NULL, -1); memset(ctx, 0, sizeof(xmlSecBase64Ctx)); ctx->encode = encode; XMLSEC_SAFE_CAST_INT_TO_SIZE(columns, ctx->columns, return(-1), NULL); return(0); } /** * xmlSecBase64CtxFinalize: * @ctx: the pointer to #xmlSecBase64Ctx structure, * * Frees all the resources allocated by @ctx. */ void xmlSecBase64CtxFinalize(xmlSecBase64CtxPtr ctx) { xmlSecAssert(ctx != NULL); memset(ctx, 0, sizeof(xmlSecBase64Ctx)); } /** * xmlSecBase64CtxUpdate_ex: * @ctx: the pointer to #xmlSecBase64Ctx structure * @in: the input buffer * @inSize: the input buffer size * @out: the output buffer * @outSize: the output buffer size * @outWritten: the pointer to store the number of bytes written into the output * * Encodes or decodes the next piece of data from input buffer. * * Returns: 0 on success and a negative value otherwise. */ int xmlSecBase64CtxUpdate_ex(xmlSecBase64CtxPtr ctx, const xmlSecByte *in, xmlSecSize inSize, xmlSecByte *out, xmlSecSize outSize, xmlSecSize* outWritten) { xmlSecSize inRead = 0; int ret; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(in != NULL, -1); xmlSecAssert2(out != NULL, -1); xmlSecAssert2(outWritten != NULL, -1); if(ctx->encode != 0) { ret = xmlSecBase64CtxEncode(ctx, in, inSize, &inRead, out, outSize, outWritten); if((ret < 0) || (inRead != inSize)) { xmlSecInternalError("xmlSecBase64CtxEncode", NULL); return(-1); } } else { ret = xmlSecBase64CtxDecode(ctx, in, inSize, &inRead, out, outSize, outWritten); if((ret < 0) || (inRead != inSize)) { xmlSecInternalError("xmlSecBase64CtxDecode", NULL); return(-1); } } return(0); } /** * xmlSecBase64CtxFinal_ex: * @ctx: the pointer to #xmlSecBase64Ctx structure * @out: the output buffer * @outSize: the output buffer size * @outWritten: the pointer to store the number of bytes written into the output * * Encodes or decodes the last piece of data stored in the context * and finalizes the result. * * Returns: 0 on success and a negative value otherwise. */ int xmlSecBase64CtxFinal_ex(xmlSecBase64CtxPtr ctx, xmlSecByte *out, xmlSecSize outSize, xmlSecSize* outWritten) { xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(out != NULL, -1); xmlSecAssert2(outSize > 0, -1); xmlSecAssert2(outWritten != NULL, -1); if(ctx->encode != 0) { int ret; ret = xmlSecBase64CtxEncodeFinal(ctx, out, outSize, outWritten); if(ret < 0) { xmlSecInternalError2("xmlSecBase64CtxEncodeFinal", NULL, "outSize=" XMLSEC_SIZE_FMT, outSize); return(-1); } } else { if(!xmlSecBase64CtxDecodeIsFinished(ctx)) { xmlSecInternalError("xmlSecBase64CtxDecodeIsFinished", NULL); return(-1); } (*outWritten) = 0; } /* add \0 just in case (if we can) */ if(((*outWritten) + 1) < outSize) { out[(*outWritten)] = '\0'; } return(0); } static xmlSecBase64Status xmlSecBase64CtxEncodeByte(xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte) { xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed); xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed); if((ctx->columns > 0) && (ctx->linePos >= ctx->columns)) { (*outByte) = '\n'; ctx->linePos = 0; return(xmlSecBase64StatusConsumeAndRepeat); } else if(ctx->inPos == 0) { /* we just started new block */ (*outByte) = base64[xmlSecBase64Encode1(inByte)]; ctx->inByte = inByte; ++ctx->linePos; ++ctx->inPos; return(xmlSecBase64StatusConsumeAndNext); } else if(ctx->inPos == 1) { (*outByte) = base64[xmlSecBase64Encode2(ctx->inByte, inByte)]; ctx->inByte = inByte; ++ctx->linePos; ++ctx->inPos; return(xmlSecBase64StatusConsumeAndNext); } else if(ctx->inPos == 2) { (*outByte) = base64[xmlSecBase64Encode3(ctx->inByte, inByte)]; ctx->inByte = inByte; ++ctx->linePos; ++ctx->inPos; return(xmlSecBase64StatusConsumeAndRepeat); } else if(ctx->inPos == 3) { (*outByte) = base64[xmlSecBase64Encode4(ctx->inByte)]; ++ctx->linePos; ctx->inByte = 0; ctx->inPos = 0; return(xmlSecBase64StatusConsumeAndNext); } xmlSecInvalidSizeDataError("ctx->inPos", ctx->inPos, "0,1,2,3", NULL); return(xmlSecBase64StatusFailed); } static xmlSecBase64Status xmlSecBase64CtxEncodeByteFinal(xmlSecBase64CtxPtr ctx, xmlSecByte* outByte) { xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed); xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed); if(ctx->inPos == 0) { return(xmlSecBase64StatusDone); } else if((ctx->columns > 0) && (ctx->linePos >= ctx->columns)) { (*outByte) = '\n'; ctx->linePos = 0; return(xmlSecBase64StatusConsumeAndRepeat); } else if(ctx->finished == 0) { ctx->finished = 1; return(xmlSecBase64CtxEncodeByte(ctx, 0, outByte)); } else if(ctx->inPos < 3) { (*outByte) = '='; ++ctx->inPos; ++ctx->linePos; return(xmlSecBase64StatusConsumeAndRepeat); } else if(ctx->inPos == 3) { (*outByte) = '='; ++ctx->linePos; ctx->inPos = 0; return(xmlSecBase64StatusConsumeAndRepeat); } xmlSecInvalidSizeDataError("ctx->inPos", ctx->inPos, "0,1,2,3", NULL); return(xmlSecBase64StatusFailed); } static xmlSecBase64Status xmlSecBase64CtxDecodeByte(xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte) { xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed); xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed); if((ctx->finished != 0) && (ctx->inPos == 0)) { return(xmlSecBase64StatusDone); } if(inByte == '=') { ctx->finished = 1; if(ctx->inPos == 2) { ++ctx->inPos; return(xmlSecBase64StatusNext); } else if(ctx->inPos == 3) { ctx->inPos = 0; return(xmlSecBase64StatusNext); } else { xmlSecInvalidSizeDataError("ctx->inPos", ctx->inPos, "2,3", NULL); return(xmlSecBase64StatusFailed); } } else if(xmlSecIsBase64Space(inByte)) { return(xmlSecBase64StatusNext); } else if(!xmlSecIsBase64Char(inByte) || (ctx->finished != 0)) { xmlSecInvalidIntegerDataError("inByte", inByte, "base64 character", NULL); return(xmlSecBase64StatusFailed); } /* convert from character to position in base64 array */ if((inByte >= 'A') && (inByte <= 'Z')) { inByte = (xmlSecByte)(inByte - 'A'); } else if((inByte >= 'a') && (inByte <= 'z')) { inByte = (xmlSecByte)(26 + (inByte - 'a')); } else if((inByte >= '0') && (inByte <= '9')) { inByte = (xmlSecByte)(52 + (inByte - '0')); } else if(inByte == '+') { inByte = (xmlSecByte)62; } else if(inByte == '/') { inByte = (xmlSecByte)63; } if(ctx->inPos == 0) { ctx->inByte = inByte; ++ctx->inPos; return(xmlSecBase64StatusNext); } else if(ctx->inPos == 1) { (*outByte) = xmlSecBase64Decode1(ctx->inByte, inByte); ctx->inByte = inByte; ++ctx->inPos; return(xmlSecBase64StatusConsumeAndNext); } else if(ctx->inPos == 2) { (*outByte) = xmlSecBase64Decode2(ctx->inByte, inByte); ctx->inByte = inByte; ++ctx->inPos; return(xmlSecBase64StatusConsumeAndNext); } else if(ctx->inPos == 3) { (*outByte) = xmlSecBase64Decode3(ctx->inByte, inByte); ctx->inByte = 0; ctx->inPos = 0; return(xmlSecBase64StatusConsumeAndNext); } xmlSecInvalidSizeDataError("ctx->inPos", ctx->inPos, "0,1,2,3", NULL); return(xmlSecBase64StatusFailed); } static int xmlSecBase64CtxEncode(xmlSecBase64CtxPtr ctx, const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize, xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) { xmlSecBase64Status status = xmlSecBase64StatusNext; xmlSecSize inPos, outPos; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(inBuf != NULL, -1); xmlSecAssert2(inBufResSize != NULL, -1); xmlSecAssert2(outBuf != NULL, -1); xmlSecAssert2(outBufResSize != NULL, -1); /* encode */ for(inPos = outPos = 0; (inPos < inBufSize) && (outPos < outBufSize); ) { status = xmlSecBase64CtxEncodeByte(ctx, inBuf[inPos], &(outBuf[outPos])); switch(status) { case xmlSecBase64StatusConsumeAndNext: ++inPos; ++outPos; break; case xmlSecBase64StatusConsumeAndRepeat: ++outPos; break; case xmlSecBase64StatusNext: case xmlSecBase64StatusDone: case xmlSecBase64StatusFailed: xmlSecInternalError2("xmlSecBase64CtxEncodeByte", NULL, "status=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(status)); return(-1); } } (*inBufResSize) = inPos; (*outBufResSize) = outPos; return(0); } static int xmlSecBase64CtxEncodeFinal(xmlSecBase64CtxPtr ctx, xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) { xmlSecBase64Status status = xmlSecBase64StatusNext; xmlSecSize outPos; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(outBuf != NULL, -1); xmlSecAssert2(outBufResSize != NULL, -1); /* encode final bytes */ for(outPos = 0; (outPos < outBufSize) && (status != xmlSecBase64StatusDone); ) { status = xmlSecBase64CtxEncodeByteFinal(ctx, &(outBuf[outPos])); switch(status) { case xmlSecBase64StatusConsumeAndNext: case xmlSecBase64StatusConsumeAndRepeat: ++outPos; break; case xmlSecBase64StatusDone: break; case xmlSecBase64StatusNext: case xmlSecBase64StatusFailed: xmlSecInternalError2("xmlSecBase64CtxEncodeByteFinal", NULL, "status=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(status)); return(-1); } } if(status != xmlSecBase64StatusDone) { xmlSecInvalidSizeOtherError("invalid base64 buffer size", NULL); return(-1); } if(outPos < outBufSize) { outBuf[outPos] = '\0'; /* just in case */ } (*outBufResSize) = outPos; return(0); } static int xmlSecBase64CtxDecode(xmlSecBase64CtxPtr ctx, const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize, xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) { xmlSecBase64Status status = xmlSecBase64StatusNext; xmlSecSize inPos, outPos; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(inBuf != NULL, -1); xmlSecAssert2(inBufResSize != NULL, -1); xmlSecAssert2(outBuf != NULL, -1); xmlSecAssert2(outBufResSize != NULL, -1); /* decode */ for(inPos = outPos = 0; (inPos < inBufSize) && (outPos < outBufSize) && (status != xmlSecBase64StatusDone); ) { status = xmlSecBase64CtxDecodeByte(ctx, inBuf[inPos], &(outBuf[outPos])); switch(status) { case xmlSecBase64StatusConsumeAndNext: ++inPos; ++outPos; break; case xmlSecBase64StatusConsumeAndRepeat: ++outPos; break; case xmlSecBase64StatusNext: ++inPos; break; case xmlSecBase64StatusDone: break; case xmlSecBase64StatusFailed: xmlSecInternalError2("xmlSecBase64CtxDecodeByte", NULL, "status=" XMLSEC_ENUM_FMT, XMLSEC_ENUM_CAST(status)); return(-1); } } /* skip spaces at the end */ while((inPos < inBufSize) && xmlSecIsBase64Space(inBuf[inPos])) { ++inPos; } (*inBufResSize) = inPos; (*outBufResSize) = outPos; return(0); } static int xmlSecBase64CtxDecodeIsFinished(xmlSecBase64CtxPtr ctx) { xmlSecAssert2(ctx != NULL, -1); return((ctx->inPos == 0) ? 1 : 0); } static xmlSecSize xmlSecBase64GetEncodeSize(xmlSecSize columnsSize, xmlSecSize inSize) { xmlSecSize size; size = (4 * inSize) / 3 + 4; if(columnsSize > 0) { size += (size / columnsSize) + 4; } return(size + 1); } static xmlSecSize xmlSecBase64GetDecodeSize(xmlSecSize inSize) { return(3 * inSize / 4 + 8); } /** * xmlSecBase64Encode: * @in: the input buffer. * @inSize: the input buffer size. * @columns: the output max line length (if 0 then no line breaks * would be inserted) * * Encodes the data from input buffer and allocates the string for the result. * The caller is responsible for freeing returned buffer using * xmlFree() function. * * Returns: newly allocated string with base64 encoded data * or NULL if an error occurs. */ xmlChar* xmlSecBase64Encode(const xmlSecByte *in, xmlSecSize inSize, int columns) { xmlSecBase64Ctx ctx; int ctx_initialized = 0; xmlSecByte* ptr = NULL; xmlChar* res = NULL; xmlSecSize outSize, outUpdatedSize, outFinalSize; int ret; xmlSecAssert2(in != NULL, NULL); ret = xmlSecBase64CtxInitialize(&ctx, 1, columns); if(ret < 0) { xmlSecInternalError("xmlSecBase64CtxInitialize", NULL); goto done; } ctx_initialized = 1; /* create result buffer */ outSize = xmlSecBase64GetEncodeSize(ctx.columns, inSize); if(outSize == 0) { xmlSecInternalError("xmlSecBase64GetEncodeSize", NULL); goto done; } ptr = (xmlSecByte*)xmlMalloc(outSize); if(ptr == NULL) { xmlSecMallocError(outSize, NULL); goto done; } ret = xmlSecBase64CtxUpdate_ex(&ctx, in, inSize, ptr, outSize, &outUpdatedSize); if (ret < 0) { xmlSecInternalError3("xmlSecBase64CtxUpdate_ex", NULL, "inSize=" XMLSEC_SIZE_FMT "; outSize=" XMLSEC_SIZE_FMT, inSize, outSize); goto done; } ret = xmlSecBase64CtxFinal_ex(&ctx, ptr + outUpdatedSize, outSize - outUpdatedSize, &outFinalSize); if (ret < 0) { xmlSecInternalError("xmlSecBase64CtxFinal_ex", NULL); goto done; } /* success */ ptr[outUpdatedSize + outFinalSize] = '\0'; res = BAD_CAST(ptr); ptr = NULL; done: if(ptr != NULL) { xmlFree(ptr); } if(ctx_initialized != 0) { xmlSecBase64CtxFinalize(&ctx); } return(res); } /** * xmlSecBase64Decode_ex: * @str: the input buffer with base64 encoded string * @out: the output buffer * @outSize: the output buffer size * @outWritten: the pointer to store the number of bytes written into the output. * * Decodes input base64 encoded string and puts result into * the output buffer. * * Returns: 0 on success and a negative value otherwise. */ int xmlSecBase64Decode_ex(const xmlChar* str, xmlSecByte* out, xmlSecSize outSize, xmlSecSize* outWritten) { xmlSecBase64Ctx ctx; int ctx_initialized = 0; xmlSecSize outUpdateSize, outFinalSize; int ret; int res = -1; xmlSecAssert2(str != NULL, -1); xmlSecAssert2(out != NULL, -1); xmlSecAssert2(outWritten != NULL, -1); ret = xmlSecBase64CtxInitialize(&ctx, 0, 0); if(ret < 0) { xmlSecInternalError("xmlSecBase64CtxInitialize", NULL); goto done; } ctx_initialized = 1; ret = xmlSecBase64CtxUpdate_ex(&ctx, (const xmlSecByte*)str, xmlSecStrlen(str), out, outSize, &outUpdateSize); if (ret < 0) { xmlSecInternalError("xmlSecBase64CtxUpdate_ex", NULL); goto done; } ret = xmlSecBase64CtxFinal_ex(&ctx, out + outUpdateSize, outSize - outUpdateSize, &outFinalSize); if (ret < 0) { xmlSecInternalError("xmlSecBase64CtxFinal_ex", NULL); goto done; } /* success */ (*outWritten) = (outUpdateSize + outFinalSize); res = 0; done: if(ctx_initialized != 0) { xmlSecBase64CtxFinalize(&ctx); } return(res); } /** * xmlSecBase64DecodeInPlace: * @str: the input/output buffer * @outWritten: the pointer to store the number of bytes written into the output. * * Decodes input base64 encoded string from @str "in-place" (i.e. puts results into @str buffer). * * Returns: 0 on success and a negative value otherwise. */ int xmlSecBase64DecodeInPlace(xmlChar* str, xmlSecSize* outWritten) { xmlSecAssert2(str != NULL, -1); return(xmlSecBase64Decode_ex(str, (xmlSecByte*)str, xmlSecStrlen(str) + 1,outWritten)); } /************************************************************** * * Base64 Transform * * xmlSecTransform + xmlSecBase64Ctx * **************************************************************/ XMLSEC_TRANSFORM_DECLARE(Base64, xmlSecBase64Ctx) #define xmlSecBase64Size XMLSEC_TRANSFORM_SIZE(Base64) static int xmlSecBase64Initialize (xmlSecTransformPtr transform); static void xmlSecBase64Finalize (xmlSecTransformPtr transform); static int xmlSecBase64Execute (xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx); static xmlSecTransformKlass xmlSecBase64Klass = { /* klass/object sizes */ sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ xmlSecBase64Size, /* xmlSecSize objSize */ xmlSecNameBase64, /* const xmlChar* name; */ xmlSecHrefBase64, /* const xmlChar* href; */ xmlSecTransformUsageDSigTransform, /* xmlSecAlgorithmUsage usage; */ xmlSecBase64Initialize, /* xmlSecTransformInitializeMethod initialize; */ xmlSecBase64Finalize, /* xmlSecTransformFinalizeMethod finalize; */ NULL, /* xmlSecTransformNodeReadMethod readNode; */ NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ NULL, /* xmlSecTransformSetKeyMethod setKey; */ NULL, /* xmlSecTransformValidateMethod validate; */ xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ NULL, /* xmlSecTransformPushXmlMethod pushXml; */ NULL, /* xmlSecTransformPopXmlMethod popXml; */ xmlSecBase64Execute, /* xmlSecTransformExecuteMethod execute; */ NULL, /* void* reserved0; */ NULL, /* void* reserved1; */ }; /** * xmlSecTransformBase64GetKlass: * * The Base64 transform klass (http://www.w3.org/TR/xmldsig-core/#sec-Base-64). * The normative specification for base64 decoding transforms is RFC 2045 * (http://www.ietf.org/rfc/rfc2045.txt). The base64 Transform element has * no content. The input is decoded by the algorithms. This transform is * useful if an application needs to sign the raw data associated with * the encoded content of an element. * * Returns: base64 transform id. */ xmlSecTransformId xmlSecTransformBase64GetKlass(void) { return(&xmlSecBase64Klass); } /** * xmlSecTransformBase64SetLineSize: * @transform: the pointer to BASE64 encode transform. * @lineSize: the new max line size. * * Sets the max line size to @lineSize. */ void xmlSecTransformBase64SetLineSize(xmlSecTransformPtr transform, xmlSecSize lineSize) { xmlSecBase64CtxPtr ctx; xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id)); ctx = xmlSecBase64GetCtx(transform); xmlSecAssert(ctx != NULL); ctx->columns = lineSize; } static int xmlSecBase64Initialize(xmlSecTransformPtr transform) { xmlSecBase64CtxPtr ctx; int ret; int columns; xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id), -1); ctx = xmlSecBase64GetCtx(transform); xmlSecAssert2(ctx != NULL, -1); columns = xmlSecBase64GetDefaultLineSize(); transform->operation = xmlSecTransformOperationDecode; ret = xmlSecBase64CtxInitialize(ctx, 0, columns); if(ret < 0) { xmlSecInternalError("xmlSecBase64CtxInitialize", xmlSecTransformGetName(transform)); return(-1); } return(0); } static void xmlSecBase64Finalize(xmlSecTransformPtr transform) { xmlSecBase64CtxPtr ctx; xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id)); ctx = xmlSecBase64GetCtx(transform); xmlSecAssert(ctx != NULL); xmlSecBase64CtxFinalize(ctx); } static int xmlSecBase64Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { xmlSecBase64CtxPtr ctx; xmlSecBufferPtr in, out; xmlSecSize inSize, outSize, outMaxLen, outLen; int ret; xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id), -1); xmlSecAssert2((transform->operation == xmlSecTransformOperationEncode) || (transform->operation == xmlSecTransformOperationDecode), -1); xmlSecAssert2(transformCtx != NULL, -1); ctx = xmlSecBase64GetCtx(transform); xmlSecAssert2(ctx != NULL, -1); in = &(transform->inBuf); out = &(transform->outBuf); if(transform->status == xmlSecTransformStatusNone) { ctx->encode = (transform->operation == xmlSecTransformOperationEncode) ? 1 : 0; transform->status = xmlSecTransformStatusWorking; } switch(transform->status) { case xmlSecTransformStatusWorking: inSize = xmlSecBufferGetSize(in); outSize = xmlSecBufferGetSize(out); if(inSize > 0) { if(ctx->encode != 0) { outMaxLen = xmlSecBase64GetEncodeSize(ctx->columns, inSize); } else { outMaxLen = xmlSecBase64GetDecodeSize(inSize); } ret = xmlSecBufferSetMaxSize(out, outSize + outMaxLen); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetMaxSize", xmlSecTransformGetName(transform), "size=" XMLSEC_SIZE_FMT, (outSize + outMaxLen)); return(-1); } /* encode/decode the next chunk */ ret = xmlSecBase64CtxUpdate_ex(ctx, xmlSecBufferGetData(in), inSize, xmlSecBufferGetData(out) + outSize, outMaxLen, &outLen); if(ret < 0) { xmlSecInternalError("xmlSecBase64CtxUpdate_ex", xmlSecTransformGetName(transform)); return(-1); } /* set correct size */ ret = xmlSecBufferSetSize(out, outSize + outLen); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetSize", xmlSecTransformGetName(transform), "size=" XMLSEC_SIZE_FMT, (outSize + outLen)); return(-1); } /* remove chunk from input */ ret = xmlSecBufferRemoveHead(in, inSize); if(ret < 0) { xmlSecInternalError2("xmlSecBufferRemoveHead", xmlSecTransformGetName(transform), "size=" XMLSEC_SIZE_FMT, inSize); return(-1); } } if(last) { outSize = xmlSecBufferGetSize(out); outMaxLen = 16; /* last block */ ret = xmlSecBufferSetMaxSize(out, outSize + outMaxLen); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetMaxSize", xmlSecTransformGetName(transform), "size=" XMLSEC_SIZE_FMT, (outSize + outMaxLen)); return(-1); } /* add from ctx buffer */ ret = xmlSecBase64CtxFinal_ex(ctx, xmlSecBufferGetData(out) + outSize, outMaxLen, &outLen); if (ret < 0) { xmlSecInternalError("xmlSecBase64CtxFinal_ex", xmlSecTransformGetName(transform)); return(-1); } /* set correct size */ ret = xmlSecBufferSetSize(out, outSize + outLen); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetSize", xmlSecTransformGetName(transform), "size=" XMLSEC_SIZE_FMT, (outSize + outLen)); return(-1); } transform->status = xmlSecTransformStatusFinished; } break; case xmlSecTransformStatusFinished: /* the only way we can get here is if there is no input */ xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); break; default: xmlSecInvalidTransfromStatusError(transform); return(-1); } return(0); }