From 3b94944cf2d6476d1b8ac7949bf8b28abb644426 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 10 Apr 2019 13:43:45 +0100 Subject: Add a maximum output length to update and final calls Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/8700) --- crypto/evp/evp_enc.c | 34 ++++++++++++++++++++++++++-------- include/openssl/core_numbers.h | 4 ++-- providers/common/ciphers/aes.c | 24 +++++++++++++++++++----- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index 6d4e033816..69cd577800 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -562,6 +562,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, { int ret; size_t soutl; + int blocksize; /* Prevent accidental use of decryption context when encrypting */ if (!ctx->encrypt) { @@ -572,11 +573,15 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, if (ctx->cipher == NULL || ctx->cipher->prov == NULL) goto legacy; - if (ctx->cipher->cupdate == NULL) { + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + if (ctx->cipher->cupdate == NULL || blocksize < 1) { EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_UPDATE_ERROR); return 0; } - ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl, in, (size_t)inl); + ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl, + inl + (blocksize == 1 ? 0 : blocksize), in, + (size_t)inl); if (soutl > INT_MAX) { EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_UPDATE_ERROR); @@ -603,6 +608,7 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) int n, ret; unsigned int i, b, bl; size_t soutl; + int blocksize; /* Prevent accidental use of decryption context when encrypting */ if (!ctx->encrypt) { @@ -613,12 +619,15 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) if (ctx->cipher == NULL || ctx->cipher->prov == NULL) goto legacy; - if (ctx->cipher->cfinal == NULL) { + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + if (blocksize < 1 || ctx->cipher->cfinal == NULL) { EVPerr(EVP_F_EVP_ENCRYPTFINAL_EX, EVP_R_FINAL_ERROR); return 0; } - ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl); + ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl, + blocksize == 1 ? 0 : blocksize); if (soutl > INT_MAX) { EVPerr(EVP_F_EVP_ENCRYPTFINAL_EX, EVP_R_FINAL_ERROR); @@ -674,6 +683,7 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, int fix_len, cmpl = inl, ret; unsigned int b; size_t soutl; + int blocksize; /* Prevent accidental use of encryption context when decrypting */ if (ctx->encrypt) { @@ -684,11 +694,15 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, if (ctx->cipher == NULL || ctx->cipher->prov == NULL) goto legacy; - if (ctx->cipher->cupdate == NULL) { + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + if (ctx->cipher->cupdate == NULL || blocksize < 1) { EVPerr(EVP_F_EVP_DECRYPTUPDATE, EVP_R_UPDATE_ERROR); return 0; } - ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl, in, (size_t)inl); + ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl, + inl + (blocksize == 1 ? 0 : blocksize), in, + (size_t)inl); if (ret) { if (soutl > INT_MAX) { @@ -779,6 +793,7 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) unsigned int b; size_t soutl; int ret; + int blocksize; /* Prevent accidental use of encryption context when decrypting */ if (ctx->encrypt) { @@ -789,12 +804,15 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) if (ctx->cipher == NULL || ctx->cipher->prov == NULL) goto legacy; - if (ctx->cipher->cfinal == NULL) { + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + if (blocksize < 1 || ctx->cipher->cfinal == NULL) { EVPerr(EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_FINAL_ERROR); return 0; } - ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl); + ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl, + blocksize == 1 ? 0 : blocksize); if (ret) { if (soutl > INT_MAX) { diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h index e56909aa03..d58888607e 100644 --- a/include/openssl/core_numbers.h +++ b/include/openssl/core_numbers.h @@ -135,10 +135,10 @@ OSSL_CORE_MAKE_FUNC(int, OP_cipher_decrypt_init, (void *vctx, const unsigned char *iv, size_t ivlen)) OSSL_CORE_MAKE_FUNC(int, OP_cipher_update, - (void *, unsigned char *out, size_t *outl, + (void *, unsigned char *out, size_t *outl, size_t outsize, const unsigned char *in, size_t inl)) OSSL_CORE_MAKE_FUNC(int, OP_cipher_final, - (void *, unsigned char *out, size_t *outl)) + (void *, unsigned char *out, size_t *outl, size_t outsize)) OSSL_CORE_MAKE_FUNC(int, OP_cipher_cipher, (void *, unsigned char *out, const unsigned char *in, size_t inl)) diff --git a/providers/common/ciphers/aes.c b/providers/common/ciphers/aes.c index 21ecc2b14a..a70facc148 100644 --- a/providers/common/ciphers/aes.c +++ b/providers/common/ciphers/aes.c @@ -65,7 +65,7 @@ static int aes_dinit(void *vctx, const unsigned char *key, size_t keylen, } static int aes_block_update(void *vctx, unsigned char *out, size_t *outl, - const unsigned char *in, size_t inl) + size_t outsize, const unsigned char *in, size_t inl) { PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; size_t nextblocks = fillblock(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE, &in, @@ -79,6 +79,8 @@ static int aes_block_update(void *vctx, unsigned char *out, size_t *outl, */ if (ctx->bufsz == AES_BLOCK_SIZE && (ctx->enc || inl > 0 || !ctx->pad)) { + if (outsize < AES_BLOCK_SIZE) + return 0; if (!ctx->ciph->cipher(ctx, out, ctx->buf, AES_BLOCK_SIZE)) return 0; ctx->bufsz = 0; @@ -91,11 +93,13 @@ static int aes_block_update(void *vctx, unsigned char *out, size_t *outl, return 0; nextblocks -= AES_BLOCK_SIZE; } + outlint += nextblocks; + if (outsize < outlint) + return 0; if (!ctx->ciph->cipher(ctx, out, in, nextblocks)) return 0; in += nextblocks; inl -= nextblocks; - outlint += nextblocks; } if (!trailingdata(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE, &in, &inl)) return 0; @@ -104,7 +108,8 @@ static int aes_block_update(void *vctx, unsigned char *out, size_t *outl, return inl == 0; } -static int aes_block_final(void *vctx, unsigned char *out, size_t *outl) +static int aes_block_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) { PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; @@ -119,6 +124,8 @@ static int aes_block_final(void *vctx, unsigned char *out, size_t *outl) return 0; } + if (outsize < AES_BLOCK_SIZE) + return 0; if (!ctx->ciph->cipher(ctx, out, ctx->buf, AES_BLOCK_SIZE)) return 0; ctx->bufsz = 0; @@ -143,6 +150,8 @@ static int aes_block_final(void *vctx, unsigned char *out, size_t *outl) if (ctx->pad && !unpadblock(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE)) return 0; + if (outsize < ctx->bufsz) + return 0; memcpy(out, ctx->buf, ctx->bufsz); *outl = ctx->bufsz; ctx->bufsz = 0; @@ -150,17 +159,22 @@ static int aes_block_final(void *vctx, unsigned char *out, size_t *outl) } static int aes_stream_update(void *vctx, unsigned char *out, size_t *outl, - const unsigned char *in, size_t inl) + size_t outsize, const unsigned char *in, + size_t inl) { PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + if (outsize < inl) + return 0; + if (!ctx->ciph->cipher(ctx, out, in, inl)) return 0; *outl = inl; return 1; } -static int aes_stream_final(void *vctx, unsigned char *out, size_t *outl) +static int aes_stream_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) { *outl = 0; return 1; -- cgit v1.2.3