EVP_DecodeUpdate() should not produce padding zeros to the decoded output (Fixes #26677)

EVP_DecodeUpdate() should not produce zeros for input padding `=` signs to avoid writing to non-allocated memory regions.

To achieve this:
- Add `eof` parameter to `evp_decodeblock_int` function in `openssl/crypto/evp`. The parameter should either contain the number of the input padding characters to ignore or `-1` if the function has to count them.
- Use precalculated `eof` in `EVP_DecodeUpdate` to fix its behaviour.
- Use `eof = -1` in `EVP_DecodeFinal` to count it in `evp_decodeblock_int`.
- Do not ignore padding in `EVP_DecodeBlock` (`eof = 0`) because it should write padding zeros according to the documentation.
- Add the HISTORY section to EVP_EncodeInit documentation to describe the fix.

Other changes:
- Update AUTHORS.md
- Update the copyright date in the documentation.

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26678)
This commit is contained in:
Valerii Krygin 2025-02-25 15:57:26 +00:00
parent 6ef393b89b
commit f86acc9434
5 changed files with 89 additions and 16 deletions

View file

@ -19,7 +19,7 @@ static unsigned char conv_ascii2bin(unsigned char a,
static int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
const unsigned char *f, int dlen);
static int evp_decodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
const unsigned char *f, int n);
const unsigned char *f, int n, int eof);
#ifndef CHARSET_EBCDIC
# define conv_bin2ascii(a, table) ((table)[(a)&0x3f])
@ -369,14 +369,14 @@ int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
}
if (n == 64) {
decoded_len = evp_decodeblock_int(ctx, out, d, n);
decoded_len = evp_decodeblock_int(ctx, out, d, n, eof);
n = 0;
if (decoded_len < 0 || eof > decoded_len) {
if (decoded_len < 0 || (decoded_len == 0 && eof > 0)) {
rv = -1;
goto end;
}
ret += decoded_len - eof;
out += decoded_len - eof;
ret += decoded_len;
out += decoded_len;
}
}
@ -388,13 +388,13 @@ int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
tail:
if (n > 0) {
if ((n & 3) == 0) {
decoded_len = evp_decodeblock_int(ctx, out, d, n);
decoded_len = evp_decodeblock_int(ctx, out, d, n, eof);
n = 0;
if (decoded_len < 0 || eof > decoded_len) {
if (decoded_len < 0 || (decoded_len == 0 && eof > 0)) {
rv = -1;
goto end;
}
ret += (decoded_len - eof);
ret += decoded_len;
} else if (seof) {
/* EOF in the middle of a base64 block. */
rv = -1;
@ -411,12 +411,16 @@ end:
}
static int evp_decodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
const unsigned char *f, int n)
const unsigned char *f, int n,
int eof)
{
int i, ret = 0, a, b, c, d;
unsigned long l;
const unsigned char *table;
if (eof < -1 || eof > 2)
return -1;
if (ctx != NULL && (ctx->flags & EVP_ENCODE_CTX_USE_SRP_ALPHABET) != 0)
table = srpdata_ascii2bin;
else
@ -437,8 +441,11 @@ static int evp_decodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
if (n % 4 != 0)
return -1;
if (n == 0)
return 0;
for (i = 0; i < n; i += 4) {
/* all 4-byte blocks except the last one do not have padding. */
for (i = 0; i < n - 4; i += 4) {
a = conv_ascii2bin(*(f++), table);
b = conv_ascii2bin(*(f++), table);
c = conv_ascii2bin(*(f++), table);
@ -453,12 +460,43 @@ static int evp_decodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
*(t++) = (unsigned char)(l) & 0xff;
ret += 3;
}
/* process the last block that may have padding. */
a = conv_ascii2bin(*(f++), table);
b = conv_ascii2bin(*(f++), table);
c = conv_ascii2bin(*(f++), table);
d = conv_ascii2bin(*(f++), table);
if ((a | b | c | d) & 0x80)
return -1;
l = ((((unsigned long)a) << 18L) |
(((unsigned long)b) << 12L) |
(((unsigned long)c) << 6L) | (((unsigned long)d)));
if (eof == -1)
eof = (f[2] == '=') + (f[3] == '=');
switch (eof) {
case 2:
*(t++) = (unsigned char)(l >> 16L) & 0xff;
break;
case 1:
*(t++) = (unsigned char)(l >> 16L) & 0xff;
*(t++) = (unsigned char)(l >> 8L) & 0xff;
break;
case 0:
*(t++) = (unsigned char)(l >> 16L) & 0xff;
*(t++) = (unsigned char)(l >> 8L) & 0xff;
*(t++) = (unsigned char)(l) & 0xff;
break;
}
ret += 3 - eof;
return ret;
}
int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n)
{
return evp_decodeblock_int(NULL, t, f, n);
return evp_decodeblock_int(NULL, t, f, n, 0);
}
int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
@ -467,7 +505,7 @@ int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
*outl = 0;
if (ctx->num != 0) {
i = evp_decodeblock_int(ctx, out, ctx->enc_data, ctx->num);
i = evp_decodeblock_int(ctx, out, ctx->enc_data, ctx->num, -1);
if (i < 0)
return -1;
ctx->num = 0;