From 900bcf745f963592c257d248f14ef7cff3219dd2 Mon Sep 17 00:00:00 2001 From: Yosuke Shimizu Date: Mon, 31 Aug 2026 10:28:42 +0900 Subject: [PATCH] ssl_bn: skip truncation shift for byte-aligned BN_rand requests - wolfSSL_BN_rand() calls mp_rshb() only when bits is not a multiple of 8. - test_wolfSSL_BN_rand() declares i and seen, and samples 8-bit TOP_ANY, 16-bit TOP_ANY, and 8-bit TOP_ONE requests to assert the results are not confined to the low byte. Issue: F-12559 --- src/ssl_bn.c | 4 ++-- tests/api/test_ossl_bn.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/ssl_bn.c b/src/ssl_bn.c index d637a5a260..86f81aa7a9 100644 --- a/src/ssl_bn.c +++ b/src/ssl_bn.c @@ -2167,8 +2167,8 @@ int wolfSSL_BN_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom) /* Dispose of buffer - no longer needed. */ XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (ret == 1) { - /* Truncate to requested bit length. */ + /* Truncate to requested bit length when not a whole number of bytes. */ + if ((ret == 1) && ((bits % 8) != 0)) { mp_rshb((mp_int*)bn->internal, 8 - (bits % 8)); } diff --git a/tests/api/test_ossl_bn.c b/tests/api/test_ossl_bn.c index c4872120f2..46d3f67cd4 100644 --- a/tests/api/test_ossl_bn.c +++ b/tests/api/test_ossl_bn.c @@ -921,6 +921,8 @@ int test_wolfSSL_BN_rand(void) BIGNUM* bn = NULL; BIGNUM* range = NULL; BIGNUM emptyBN; + int i; + int seen; XMEMSET(&emptyBN, 0, sizeof(emptyBN)); ExpectNotNull(bn = BN_new()); @@ -1045,6 +1047,42 @@ int test_wolfSSL_BN_rand(void) WOLFSSL_BN_RAND_BOTTOM_ANY), 1); ExpectIntEQ(BN_num_bits(bn), 13); + /* A request for a multiple of 8 bits keeps every generated bit. Shifting + * out a whole byte would make the 8-bit values zero, hold the 16-bit + * values in the low byte, and fix the 8-bit top bit results at 0x80. */ + seen = 0; + for (i = 0; (i < 64) && EXPECT_SUCCESS(); i++) { + ExpectIntEQ(BN_rand(bn, 8, WOLFSSL_BN_RAND_TOP_ANY, + WOLFSSL_BN_RAND_BOTTOM_ANY), 1); + if (EXPECT_SUCCESS() && (BN_is_zero(bn) == 0)) { + seen = 1; + break; + } + } + ExpectIntEQ(seen, 1); + + seen = 0; + for (i = 0; (i < 64) && EXPECT_SUCCESS(); i++) { + ExpectIntEQ(BN_rand(bn, 16, WOLFSSL_BN_RAND_TOP_ANY, + WOLFSSL_BN_RAND_BOTTOM_ANY), 1); + if (EXPECT_SUCCESS() && (BN_num_bits(bn) > 8)) { + seen = 1; + break; + } + } + ExpectIntEQ(seen, 1); + + seen = 0; + for (i = 0; (i < 64) && EXPECT_SUCCESS(); i++) { + ExpectIntEQ(BN_pseudo_rand(bn, 8, WOLFSSL_BN_RAND_TOP_ONE, + WOLFSSL_BN_RAND_BOTTOM_ANY), 1); + if (EXPECT_SUCCESS() && (BN_get_word(bn) != 0x80)) { + seen = 1; + break; + } + } + ExpectIntEQ(seen, 1); + ExpectIntEQ(BN_rand(range, 64, WOLFSSL_BN_RAND_TOP_ONE, WOLFSSL_BN_RAND_BOTTOM_ANY), 1); ExpectIntEQ(BN_rand_range(bn, range), 1);