diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index ead4a2daf6..32351f8334 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -23,7 +23,7 @@ jobs: check_filenames: true check_hidden: true # Add comma separated list of words that occur multiple times that should be ignored (sorted alphabetically, case sensitive) - ignore_words_list: adin,aNULL,brunch,carryIn,chainG,ciph,cLen,cliKs,dout,haveA,inCreated,inOut,inout,larg,LEAPYEAR,Merget,optionA,parm,parms,repid,rIn,userA,ser,siz,te,Te,HSI,failT, + ignore_words_list: adin,aNULL,brunch,carryIn,chainG,ciph,cLen,cliKs,dout,haveA,inCreated,inOut,inout,larg,LEAPYEAR,Merget,optionA,parm,parms,repid,rIn,userA,ser,siz,te,Te,HSI,failT,toLen, # The exclude_file contains lines of code that should be ignored. This is useful for individual lines which have non-words that can safely be ignored. exclude_file: '.codespellexcludelines' # To skip files entirely from being processed, add it to the following list: diff --git a/.github/workflows/openvpn.yml b/.github/workflows/openvpn.yml index 6fcfd1b7ec..56eb454530 100644 --- a/.github/workflows/openvpn.yml +++ b/.github/workflows/openvpn.yml @@ -42,9 +42,7 @@ jobs: strategy: fail-fast: false matrix: - # Pinned refs: avoid OpenVPN master until wolfSSL adds any new OpenSSL - # APIs it adopts (e.g. BN_bn2binpad). release/2.6 + latest stable tag. - ref: [ release/2.6, v2.6.19 ] + ref: [ master, release/2.6, v2.6.19 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' runs-on: ubuntu-24.04 diff --git a/src/ssl_bn.c b/src/ssl_bn.c index e3b758beb2..74d828da93 100644 --- a/src/ssl_bn.c +++ b/src/ssl_bn.c @@ -468,6 +468,56 @@ int wolfSSL_BN_bn2bin(const WOLFSSL_BIGNUM* bn, unsigned char* r) } +/* Encode a big number as a big-endian byte array, zero-padded to toLen bytes. + * + * Returns toLen on success, -1 on error (including when the number is too + * large to fit in toLen bytes). + * + * @param [in] bn Big number to encode. + * @param [out] r Buffer to place encoding into. Must be at least toLen + * bytes. + * @param [in] toLen Desired output length in bytes. + * @return toLen on success. + * @return -1 on error. + */ +int wolfSSL_BN_bn2binpad(const WOLFSSL_BIGNUM* bn, unsigned char* r, int toLen) +{ + int numBytes; + + WOLFSSL_ENTER("wolfSSL_BN_bn2binpad"); + + /* Validate parameters. */ + if (BN_IS_NULL(bn) || (r == NULL) || (toLen < 0)) { + WOLFSSL_MSG("NULL bn, r, or invalid toLen error"); + return WOLFSSL_FATAL_ERROR; + } + + /* Get the number of bytes needed to encode the big number. */ + numBytes = mp_unsigned_bin_size((mp_int*)bn->internal); + if (numBytes < 0) { + WOLFSSL_MSG("mp_unsigned_bin_size error"); + return WOLFSSL_FATAL_ERROR; + } + if (numBytes > toLen) { + WOLFSSL_MSG("BN too large for toLen"); + return WOLFSSL_FATAL_ERROR; + } + + /* Zero-pad leading bytes. */ + XMEMSET(r, 0, (size_t)(toLen - numBytes)); + + /* Encode the big number into the remaining bytes. */ + if (numBytes > 0 && + mp_to_unsigned_bin((mp_int*)bn->internal, r + toLen - numBytes) != + MP_OKAY) { + WOLFSSL_MSG("mp_to_unsigned_bin error"); + return WOLFSSL_FATAL_ERROR; + } + + return toLen; +} + + /* Return a big number with value of the decoding of the big-endian byte array. * * Returns ret when not NULL. diff --git a/tests/api/test_ossl_bn.c b/tests/api/test_ossl_bn.c index 3d9db919f2..61b036e545 100644 --- a/tests/api/test_ossl_bn.c +++ b/tests/api/test_ossl_bn.c @@ -323,6 +323,39 @@ int test_wolfSSL_BN_enc_dec(void) ExpectNotNull(BN_bin2bn(binNum, sizeof(binNum), b)); ExpectIntEQ(BN_cmp(a, b), -1); + /* BN_bn2binpad tests */ + { + unsigned char padOut[5]; + + /* Invalid parameters */ + ExpectIntEQ(BN_bn2binpad(NULL, padOut, sizeof(padOut)), -1); + ExpectIntEQ(BN_bn2binpad(&emptyBN, padOut, sizeof(padOut)), -1); + ExpectIntEQ(BN_bn2binpad(a, NULL, sizeof(padOut)), -1); + ExpectIntEQ(BN_bn2binpad(a, padOut, -1), -1); + /* toLen too small for the value */ + ExpectNotNull(BN_bin2bn(binNum, sizeof(binNum), b)); + ExpectIntEQ(BN_bn2binpad(b, padOut, 2), -1); + /* Normal case: a = 2, padded to 5 bytes */ + XMEMSET(padOut, 0xFF, sizeof(padOut)); + ExpectIntEQ(BN_bn2binpad(a, padOut, 5), 5); + ExpectIntEQ(padOut[0], 0x00); + ExpectIntEQ(padOut[1], 0x00); + ExpectIntEQ(padOut[2], 0x00); + ExpectIntEQ(padOut[3], 0x00); + ExpectIntEQ(padOut[4], 0x02); + /* Exact size (no padding needed) */ + ExpectIntEQ(BN_bn2binpad(a, padOut, 1), 1); + ExpectIntEQ(padOut[0], 0x02); + /* Zero value padded to 3 bytes */ + ExpectIntEQ(BN_set_word(a, 0), 1); + ExpectIntEQ(BN_bn2binpad(a, padOut, 3), 3); + ExpectIntEQ(padOut[0], 0x00); + ExpectIntEQ(padOut[1], 0x00); + ExpectIntEQ(padOut[2], 0x00); + /* Restore a = 2 for subsequent tests */ + ExpectIntEQ(BN_set_word(a, 2), 1); + } + ExpectNotNull(str = BN_bn2hex(a)); ExpectNotNull(BN_hex2bn(&b, str)); ExpectIntEQ(BN_cmp(a, b), 0); diff --git a/wolfssl/openssl/bn.h b/wolfssl/openssl/bn.h index 392aebac5f..7371f8a03a 100644 --- a/wolfssl/openssl/bn.h +++ b/wolfssl/openssl/bn.h @@ -135,6 +135,8 @@ WOLFSSL_API int wolfSSL_BN_cmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b) WOLFSSL_API int wolfSSL_BN_ucmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b); WOLFSSL_API int wolfSSL_BN_bn2bin(const WOLFSSL_BIGNUM* bn, unsigned char* r); +WOLFSSL_API int wolfSSL_BN_bn2binpad(const WOLFSSL_BIGNUM* bn, unsigned char* r, + int toLen); WOLFSSL_API WOLFSSL_BIGNUM* wolfSSL_BN_bin2bn(const unsigned char* str, int len, WOLFSSL_BIGNUM* ret); @@ -246,8 +248,9 @@ typedef WOLFSSL_BN_GENCB BN_GENCB; #define BN_cmp wolfSSL_BN_cmp #define BN_ucmp wolfSSL_BN_ucmp -#define BN_bn2bin wolfSSL_BN_bn2bin -#define BN_bin2bn wolfSSL_BN_bin2bn +#define BN_bn2bin wolfSSL_BN_bn2bin +#define BN_bn2binpad wolfSSL_BN_bn2binpad +#define BN_bin2bn wolfSSL_BN_bin2bn #define BN_mod wolfSSL_BN_mod #define BN_mod_exp wolfSSL_BN_mod_exp