aboutsummaryrefslogtreecommitdiff
path: root/crypto/evp/encode.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/evp/encode.c')
-rw-r--r--crypto/evp/encode.c66
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;