Commit c478df55d5 for openssl.org
commit c478df55d50d5e5b97ae730a54dc324fd3263d90
Author: Alexandr Nedvedicky <sashan@openssl.org>
Date: Tue Jan 13 18:08:58 2026 +0100
BIO_FLAGS_BASE64_NO_NL ignored by b64_write() in OpenSSL 4.0.0
Fixes #29618
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/29629)
diff --git a/crypto/evp/bio_b64.c b/crypto/evp/bio_b64.c
index 7b3decd2bf..2eab67caba 100644
--- a/crypto/evp/bio_b64.c
+++ b/crypto/evp/bio_b64.c
@@ -13,6 +13,7 @@
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include "internal/bio.h"
+#include "crypto/evp.h"
static int b64_write(BIO *h, const char *buf, int num);
static int b64_read(BIO *h, char *buf, int size);
@@ -334,6 +335,9 @@ static int b64_write(BIO *b, const char *in, int inl)
int i;
BIO_B64_CTX *ctx;
BIO *next;
+ int encoded_length;
+ unsigned char *encoded;
+ int n_bytes_enc;
ctx = (BIO_B64_CTX *)BIO_get_data(b);
next = BIO_next(b);
@@ -348,6 +352,8 @@ static int b64_write(BIO *b, const char *in, int inl)
ctx->buf_off = 0;
ctx->tmp_len = 0;
EVP_EncodeInit(ctx->base64);
+ if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)
+ evp_encode_ctx_set_flags(ctx->base64, EVP_ENCODE_CTX_NO_NEWLINES);
}
if (!ossl_assert(ctx->buf_off < (int)sizeof(ctx->buf))) {
ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR);
@@ -386,7 +392,7 @@ static int b64_write(BIO *b, const char *in, int inl)
if (in == NULL || inl <= 0)
return 0;
- int encoded_length = EVP_ENCODE_LENGTH(inl);
+ encoded_length = EVP_ENCODE_LENGTH(inl);
if (ctx->encoded_buf == NULL || (size_t)encoded_length > ctx->encoded_buf_len) {
OPENSSL_free(ctx->encoded_buf);
@@ -398,13 +404,13 @@ static int b64_write(BIO *b, const char *in, int inl)
ctx->encoded_buf_len = encoded_length;
}
- unsigned char *encoded = ctx->encoded_buf;
+ encoded = ctx->encoded_buf;
if (encoded == NULL) {
ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
return -1;
}
- int n_bytes_enc = 0;
+ n_bytes_enc = 0;
if (!EVP_EncodeUpdate(ctx->base64, encoded, &n_bytes_enc,
(unsigned char *)in, inl)) {
return -1;
@@ -470,15 +476,7 @@ static long b64_ctrl(BIO *b, int cmd, long num, void *ptr)
if (i < 0)
return i;
}
- if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
- if (ctx->tmp_len != 0) {
- ctx->buf_len = EVP_EncodeBlock(ctx->buf,
- ctx->tmp, ctx->tmp_len);
- ctx->buf_off = 0;
- ctx->tmp_len = 0;
- goto again;
- }
- } else if (ctx->encode != B64_NONE
+ if (ctx->encode != B64_NONE
&& EVP_ENCODE_CTX_num(ctx->base64) != 0) {
ctx->buf_off = 0;
EVP_EncodeFinal(ctx->base64, ctx->buf, &(ctx->buf_len));
diff --git a/test/bio_base64_test.c b/test/bio_base64_test.c
index 733bfa1b7d..dbdce741f4 100644
--- a/test/bio_base64_test.c
+++ b/test/bio_base64_test.c
@@ -428,6 +428,45 @@ static int test_bio_base64_corner_case_bug(int idx)
return generic_case(&t, 0);
}
+#define MEM_CHK "QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB" \
+ "QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB" \
+ "QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB"
+
+static int test_bio_base64_no_nl(void)
+{
+ char msg[120];
+ BIO *b64 = NULL;
+ BIO *mem = NULL;
+ BIO *b64_chk;
+ BUF_MEM *bptr = NULL;
+ int ok = 0;
+
+ memset(msg, 'A', sizeof(msg));
+
+ b64 = BIO_new(BIO_f_base64());
+ if (!TEST_ptr(b64))
+ goto done;
+
+ mem = BIO_new(BIO_s_mem());
+ if (!TEST_ptr(mem))
+ goto done;
+
+ b64_chk = BIO_push(b64, mem);
+ if (!TEST_ptr_eq(b64, b64_chk))
+ goto done;
+
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+ BIO_write(b64, msg, sizeof(msg));
+ if (!TEST_true(BIO_flush(b64)))
+ goto done;
+ BIO_get_mem_ptr(mem, &bptr);
+ ok = TEST_mem_eq(MEM_CHK, sizeof(MEM_CHK) - 1, bptr->data, bptr->length);
+
+done:
+ BIO_free_all(b64);
+ return ok;
+}
+
int setup_tests(void)
{
int numidx;
@@ -483,5 +522,6 @@ int setup_tests(void)
numidx = 2 * 2;
ADD_ALL_TESTS(test_bio_base64_corner_case_bug, numidx);
+ ADD_TEST(test_bio_base64_no_nl);
return 1;
}