diff options
Diffstat (limited to 'src/openssl/ciphers.c')
-rw-r--r-- | src/openssl/ciphers.c | 603 |
1 files changed, 421 insertions, 182 deletions
diff --git a/src/openssl/ciphers.c b/src/openssl/ciphers.c index c93f06b9..35163b33 100644 --- a/src/openssl/ciphers.c +++ b/src/openssl/ciphers.c @@ -1,11 +1,19 @@ -/** - * XMLSec library +/* + * 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-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. */ +/** + * SECTION:ciphers + * @Short_description: Ciphers transforms implementation for OpenSSL. + * @Stability: Private + * + */ + #include "globals.h" #include <string.h> @@ -20,12 +28,10 @@ #include <xmlsec/openssl/crypto.h> #include <xmlsec/openssl/evp.h> +#include "openssl_compat.h" -/* new API from OpenSSL 1.1.0 */ -#if !defined(XMLSEC_OPENSSL_110) -#define EVP_CIPHER_CTX_encrypting(x) ((x)->encrypt) -#endif /* !defined(XMLSEC_OPENSSL_110) */ - +#define xmlSecOpenSSLAesGcmNonceLengthInBytes 12 +#define xmlSecOpenSSLAesGcmTagLengthInBytes 16 /************************************************************************** * @@ -40,6 +46,7 @@ struct _xmlSecOpenSSLEvpBlockCipherCtx { EVP_CIPHER_CTX* cipherCtx; int keyInitialized; int ctxInitialized; + int cbcMode; xmlSecByte key[EVP_MAX_KEY_LENGTH]; xmlSecByte iv[EVP_MAX_IV_LENGTH]; xmlSecByte pad[2*EVP_MAX_BLOCK_LENGTH]; @@ -56,7 +63,8 @@ static int xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(xmlSecOpenSSLEvpBlockC int inSize, xmlSecBufferPtr out, const xmlChar* cipherName, - int final); + int final, + xmlSecByte *tag); static int xmlSecOpenSSLEvpBlockCipherCtxUpdate (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, xmlSecBufferPtr in, xmlSecBufferPtr out, @@ -67,6 +75,7 @@ static int xmlSecOpenSSLEvpBlockCipherCtxFinal (xmlSecOpenSSLEvpBlockCi xmlSecBufferPtr out, const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx); + static int xmlSecOpenSSLEvpBlockCipherCtxInit(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, xmlSecBufferPtr in, xmlSecBufferPtr out, @@ -85,7 +94,13 @@ xmlSecOpenSSLEvpBlockCipherCtxInit(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, xmlSecAssert2(out != NULL, -1); xmlSecAssert2(transformCtx != NULL, -1); - ivLen = EVP_CIPHER_iv_length(ctx->cipher); + if(ctx->cbcMode) { + ivLen = EVP_CIPHER_iv_length(ctx->cipher); + } else { + /* This is the nonce length for GCM mode rather than an IV */ + ivLen = xmlSecOpenSSLAesGcmNonceLengthInBytes; + } + xmlSecAssert2(ivLen > 0, -1); xmlSecAssert2((xmlSecSize)ivLen <= sizeof(ctx->iv), -1); @@ -93,22 +108,15 @@ xmlSecOpenSSLEvpBlockCipherCtxInit(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, /* generate random iv */ ret = RAND_bytes(ctx->iv, ivLen); if(ret != 1) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "RAND_bytes", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - "size=%d", ivLen); + xmlSecOpenSSLError2("RAND_bytes", cipherName, + "size=%lu", (unsigned long)ivLen); return(-1); } /* write iv to the output */ ret = xmlSecBufferAppend(out, ctx->iv, ivLen); if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecBufferAppend", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - "size=%d", ivLen); + xmlSecInternalError2("xmlSecBufferAppend", cipherName, "size=%d", ivLen); return(-1); } @@ -126,11 +134,7 @@ xmlSecOpenSSLEvpBlockCipherCtxInit(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, /* and remove from input */ ret = xmlSecBufferRemoveHead(in, ivLen); if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecBufferRemoveHead", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - "size=%d", ivLen); + xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName, "size=%d", ivLen); return(-1); } } @@ -138,11 +142,7 @@ xmlSecOpenSSLEvpBlockCipherCtxInit(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, /* set iv */ ret = EVP_CipherInit(ctx->cipherCtx, ctx->cipher, ctx->key, ctx->iv, encrypt); if(ret != 1) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "EVP_CipherInit", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); + xmlSecOpenSSLError("EVP_CipherIn", cipherName); return(-1); } @@ -155,18 +155,21 @@ xmlSecOpenSSLEvpBlockCipherCtxInit(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, * * https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html#sec-Alg-Block */ - EVP_CIPHER_CTX_set_padding(ctx->cipherCtx, 0); + if(ctx->cbcMode) { + EVP_CIPHER_CTX_set_padding(ctx->cipherCtx, 0); + } return(0); } static int xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, - const xmlSecByte * in, - int inSize, - xmlSecBufferPtr out, - const xmlChar* cipherName, - int final) { + const xmlSecByte * in, + int inSize, + xmlSecBufferPtr out, + const xmlChar* cipherName, + int final, + xmlSecByte *tagData) { xmlSecByte* outBuf; xmlSecSize outSize; int blockLen, outLen = 0; @@ -178,9 +181,16 @@ xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, xmlSecAssert2(ctx->keyInitialized != 0, -1); xmlSecAssert2(ctx->ctxInitialized != 0, -1); xmlSecAssert2(in != NULL, -1); - xmlSecAssert2(inSize > 0, -1); xmlSecAssert2(out != NULL, -1); + if (ctx->cbcMode) { + xmlSecAssert2(inSize > 0, -1); + } else { + if (final != 0) { + xmlSecAssert2(tagData != NULL, -1); + } + } + /* OpenSSL docs: If the pad parameter is zero then no padding is performed, the total amount of * data encrypted or decrypted must then be a multiple of the block size or an error will occur. */ @@ -188,27 +198,34 @@ xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, xmlSecAssert2(blockLen > 0, -1); xmlSecAssert2((inSize % blockLen) == 0, -1); - /* prepare: ensure we have enough space (+blockLen for final) */ outSize = xmlSecBufferGetSize(out); - ret = xmlSecBufferSetMaxSize(out, outSize + inSize + blockLen); - if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecBufferSetMaxSize", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - "size=%d", (int)(outSize + inSize + blockLen)); - return(-1); + + if(ctx->cbcMode) { + /* prepare: ensure we have enough space (+blockLen for final) */ + ret = xmlSecBufferSetMaxSize(out, outSize + inSize + blockLen); + if(ret < 0) { + xmlSecInternalError2("xmlSecBufferSetMaxSize", + xmlSecErrorsSafeString(cipherName), + "size=%d", (int)(outSize + inSize + blockLen)); + return(-1); + } + } else { + /* prepare: ensure we have enough space */ + ret = xmlSecBufferSetMaxSize(out, outSize + inSize); + if(ret < 0) { + xmlSecInternalError2("xmlSecBufferSetMaxSize", + xmlSecErrorsSafeString(cipherName), + "size=%d", (int)(outSize + inSize + blockLen)); + return(-1); + } } + outBuf = xmlSecBufferGetData(out) + outSize; /* encrypt/decrypt */ ret = EVP_CipherUpdate(ctx->cipherCtx, outBuf, &outLen, in, inSize); if(ret != 1) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "EVP_CipherUpdate", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); + xmlSecOpenSSLError("EVP_CipherUpdate", cipherName); return(-1); } xmlSecAssert2(outLen == inSize, -1); @@ -217,27 +234,42 @@ xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, if(final != 0) { int outLen2 = 0; + if(ctx->cbcMode == 0) { + if(!EVP_CIPHER_CTX_encrypting(ctx->cipherCtx)) { + ret = EVP_CIPHER_CTX_ctrl(ctx->cipherCtx, EVP_CTRL_GCM_SET_TAG, + xmlSecOpenSSLAesGcmTagLengthInBytes, tagData); + if(ret != 1) { + xmlSecOpenSSLError("EVP_CIPHER_CTX_ctrl", cipherName); + return(-1); + } + } + } + ret = EVP_CipherFinal(ctx->cipherCtx, outBuf + outLen, &outLen2); if(ret != 1) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "EVP_CipherFinal", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); + xmlSecOpenSSLError("EVP_CipherFinal", cipherName); return(-1); } + if(ctx->cbcMode == 0) { + if(EVP_CIPHER_CTX_encrypting(ctx->cipherCtx)) { + ret = EVP_CIPHER_CTX_ctrl(ctx->cipherCtx, EVP_CTRL_GCM_GET_TAG, + xmlSecOpenSSLAesGcmTagLengthInBytes, tagData); + if(ret != 1) { + xmlSecOpenSSLError("EVP_CIPHER_CTX_ctrl", cipherName); + return(-1); + } + } + } + outLen += outLen2; } /* set correct output buffer size */ ret = xmlSecBufferSetSize(out, outSize + outLen); if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecBufferSetSize", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - "size=%d", (int)(outSize + outLen)); + xmlSecInternalError2("xmlSecBufferSetSize", cipherName, + "size=%d", (int)(outSize + outLen)); return(-1); } @@ -247,9 +279,9 @@ xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, static int xmlSecOpenSSLEvpBlockCipherCtxUpdate(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, - xmlSecBufferPtr in, xmlSecBufferPtr out, - const xmlChar* cipherName, - xmlSecTransformCtxPtr transformCtx) { + xmlSecBufferPtr in, xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { xmlSecSize inSize, blockLen, inBlocksLen; xmlSecByte* inBuf; int ret; @@ -266,11 +298,21 @@ xmlSecOpenSSLEvpBlockCipherCtxUpdate(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, xmlSecAssert2(blockLen > 0, -1); inSize = xmlSecBufferGetSize(in); - if(inSize <= blockLen) { - /* wait for more data: we want to make sure we keep the last chunk in tmp buffer for - * padding check/removal on decryption - */ - return(0); + + if(ctx->cbcMode) { + if(inSize <= blockLen) { + /* wait for more data: we want to make sure we keep the last chunk in tmp buffer for + * padding check/removal on decryption + */ + return(0); + } + } else { + if(inSize <= xmlSecOpenSSLAesGcmTagLengthInBytes) { + /* In GCM mode during decryption the last 16 bytes of the buffer are the tag. + * Make sure there are always at least 16 bytes left over until we know we're + * processing the last buffer */ + return(0); + } } /* OpenSSL docs: If the pad parameter is zero then no padding is performed, the total amount of @@ -278,54 +320,65 @@ xmlSecOpenSSLEvpBlockCipherCtxUpdate(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, * * We process all complete blocks from the input */ - inBlocksLen = blockLen * (inSize / blockLen); + if(ctx->cbcMode) { + inBlocksLen = blockLen * (inSize / blockLen); + } else { + /* ensure we keep the last 16 bytes around until the Final() call */ + inBlocksLen = blockLen * ((inSize - xmlSecOpenSSLAesGcmTagLengthInBytes) / blockLen); + if(inBlocksLen == 0) { + return(0); + } + } + if(inBlocksLen == inSize) { - inBlocksLen -= blockLen; /* ensure we keep the last block around for Final() call to add/check/remove padding */ + if(ctx->cbcMode) { + inBlocksLen -= blockLen; /* ensure we keep the last block around for Final() call to add/check/remove padding */ + } } xmlSecAssert2(inBlocksLen > 0, -1); inBuf = xmlSecBufferGetData(in); - ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, inBlocksLen, out, cipherName, 0); /* not final */ + ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, (int)inBlocksLen, out, cipherName, 0, + NULL); /* not final */ if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - NULL); + xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName); return(-1); } /* remove the processed block from input */ ret = xmlSecBufferRemoveHead(in, inBlocksLen); if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecBufferRemoveHead", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - "size=%d", (int)inSize); + xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName, "size=%d", (int)inSize); return(-1); } /* just a double check */ inSize = xmlSecBufferGetSize(in); xmlSecAssert2(inSize > 0, -1); - xmlSecAssert2(inSize <= blockLen, -1); + + if(ctx->cbcMode) { + xmlSecAssert2(inSize <= blockLen, -1); + } /* done */ return(0); } static int -xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, - xmlSecBufferPtr in, - xmlSecBufferPtr out, - const xmlChar* cipherName, - xmlSecTransformCtxPtr transformCtx) { +xmlSecOpenSSLEvpBlockCipherCBCCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) +{ xmlSecSize inSize, outSize, blockLen; xmlSecByte* inBuf; xmlSecByte* outBuf; int ret; + /* unreferenced parameter */ + (void)transformCtx; + xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->cipher != NULL, -1); xmlSecAssert2(ctx->cipherCtx != NULL, -1); @@ -345,12 +398,12 @@ xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, xmlSecAssert2(inSize <= blockLen, -1); /* - * The padding used in XML Enc does not follow RFC 1423 - * and is not supported by OpenSSL. However, it is possible - * to disable padding and do it by yourself - * - * https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html#sec-Alg-Block - */ + * The padding used in XML Enc does not follow RFC 1423 + * and is not supported by OpenSSL. However, it is possible + * to disable padding and do it by yourself + * + * https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html#sec-Alg-Block + */ if(EVP_CIPHER_CTX_encrypting(ctx->cipherCtx)) { xmlSecSize padLen; @@ -369,41 +422,30 @@ xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, /* generate random padding */ if(padLen > 1) { - ret = RAND_bytes(ctx->pad + inSize, padLen - 1); - if(ret != 1) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "RAND_bytes", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - "size=%d", (int)(padLen - 1)); + ret = RAND_bytes(ctx->pad + inSize, (int)(padLen - 1)); + if (ret != 1) { + xmlSecOpenSSLError("RAND_bytes", cipherName); return(-1); } } /* set the last byte to the pad length */ - ctx->pad[inSize + padLen - 1] = padLen; + ctx->pad[inSize + padLen - 1] = (xmlSecByte)padLen; /* update the last 1 or 2 blocks with padding */ - ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, ctx->pad, inSize + padLen, out, cipherName, 1); /* final */ + ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, ctx->pad, (int)(inSize + padLen), out, + cipherName, 1, NULL); /* final */ if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - NULL); + xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName); return(-1); } } else { xmlSecSize padLen; /* update the last one block with padding */ - ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, inSize, out, cipherName, 1); /* final */ + ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, (int)inSize, out, cipherName, 1, NULL); /* final */ if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - NULL); + xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName); return(-1); } @@ -411,24 +453,16 @@ xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, outBuf = xmlSecBufferGetData(out); outSize = xmlSecBufferGetSize(out); if(outSize < blockLen) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - NULL, - XMLSEC_ERRORS_R_INVALID_DATA, - "outSize=%d;blockLen=%d", - (int)outSize, (int)blockLen); + xmlSecInvalidIntegerDataError2("outSize", outSize, "blockLen", blockLen, + "outSize >= blockLen", cipherName); return(-1); } /* get the pad length from the last byte */ padLen = (xmlSecSize)(outBuf[outSize - 1]); if(padLen > blockLen) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - NULL, - XMLSEC_ERRORS_R_INVALID_DATA, - "padLen=%d;blockLen=%d", - (int)padLen, (int)blockLen); + xmlSecInvalidIntegerDataError2("padLen", padLen, "blockLen", blockLen, + "padLen <= blockLen", cipherName); return(-1); } xmlSecAssert2(padLen <= outSize, -1); @@ -436,11 +470,7 @@ xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, /* remove the padding */ ret = xmlSecBufferRemoveTail(out, padLen); if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecBufferRemoveTail", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - "size=%d", (int)padLen); + xmlSecInternalError2("xmlSecBufferRemoveTail", cipherName, "size=%d", (int)padLen); return(-1); } } @@ -448,17 +478,114 @@ xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, /* remove the processed block from input */ ret = xmlSecBufferRemoveHead(in, inSize); if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(cipherName), - "xmlSecBufferRemoveHead", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - "size=%d", (int)inSize); + xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName, "size=%d", (int)inSize); + return(-1); + } + + /* done */ + return(0); + +} + +#ifndef XMLSEC_NO_AES +static int +xmlSecOpenSSLEvpBlockCipherGCMCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) +{ + xmlSecSize inSize, outSize; + xmlSecByte* inBuf; + xmlSecByte* outBuf; + xmlSecByte tag[xmlSecOpenSSLAesGcmTagLengthInBytes]; + int ret; + + /* unreferenced parameter */ + (void)transformCtx; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != NULL, -1); + xmlSecAssert2(ctx->cipherCtx != NULL, -1); + xmlSecAssert2(ctx->keyInitialized != 0, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + inSize = xmlSecBufferGetSize(in); + inBuf = xmlSecBufferGetData(in); + + if(EVP_CIPHER_CTX_encrypting(ctx->cipherCtx)) { + ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, (int)inSize, out, cipherName, + 1, tag); /* final */ + if(ret < 0) { + xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName); + return(-1); + } + + /* get the tag and add to the output */ + outSize = xmlSecBufferGetSize(out); + ret = xmlSecBufferSetMaxSize(out, outSize + xmlSecOpenSSLAesGcmTagLengthInBytes); + if(ret < 0) { + xmlSecInternalError("xmlSecBufferSetMaxSize", cipherName); + return(-1); + } + outBuf = xmlSecBufferGetData(out) + outSize; + memcpy(outBuf, tag, xmlSecOpenSSLAesGcmTagLengthInBytes); + ret = xmlSecBufferSetSize(out, outSize + xmlSecOpenSSLAesGcmTagLengthInBytes); + if(ret < 0) { + xmlSecInternalError("xmlSecBufferSetSize", cipherName); + return(-1); + } + } else { + /* There must be at least 16 bytes in the buffer - the tag and anything left over */ + xmlSecAssert2(inSize >= xmlSecOpenSSLAesGcmTagLengthInBytes, -1); + + /* extract the tag */ + memcpy(tag, inBuf + inSize - xmlSecOpenSSLAesGcmTagLengthInBytes, + xmlSecOpenSSLAesGcmTagLengthInBytes); + xmlSecBufferRemoveTail(in, xmlSecOpenSSLAesGcmTagLengthInBytes); + + inBuf = xmlSecBufferGetData(in); + inSize = xmlSecBufferGetSize(in); + + /* Decrypt anything remaining and verify the tag */ + ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, (int)inSize, out, cipherName, + 1, tag); /* final */ + if(ret < 0) { + xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName); + return(-1); + } + } + + /* remove the processed data from input */ + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName, "size=%d", (int)inSize); return(-1); } /* done */ return(0); } +#endif + +static int +xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) +{ + xmlSecAssert2(ctx != NULL, -1); + + if (ctx->cbcMode) { + return xmlSecOpenSSLEvpBlockCipherCBCCtxFinal(ctx, in, out, cipherName, transformCtx); + } else { + return xmlSecOpenSSLEvpBlockCipherGCMCtxFinal(ctx, in, out, cipherName, transformCtx); + } +} /****************************************************************************** @@ -497,7 +624,10 @@ xmlSecOpenSSLEvpBlockCipherCheckId(xmlSecTransformPtr transform) { #ifndef XMLSEC_NO_AES if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes128CbcId) || xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes192CbcId) || - xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes256CbcId)) { + xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes256CbcId) || + xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes128GcmId) || + xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes192GcmId) || + xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes256GcmId)) { return(1); } @@ -522,6 +652,7 @@ xmlSecOpenSSLEvpBlockCipherInitialize(xmlSecTransformPtr transform) { if(transform->id == xmlSecOpenSSLTransformDes3CbcId) { ctx->cipher = EVP_des_ede3_cbc(); ctx->keyId = xmlSecOpenSSLKeyDataDesId; + ctx->cbcMode = 1; } else #endif /* XMLSEC_NO_DES */ @@ -529,32 +660,40 @@ xmlSecOpenSSLEvpBlockCipherInitialize(xmlSecTransformPtr transform) { if(transform->id == xmlSecOpenSSLTransformAes128CbcId) { ctx->cipher = EVP_aes_128_cbc(); ctx->keyId = xmlSecOpenSSLKeyDataAesId; + ctx->cbcMode = 1; } else if(transform->id == xmlSecOpenSSLTransformAes192CbcId) { ctx->cipher = EVP_aes_192_cbc(); ctx->keyId = xmlSecOpenSSLKeyDataAesId; + ctx->cbcMode = 1; } else if(transform->id == xmlSecOpenSSLTransformAes256CbcId) { ctx->cipher = EVP_aes_256_cbc(); ctx->keyId = xmlSecOpenSSLKeyDataAesId; + ctx->cbcMode = 1; + } else if(transform->id == xmlSecOpenSSLTransformAes128GcmId) { + ctx->cipher = EVP_aes_128_gcm(); + ctx->keyId = xmlSecOpenSSLKeyDataAesId; + ctx->cbcMode = 0; + } else if(transform->id == xmlSecOpenSSLTransformAes192GcmId) { + ctx->cipher = EVP_aes_192_gcm(); + ctx->keyId = xmlSecOpenSSLKeyDataAesId; + ctx->cbcMode = 0; + } else if(transform->id == xmlSecOpenSSLTransformAes256GcmId) { + ctx->cipher = EVP_aes_256_gcm(); + ctx->keyId = xmlSecOpenSSLKeyDataAesId; + ctx->cbcMode = 0; } else #endif /* XMLSEC_NO_AES */ if(1) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - NULL, - XMLSEC_ERRORS_R_INVALID_TRANSFORM, - XMLSEC_ERRORS_NO_MESSAGE); + xmlSecInvalidTransfromError(transform) return(-1); } /* create cipher ctx */ ctx->cipherCtx = EVP_CIPHER_CTX_new(); if(ctx->cipherCtx == NULL) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - "EVP_CIPHER_CTX_new", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); + xmlSecOpenSSLError("EVP_CIPHER_CTX_new", + xmlSecTransformGetName(transform)); return(-1); } @@ -595,7 +734,7 @@ xmlSecOpenSSLEvpBlockCipherSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReq xmlSecAssert2(ctx->keyId != NULL, -1); keyReq->keyId = ctx->keyId; - keyReq->keyType = xmlSecKeyDataTypeSymmetric; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; if(transform->operation == xmlSecTransformOperationEncrypt) { keyReq->keyUsage = xmlSecKeyUsageEncrypt; } else { @@ -635,12 +774,8 @@ xmlSecOpenSSLEvpBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key xmlSecAssert2(buffer != NULL, -1); if(xmlSecBufferGetSize(buffer) < (xmlSecSize)cipherKeyLen) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - NULL, - XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, - "keySize=%d;expected=%d", - (int)xmlSecBufferGetSize(buffer), (int)cipherKeyLen); + xmlSecInvalidKeyDataSizeError(xmlSecBufferGetSize(buffer), cipherKeyLen, + xmlSecTransformGetName(transform)); return(-1); } @@ -678,47 +813,35 @@ xmlSecOpenSSLEvpBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSe (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, xmlSecTransformGetName(transform), transformCtx); if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - "xmlSecOpenSSLEvpBlockCipherCtxInit", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); + xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxInit", + xmlSecTransformGetName(transform)); return(-1); } } if((ctx->ctxInitialized == 0) && (last != 0)) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - NULL, - XMLSEC_ERRORS_R_INVALID_DATA, - "not enough data to initialize transform"); + xmlSecInvalidDataError("not enough data to initialize transform", + xmlSecTransformGetName(transform)); return(-1); } if(ctx->ctxInitialized != 0) { ret = xmlSecOpenSSLEvpBlockCipherCtxUpdate(ctx, in, out, - xmlSecTransformGetName(transform), - transformCtx); + xmlSecTransformGetName(transform), + transformCtx); if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - "xmlSecOpenSSLEvpBlockCipherCtxUpdate", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); + xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdate", + xmlSecTransformGetName(transform)); return(-1); } } if(last != 0) { ret = xmlSecOpenSSLEvpBlockCipherCtxFinal(ctx, in, out, - xmlSecTransformGetName(transform), - transformCtx); + xmlSecTransformGetName(transform), + transformCtx); if(ret < 0) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - "xmlSecOpenSSLEvpBlockCipherCtxFinal", - XMLSEC_ERRORS_R_XMLSEC_FAILED, - XMLSEC_ERRORS_NO_MESSAGE); + xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxFinal", + xmlSecTransformGetName(transform)); return(-1); } transform->status = xmlSecTransformStatusFinished; @@ -733,11 +856,7 @@ xmlSecOpenSSLEvpBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSe /* the only way we can get here is if there is no enough data in the input */ xmlSecAssert2(last == 0, -1); } else { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - NULL, - XMLSEC_ERRORS_R_INVALID_STATUS, - "status=%d", (int)(transform->status)); + xmlSecInvalidTransfromStatusError(transform); return(-1); } @@ -868,6 +987,126 @@ xmlSecOpenSSLTransformAes256CbcGetKlass(void) { return(&xmlSecOpenSSLAes256CbcKlass); } +static xmlSecTransformKlass xmlSecOpenSSLAes128GcmKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes128Gcm, /* const xmlChar* name; */ + xmlSecHrefAes128Gcm, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** +* xmlSecOpenSSLTransformAes128GcmGetKlass: +* +* AES 128 GCM encryption transform klass. +* +* Returns: pointer to AES 128 GCM encryption transform. +*/ +xmlSecTransformId +xmlSecOpenSSLTransformAes128GcmGetKlass(void) +{ + return(&xmlSecOpenSSLAes128GcmKlass); +} + +static xmlSecTransformKlass xmlSecOpenSSLAes192GcmKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes192Gcm, /* const xmlChar* name; */ + xmlSecHrefAes192Gcm, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** +* xmlSecOpenSSLTransformAes192GcmGetKlass: +* +* AES 192 GCM encryption transform klass. +* +* Returns: pointer to AES 192 GCM encryption transform. +*/ +xmlSecTransformId +xmlSecOpenSSLTransformAes192GcmGetKlass(void) +{ + return(&xmlSecOpenSSLAes192GcmKlass); +} + +static xmlSecTransformKlass xmlSecOpenSSLAes256GcmKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes256Gcm, /* const xmlChar* name; */ + xmlSecHrefAes256Gcm, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** +* xmlSecOpenSSLTransformAes256GcmGetKlass: +* +* AES 256 GCM encryption transform klass. +* +* Returns: pointer to AES 256 GCM encryption transform. +*/ +xmlSecTransformId +xmlSecOpenSSLTransformAes256GcmGetKlass(void) +{ + return(&xmlSecOpenSSLAes256GcmKlass); +} + #endif /* XMLSEC_NO_AES */ #ifndef XMLSEC_NO_DES |