diff options
Diffstat (limited to 'crypto/evp/encode.c')
-rw-r--r-- | crypto/evp/encode.c | 66 |
1 files changed, 52 insertions, 14 deletions
diff --git a/crypto/evp/encode.c b/crypto/evp/encode.c index 2c047fa039ae..9bbb9b43aa42 100644 --- a/crypto/evp/encode.c +++ b/crypto/evp/encode.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -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,13 +441,16 @@ 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); d = conv_ascii2bin(*(f++), table); - if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) + if ((a | b | c | d) & 0x80) return -1; l = ((((unsigned long)a) << 18L) | (((unsigned long)b) << 12L) | @@ -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; |