From: Alexandr Nedvedicky Date: Tue, 13 Jan 2026 17:08:58 +0000 (+0100) Subject: BIO_FLAGS_BASE64_NO_NL ignored by b64_write() in OpenSSL 4.0.0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c478df55d50d5e5b97ae730a54dc324fd3263d90;p=thirdparty%2Fopenssl.git BIO_FLAGS_BASE64_NO_NL ignored by b64_write() in OpenSSL 4.0.0 Fixes #29618 Reviewed-by: Paul Dale Reviewed-by: Nikola Pajkovsky Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/29629) --- diff --git a/crypto/evp/bio_b64.c b/crypto/evp/bio_b64.c index 7b3decd2bfd..2eab67caba7 100644 --- a/crypto/evp/bio_b64.c +++ b/crypto/evp/bio_b64.c @@ -13,6 +13,7 @@ #include #include #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 733bfa1b7d6..dbdce741f43 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; }