Files
wolfssl/src/ssl_bn.c
Daniel Pouzzner b2c105d5f7 Merge pull request #9292 from embhorn/zd20626
Fix GCC warnings
2025-10-13 23:17:13 -05:00

2582 lines
71 KiB
C

/* ssl_bn.c
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#include <wolfssl/internal.h>
#ifndef WC_NO_RNG
#include <wolfssl/wolfcrypt/random.h>
#endif
#if !defined(WOLFSSL_SSL_BN_INCLUDED)
#ifndef WOLFSSL_IGNORE_FILE_WARN
#warning ssl_bn.c does not need to be compiled separately from ssl.c
#endif
#else
/* Check on validity of big number.
*
* Used for parameter validation.
*
* @param [in] bn Big number.
* @return 1 when bn is not NULL and internal representation is not NULL.
* @return 0 otherwise.
*/
#define BN_IS_NULL(bn) (((bn) == NULL) || ((bn)->internal == NULL))
/*******************************************************************************
* Constructor/Destructor/Initializer APIs
******************************************************************************/
#if defined(OPENSSL_EXTRA) && !defined(NO_ASN)
/* Set big number to be negative.
*
* @param [in, out] bn Big number to make negative.
* @param [in] neg Whether number is negative.
* @return 1 on success.
* @return -1 when bn or internal representation of bn is NULL.
*/
static int wolfssl_bn_set_neg(WOLFSSL_BIGNUM* bn, int neg)
{
int ret = 1;
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
#if !defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_SP_INT_NEGATIVE)
else if (neg) {
mp_setneg((mp_int*)bn->internal);
}
else {
((mp_int*)bn->internal)->sign = MP_ZPOS;
}
#endif
return ret;
}
#endif /* OPENSSL_EXTRA && !NO_ASN */
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
/* Get the internal representation value into an MP integer.
*
* When calling wolfssl_bn_get_value, mpi should be cleared by caller if no
* longer used. ie mp_free(mpi). This is to free data when fastmath is
* disabled since a copy of mpi is made by this function and placed into bn.
*
* @param [in] bn Big number to copy value from.
* @param [in, out] mpi MP integer to copy into.
* @return 1 on success.
* @return -1 when bn or internal representation of bn is NULL.
* @return -1 when mpi is NULL.
* @return -1 when copy fails.
*/
int wolfssl_bn_get_value(WOLFSSL_BIGNUM* bn, mp_int* mpi)
{
int ret = 1;
WOLFSSL_MSG("Entering wolfssl_bn_get_value_mp");
/* Validate parameters. */
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
else if (mpi == NULL) {
WOLFSSL_MSG("mpi NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
/* Copy the internal representation into MP integer. */
if ((ret == 1) && mp_copy((mp_int*)bn->internal, mpi) != MP_OKAY) {
WOLFSSL_MSG("mp_copy error");
ret = WOLFSSL_FATAL_ERROR;
}
return ret;
}
/* Set big number internal representation to value in mpi.
*
* Will create a new big number if bn points to NULL.
*
* When calling wolfssl_bn_set_value, mpi should be cleared by caller if no
* longer used. ie mp_free(mpi). This is to free data when fastmath is
* disabled since a copy of mpi is made by this function and placed into bn.
*
* @param [in, out] bn Pointer to big number to have value.
* @param [in] mpi MP integer with value to set.
* @return 1 on success.
* @return -1 when mpi or bn is NULL.
* @return -1 when creating a new big number fails.
* @return -1 when copying MP integer fails.
*/
int wolfssl_bn_set_value(WOLFSSL_BIGNUM** bn, mp_int* mpi)
{
int ret = 1;
WOLFSSL_BIGNUM* a = NULL;
#ifdef WOLFSSL_DEBUG_OPENSSL
WOLFSSL_ENTER("wolfssl_bn_set_value");
#endif
/* Validate parameters. */
if ((bn == NULL) || (mpi == NULL)) {
WOLFSSL_MSG("mpi or bn NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
/* Allocate a new big number if one not passed in. */
if ((ret == 1) && (*bn == NULL)) {
a = wolfSSL_BN_new();
if (a == NULL) {
WOLFSSL_MSG("wolfssl_bn_set_value alloc failed");
ret = WOLFSSL_FATAL_ERROR;
}
*bn = a;
}
/* Copy MP integer value into internal representation of big number. */
if ((ret == 1) && (mp_copy(mpi, (mp_int*)((*bn)->internal)) != MP_OKAY)) {
WOLFSSL_MSG("mp_copy error");
ret = WOLFSSL_FATAL_ERROR;
}
/* Dispose of any allocated big number on error. */
if ((ret == -1) && (a != NULL)) {
wolfSSL_BN_free(a);
*bn = NULL;
}
return ret;
}
/* Initialize a big number.
*
* Assumes bn is not NULL.
*
* @param [in, out] bn Big number to initialize.
*/
static void wolfssl_bn_init(WOLFSSL_BIGNUM* bn)
{
/* Clear fields of big number. */
XMEMSET(bn, 0, sizeof(WOLFSSL_BIGNUM));
/* Initialization only fails when passed NULL. */
(void)mp_init(&bn->mpi);
/* Set an internal representation. */
bn->internal = &bn->mpi;
}
/* Create a new big number.
*
* @return An allocated and initialized big number on success.
* @return NULL on failure.
*/
WOLFSSL_BIGNUM* wolfSSL_BN_new(void)
{
WOLFSSL_BIGNUM* bn = NULL;
#ifdef WOLFSSL_DEBUG_OPENSSL
WOLFSSL_ENTER("wolfSSL_BN_new");
#endif
/* Allocate memory for big number. */
bn = (WOLFSSL_BIGNUM*)XMALLOC(sizeof(WOLFSSL_BIGNUM), NULL,
DYNAMIC_TYPE_BIGINT);
if (bn == NULL) {
WOLFSSL_MSG("wolfSSL_BN_new malloc WOLFSSL_BIGNUM failure");
}
else {
/* Initialize newly allocated object. */
wolfssl_bn_init(bn);
}
return bn;
}
#if !defined(USE_INTEGER_HEAP_MATH) && !defined(HAVE_WOLF_BIGINT)
/* Initialize a big number.
*
* Call this instead of wolfSSL_BN_new() and wolfSSL_BN_free().
*
* Do not call this API after wolfSSL_BN_new() or wolfSSL_BN_init().
*
* @param [in, out] bn Big number to initialize.
*/
void wolfSSL_BN_init(WOLFSSL_BIGNUM* bn)
{
#ifdef WOLFSSL_DEBUG_OPENSSL
WOLFSSL_ENTER("wolfSSL_BN_init");
#endif
/* Validate parameter. */
if (bn != NULL) {
/* Initialize big number object. */
wolfssl_bn_init(bn);
}
}
#endif
/* Dispose of big number.
*
* bn is unusable after this call.
*
* @param [in, out] bn Big number to free.
*/
void wolfSSL_BN_free(WOLFSSL_BIGNUM* bn)
{
#ifdef WOLFSSL_DEBUG_OPENSSL
WOLFSSL_ENTER("wolfSSL_BN_free");
#endif
/* Validate parameter. */
if (bn != NULL) {
/* Cleanup any internal representation. */
if (bn->internal != NULL) {
/* Free MP integer. */
mp_free(&bn->mpi);
}
/* Dispose of big number object. */
XFREE(bn, NULL, DYNAMIC_TYPE_BIGINT);
/* bn = NULL, don't try to access or double free it */
}
}
/* Zeroize and dispose of big number.
*
* bn is unusable after this call.
*
* @param [in, out] bn Big number to clear and free.
*/
void wolfSSL_BN_clear_free(WOLFSSL_BIGNUM* bn)
{
#ifdef WOLFSSL_DEBUG_OPENSSL
WOLFSSL_ENTER("wolfSSL_BN_clear_free");
#endif
/* Validate parameter. */
if (bn != NULL) {
/* Check for internal representation. */
if (bn->internal != NULL) {
/* Zeroize MP integer. */
mp_forcezero((mp_int*)bn->internal);
}
/* Dispose of big number. */
wolfSSL_BN_free(bn);
}
}
/* Zeroize big number.
*
* @param [in, out] bn Big number to clear.
*/
void wolfSSL_BN_clear(WOLFSSL_BIGNUM* bn)
{
#ifdef WOLFSSL_DEBUG_OPENSSL
WOLFSSL_ENTER("wolfSSL_BN_clear");
#endif
/* Validate parameter. */
if (!BN_IS_NULL(bn)) {
/* Zeroize MP integer. */
mp_forcezero((mp_int*)bn->internal);
}
}
#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
#ifdef OPENSSL_EXTRA
static WOLFSSL_BIGNUM* bn_one = NULL;
/* Return a big number with the value of one.
*
* @return A big number with the value one on success.
* @return NULL on failure.
*/
const WOLFSSL_BIGNUM* wolfSSL_BN_value_one(void)
{
WOLFSSL_BIGNUM* one;
WOLFSSL_ENTER("wolfSSL_BN_value_one");
/* Get the global object. */
one = bn_one;
/* Create a new big number if global not set. */
if ((one == NULL) && ((one = wolfSSL_BN_new()) != NULL)) {
/* Set internal representation to have a value of 1. */
if (mp_set_int((mp_int*)one->internal, 1) != MP_OKAY) {
/* Dispose of big number on error. */
wolfSSL_BN_free(one);
one = NULL;
}
else
#ifndef SINGLE_THREADED
/* Ensure global has not been set by another thread. */
if (bn_one == NULL)
#endif
{
/* Set this big number as the global. */
bn_one = one;
}
#ifndef SINGLE_THREADED
/* Check if another thread has set the global. */
if (bn_one != one) {
/* Dispose of this big number and return the global. */
wolfSSL_BN_free(one);
one = bn_one;
}
#endif
}
return one;
}
static void wolfSSL_BN_free_one(void) {
wolfSSL_BN_free(bn_one);
bn_one = NULL;
}
/* Create a new big number with the same value as the one passed in.
*
* @param [in] bn Big number to duplicate.
* @return Big number on success.
* @return NULL when bn or internal representation of bn is NULL.
* @return NULL when creating a new big number fails.
* @return NULL when copying the internal representation fails.
*/
WOLFSSL_BIGNUM* wolfSSL_BN_dup(const WOLFSSL_BIGNUM* bn)
{
int err = 0;
WOLFSSL_BIGNUM* ret = NULL;
WOLFSSL_ENTER("wolfSSL_BN_dup");
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
err = 1;
}
/* Create a new big number to return. */
if ((!err) && ((ret = wolfSSL_BN_new()) == NULL)) {
WOLFSSL_MSG("bn new error");
err = 1;
}
if (!err) {
err = (wolfSSL_BN_copy(ret, bn) == NULL);
}
if (err) {
/* Dispose of dynamically allocated data. */
wolfSSL_BN_free(ret);
ret = NULL;
}
return ret;
}
/* Copy value from bn into another r.
*
* @param [in, out] r Big number to copy into.
* @param [in] bn Big number to copy from.
* @return Big number copied into on success.
* @return NULL when r or bn is NULL.
* @return NULL when copying fails.
*/
WOLFSSL_BIGNUM* wolfSSL_BN_copy(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* bn)
{
WOLFSSL_ENTER("wolfSSL_BN_copy");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(bn)) {
WOLFSSL_MSG("r or bn NULL error");
r = NULL;
}
/* Copy the value in. */
if ((r != NULL) && mp_copy((mp_int*)bn->internal, (mp_int*)r->internal) !=
MP_OKAY) {
WOLFSSL_MSG("mp_copy error");
r = NULL;
}
if (r != NULL) {
/* Copy other fields in a big number. */
r->neg = bn->neg;
}
return r;
}
/*******************************************************************************
* Encode/Decode APIs.
******************************************************************************/
/* Encode the number is a big-endian byte array.
*
* Assumes byte array is large enough to hold encoding when not NULL.
* Use NULL for byte array to get length.
*
* Return compliant with OpenSSL.
*
* @param [in] bn Big number to reduced
* @param [out] r Byte array to encode into. May be NULL.
* @return Length of big number in bytes on success.
* @return -1 when bn is NULL or encoding fails.
*/
int wolfSSL_BN_bn2bin(const WOLFSSL_BIGNUM* bn, unsigned char* r)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_bn2bin");
/* Validate parameters. */
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("NULL bn error");
ret = WOLFSSL_FATAL_ERROR;
}
else {
/* Get the length of the encoding. */
ret = mp_unsigned_bin_size((mp_int*)bn->internal);
/* Encode if byte array supplied. */
if ((r != NULL) && (mp_to_unsigned_bin((mp_int*)bn->internal, r) !=
MP_OKAY)) {
WOLFSSL_MSG("mp_to_unsigned_bin error");
ret = WOLFSSL_FATAL_ERROR;
}
}
return ret;
}
/* Return a big number with value of the decoding of the big-endian byte array.
*
* Returns ret when not NULL.
* Allocates a big number when ret is NULL.
* Assumes str is not NULL.
*
* @param [in] data Byte array to decode.
* @param [in] len Number of bytes in byte array.
* @param [in, out] ret Big number to reduced. May be NULL.
* @return A big number on success.
* @return NULL on failure.
*/
WOLFSSL_BIGNUM* wolfSSL_BN_bin2bn(const unsigned char* data, int len,
WOLFSSL_BIGNUM* ret)
{
WOLFSSL_BIGNUM* bn = NULL;
WOLFSSL_ENTER("wolfSSL_BN_bin2bn");
/* Validate parameters. */
if (len < 0) {
ret = NULL;
}
/* Allocate a new big number when ret is NULL. */
else if (ret == NULL) {
ret = wolfSSL_BN_new();
bn = ret;
}
/* Check ret is usable. */
if (ret != NULL) {
/* Check internal representation is usable. */
if (ret->internal == NULL) {
ret = NULL;
}
else if (data != NULL) {
/* Decode into big number. */
if (mp_read_unsigned_bin((mp_int*)ret->internal, data, (word32)len)
!= 0) {
WOLFSSL_MSG("mp_read_unsigned_bin failure");
/* Don't return anything on failure. bn will be freed if set. */
ret = NULL;
}
else {
/* Don't free bn as we are returning it. */
bn = NULL;
}
}
else if (data == NULL) {
wolfSSL_BN_zero(ret);
/* Don't free bn as we are returning it. */
bn = NULL;
}
}
/* Dispose of allocated BN not being returned. */
wolfSSL_BN_free(bn);
return ret;
}
/* Encode the big number value into a string, of the radix, that is allocated.
*
* @param [in] bn Big number to encode.
* @param [in] radix Radix to encode to.
* @return String with encoding on success.
* @return NULL when bn or internal representation of bn is NULL.
* @return NULL on failure.
*/
static char* wolfssl_bn_bn2radix(const WOLFSSL_BIGNUM* bn, int radix)
{
int err = 0;
int len = 0;
char* str = NULL;
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
err = 1;
}
/* Determine length of encoding. */
if ((!err) && (mp_radix_size((mp_int*)bn->internal, radix, &len) !=
MP_OKAY)) {
WOLFSSL_MSG("mp_radix_size failure");
err = 1;
}
if (!err) {
/* Allocate string. */
str = (char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_OPENSSL);
if (str == NULL) {
WOLFSSL_MSG("BN_bn2hex malloc string failure");
err = 1;
}
}
/* Encode into string using wolfCrypt. */
if ((!err) && (mp_toradix((mp_int*)bn->internal, str, radix) != MP_OKAY)) {
err = 1;
}
if (err) {
/* Dispose of dynamically allocated data. */
XFREE(str, NULL, DYNAMIC_TYPE_OPENSSL);
/* Don't return freed string. */
str = NULL;
}
return str;
}
/* Encode the big number value into hex string that is allocated.
*
* @param [in] bn Big number to encode.
* @return String with encoding on success.
* @return NULL when bn or internal representation of bn is NULL.
* @return NULL on failure.
*/
char* wolfSSL_BN_bn2hex(const WOLFSSL_BIGNUM *bn)
{
WOLFSSL_ENTER("wolfSSL_BN_bn2hex");
return wolfssl_bn_bn2radix(bn, MP_RADIX_HEX);
}
/* Decode string of a radix into a big number.
*
* If bn is a pointer to NULL, then a new big number is allocated and assigned.
*
* Note on use: this function expects str to be an even length. It is
* converting pairs of bytes into 8-bit values. As an example, the RSA
* public exponent is commonly 0x010001. To get it to convert, you need
* to pass in the string "010001", it will fail if you use "10001". This
* is an affect of how Base16_Decode() works.
*
* @param [in, out] bn Pointer to a big number. May point to NULL.
* @param [in] str Hex string to decode.
* @param [in] radix Radix to decode from.
* @return 1 on success.
* @return 0 when bn or str is NULL or str is zero length.
* @return 0 when creating a new big number fails.
* @return 0 when decoding fails.
*/
static int wolfssl_bn_radix2bn(WOLFSSL_BIGNUM** bn, const char* str, int radix)
{
int ret = 1;
WOLFSSL_BIGNUM* a = NULL;
/* Validate parameters. */
if ((bn == NULL) || (str == NULL) || (str[0] == '\0')) {
WOLFSSL_MSG("Bad function argument");
ret = 0;
}
/* Check if we have a big number to decode into. */
if ((ret == 1) && (*bn == NULL)) {
/* Allocate a new big number. */
a = wolfSSL_BN_new();
if (a == NULL) {
WOLFSSL_MSG("BN new failed");
ret = 0;
}
/* Return allocated big number. */
*bn = a;
}
/* Decode hex string into internal representation. */
if ((ret == 1) && (mp_read_radix((mp_int*)(*bn)->internal, str, radix) !=
MP_OKAY)) {
WOLFSSL_MSG("Bad read_radix error");
ret = 0;
}
if ((ret == 0) && (a != NULL)) {
/* Dispose of big number. */
wolfSSL_BN_free(a);
/* Don't return freed big number. */
*bn = NULL;
}
return ret;
}
/* Decode hex string into a big number.
*
* If bn is a pointer to NULL, then a new big number is allocated and assigned.
*
* Note on use: this function expects str to be an even length. It is
* converting pairs of bytes into 8-bit values. As an example, the RSA
* public exponent is commonly 0x010001. To get it to convert, you need
* to pass in the string "010001", it will fail if you use "10001". This
* is an affect of how Base16_Decode() works.
*
* @param [in, out] bn Pointer to a big number. May point to NULL.
* @param [in] str Hex string to decode.
* @return 1 on success.
* @return 0 when bn or str is NULL or str is zero length.
* @return 0 when creating a new big number fails.
* @return 0 when decoding fails.
*/
int wolfSSL_BN_hex2bn(WOLFSSL_BIGNUM** bn, const char* str)
{
WOLFSSL_ENTER("wolfSSL_BN_hex2bn");
return wolfssl_bn_radix2bn(bn, str, MP_RADIX_HEX);
}
#if defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY)
/* Encode big number into decimal string.
*
* @param [in] bn Big number to encode.
* @return String with encoding on success.
* @return NULL when bn or internal representation of bn is NULL.
* @return NULL on failure.
*/
char* wolfSSL_BN_bn2dec(const WOLFSSL_BIGNUM *bn)
{
WOLFSSL_ENTER("wolfSSL_BN_bn2hex");
return wolfssl_bn_bn2radix(bn, MP_RADIX_DEC);
}
#else
/* Encode big number into decimal string.
*
* @param [in] bn Big number to encode.
* @return NULL as implementation not available.
*/
char* wolfSSL_BN_bn2dec(const WOLFSSL_BIGNUM* bn)
{
(void)bn;
WOLFSSL_ENTER("wolfSSL_BN_bn2dec");
return NULL;
}
#endif /* defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) */
#ifndef NO_RSA
/* Decode hex string into a big number.
*
* If bn is a pointer to NULL, then a new big number is allocated and assigned.
*
* Note on use: this function expects str to be an even length. It is
* converting pairs of bytes into 8-bit values. As an example, the RSA
* public exponent is commonly 0x010001. To get it to convert, you need
* to pass in the string "010001", it will fail if you use "10001". This
* is an affect of how Base16_Decode() works.
*
* @param [in, out] bn Pointer to a big number. May point to NULL.
* @param [in] str Hex string to decode.
* @return 1 on success.
* @return 0 when bn or str is NULL or str is zero length.
* @return 0 when creating a new big number fails.
* @return 0 when decoding fails.
*/
int wolfSSL_BN_dec2bn(WOLFSSL_BIGNUM** bn, const char* str)
{
WOLFSSL_ENTER("wolfSSL_BN_bn2dec");
return wolfssl_bn_radix2bn(bn, str, MP_RADIX_DEC);
}
#else
/* Decode hex string into a big number.
*
* @param [in, out] bn Pointer to a big number. May point to NULL.
* @param [in] str Hex string to decode.
* @return 0 as implementation not available..
*/
int wolfSSL_BN_dec2bn(WOLFSSL_BIGNUM** bn, const char* str)
{
(void)bn;
(void)str;
WOLFSSL_ENTER("wolfSSL_BN_bn2dec");
return 0;
}
#endif
/*******************************************************************************
* Get/Set APIs
******************************************************************************/
/* Calculate the number of bytes need to represent big number.
*
* Return compliant with OpenSSL.
*
* @param [in] bn Big number to use.
* @return Size of BIGNUM in bytes on success.
* @return 0 when bn or internal representation of bn is NULL.
*/
int wolfSSL_BN_num_bytes(const WOLFSSL_BIGNUM* bn)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_num_bytes");
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
ret = 0;
}
else {
/* Get size from wolfCrypt. */
ret = mp_unsigned_bin_size((mp_int*)bn->internal);
}
return ret;
}
/* Calculate the number of bits need to represent big number.
*
* Return compliant with OpenSSL.
*
* @param [in] bn Big number to use.
* @return Size of BIGNUM in bits on success.
* @return 0 when bn or internal representation of bn is NULL.
*/
int wolfSSL_BN_num_bits(const WOLFSSL_BIGNUM* bn)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_num_bits");
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
ret = 0;
}
else {
/* Get size from wolfCrypt. */
ret = mp_count_bits((mp_int*)bn->internal);
}
return ret;
}
/* Indicates whether a big number is negative.
*
* @param [in] bn Big number to use.
* @return 1 when number is negative.
* @return 0 when number is positive.
* @return 0 when bn is NULL.
*/
int wolfSSL_BN_is_negative(const WOLFSSL_BIGNUM* bn)
{
int ret;
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
ret = 0;
}
else {
/* Check sign with wolfCrypt. */
ret = mp_isneg((mp_int*)bn->internal);
}
return ret;
}
/* Indicates whether a big number is odd.
*
* Return compliant with OpenSSL.
*
* @param [in] bn Big number to use.
* @return 1 when number is odd.
* @return 0 when number is even.
* @return 0 when bn or internal representation of bn is NULL.
*/
int wolfSSL_BN_is_odd(const WOLFSSL_BIGNUM* bn)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_is_odd");
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
ret = 0;
}
else {
/* wolfCrypt checks whether value is odd. */
ret = (mp_isodd((mp_int*)bn->internal) == MP_YES);
}
return ret;
}
#ifndef NO_WOLFSSL_STUB
/* Mask the lowest n bits.
*
* TODO: mp_mod_2d()
*
* Return compliant with OpenSSL.
*
* @param [in, out] bn Big number to operation on.
* @param [in] n Number of bits.
* @return 0 on failure.
*/
int wolfSSL_mask_bits(WOLFSSL_BIGNUM* bn, int n)
{
(void)bn;
(void)n;
WOLFSSL_ENTER("wolfSSL_BN_mask_bits");
WOLFSSL_STUB("BN_mask_bits");
return 0;
}
#endif
/* Set a bit of the value in a big number.
*
* Return code compliant with OpenSSL.
*
* @param [in, out] bn Big number to modify.
* @return 1 on success.
* @return 0 when bn or internal representation of bn is NULL.
* @return 0 when failed to set bit.
*/
int wolfSSL_BN_set_bit(WOLFSSL_BIGNUM* bn, int n)
{
int ret = 1;
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
else if (mp_set_bit((mp_int*)bn->internal, n) != MP_OKAY) {
WOLFSSL_MSG("mp_set_bit error");
ret = 0;
}
return ret;
}
/* Clear a bit of the value in a big number.
*
* Return code compliant with OpenSSL.
*
* @param [in] bn Big number to check.
* @param [in] n Inidex of bit to check.
* @return 1 on success.
* @return 0 when bn or internal representation of bn is NULL.
* @return 0 when failed to clear bit.
*/
int wolfSSL_BN_clear_bit(WOLFSSL_BIGNUM* bn, int n)
{
int ret = 1;
WC_DECLARE_VAR(tmp, mp_int, 1, 0);
/* Validate parameters. */
if (BN_IS_NULL(bn) || (n < 0)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
/* Check if bit is set to clear. */
if ((ret == 1) && (mp_is_bit_set((mp_int*)bn->internal, n))) {
/* Allocate a new MP integer to hold bit to clear. */
WC_ALLOC_VAR_EX(tmp, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, ret=0);
if (ret == 1) {
/* Reset new MP integer. */
XMEMSET(tmp, 0, sizeof(mp_int));
if (mp_init(tmp) != MP_OKAY) {
ret = 0;
}
}
/* Set the bit to clear into temporary MP integer. */
if ((ret == 1) && (mp_set_bit(tmp, n) != MP_OKAY)) {
ret = 0;
}
/* Clear bit by sutraction. */
if ((ret == 1) && (mp_sub((mp_int*)bn->internal, tmp,
(mp_int*)bn->internal) != MP_OKAY)) {
ret = 0;
}
/* Free any dynamic memory in MP integer. */
mp_clear(tmp);
WC_FREE_VAR_EX(tmp, NULL, DYNAMIC_TYPE_BIGINT);
}
return ret;
}
/* Returns whether the bit is set in the value of the big number.
*
* When bn is NULL, returns 0.
*
* Return code compliant with OpenSSL.
*
* @param [in] bn Big number to check.
* @param [in] n Inidex of bit to check.
* @return 1 if bit set.
* @return 0 otherwise.
*/
int wolfSSL_BN_is_bit_set(const WOLFSSL_BIGNUM* bn, int n)
{
int ret;
/* Check for big number value. */
if (BN_IS_NULL(bn) || (n < 0)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
else {
/* Set bit with wolfCrypt. */
ret = mp_is_bit_set((mp_int*)bn->internal, (mp_digit)n);
}
return ret;
}
/* Set the big number to the value 0.
*
* @param [in, out] bn Big number to use.
*/
void wolfSSL_BN_zero(WOLFSSL_BIGNUM* bn)
{
/* Validate parameter. */
if (!BN_IS_NULL(bn)) {
/* Set wolfCrypt representation to 0. */
mp_zero((mp_int*)bn->internal);
}
}
/* Set the big number to the value 0.
*
* @param [in, out] bn Big number to use.
* @return 1 on success.
* @return 0 when bn or internal representation of bn is NULL.
*/
int wolfSSL_BN_one(WOLFSSL_BIGNUM* bn)
{
int ret;
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
ret = 0;
}
else {
/* Set to value one. */
ret = wolfSSL_BN_set_word(bn, 1);
}
return ret;
}
/* Get the value of the MP integer as a word.
*
* Assumes the MP integer value will fit in a word.
*
* @param [in] mp MP integer.
* @return Value of MP integer as an unsigned long.
*/
static WOLFSSL_BN_ULONG wolfssl_bn_get_word_1(mp_int *mp) {
#if DIGIT_BIT >= (SIZEOF_LONG * CHAR_BIT)
return (WOLFSSL_BN_ULONG)mp->dp[0];
#else
WOLFSSL_BN_ULONG ret = 0UL;
unsigned int i;
for (i = 0; i < (unsigned int)mp->used; ++i) {
ret |= ((WOLFSSL_BN_ULONG)mp->dp[i]) << (DIGIT_BIT * i);
}
return ret;
#endif
}
/* Return the value of big number as an unsigned long if possible.
*
* @param [in] bn Big number to get value from.
* @return Value or 0xFFFFFFFFL if bigger than unsigned long.
*/
WOLFSSL_BN_ULONG wolfSSL_BN_get_word(const WOLFSSL_BIGNUM* bn)
{
WOLFSSL_BN_ULONG ret;
WOLFSSL_ENTER("wolfSSL_BN_get_word");
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("Invalid argument");
ret = 0;
}
/* Check whether big number is to fit in an unsigned long. */
else if (wolfSSL_BN_num_bytes(bn) > (int)sizeof(unsigned long)) {
WOLFSSL_MSG("bignum is larger than unsigned long");
ret = WOLFSSL_BN_MAX_VAL;
}
else {
/* Get the word from the internal representation. */
ret = wolfssl_bn_get_word_1((mp_int*)bn->internal);
}
return ret;
}
/* Set the big number to the value in the word.
*
* Return code compliant with OpenSSL.
*
* @param [in, out] bn Big number to set.
* @param [in w Word to set.
* @return 1 on success.
* @return 0 when bn is NULL or setting value failed.
*/
int wolfSSL_BN_set_word(WOLFSSL_BIGNUM* bn, unsigned long w)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_BN_set_word");
/* Validate parameters. */
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
/* Set the word into the internal representation. */
if ((ret == 1) && (mp_set_int((mp_int*)bn->internal, w) != MP_OKAY)) {
WOLFSSL_MSG("mp_init_set_int error");
ret = 0;
}
return ret;
}
/*******************************************************************************
* Comparison APIs
******************************************************************************/
/* Compares two big numbers. a <=> b
*
* NULL equals NULL
* NULL less than not NULL
* not NULL greater than NULL.
*
* Return compliant with OpenSSL.
*
* @param [in] bn First big number to compare.
* @param [in] bn Second big number to compare.
* @return -1 when a is less than b (a < b).
* @return 0 when a is equal to b (a == b).
* @return 1 when a is greater than b (a > b).
* @return 0 when bn or internal representation of bn is NULL.
*/
int wolfSSL_BN_cmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b)
{
int ret;
int bIsNull;
WOLFSSL_ENTER("wolfSSL_BN_cmp");
/* Must know whether b is NULL. */
bIsNull = BN_IS_NULL(b);
/* Check whether a is NULL. */
if (BN_IS_NULL(a)) {
if (bIsNull) {
/* NULL equals NULL. */
ret = 0;
}
else {
ret = -1; /* NULL less than not NULL. */
}
}
else if (bIsNull) {
/* not NULL greater than NULL. */
ret = 1;
}
else {
PRAGMA_GCC_DIAG_PUSH
PRAGMA_GCC("GCC diagnostic ignored \"-Wduplicated-branches\"")
/* Compare big numbers with wolfCrypt. */
ret = mp_cmp((mp_int*)a->internal, (mp_int*)b->internal);
/* Convert wolfCrypt return value. */
if (ret == MP_EQ) {
ret = 0;
}
else if (ret == MP_GT) {
ret = 1;
}
else if (ret == MP_LT) {
ret = -1;
}
else {
/* ignored warning here because the same return value
was intentional */
ret = WOLFSSL_FATAL_ERROR; /* also -1 */
}
PRAGMA_GCC_DIAG_POP
}
return ret;
}
/* Same as above, but compare absolute value. */
int wolfSSL_BN_ucmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b)
{
int ret = 0;
int bIsNull;
WOLFSSL_ENTER("wolfSSL_BN_ucmp");
/* Must know whether b is NULL. */
bIsNull = BN_IS_NULL(b);
/* Check whether a is NULL. */
if (BN_IS_NULL(a)) {
if (bIsNull) {
/* NULL equals NULL. */
ret = 0;
}
else {
ret = -1; /* NULL less than not NULL. */
}
}
else if (bIsNull) {
/* not NULL greater than NULL. */
ret = 1;
}
else {
/* Neither are NULL; copy to new instances and switch to positive if
* required, compare, and then free. Must copy because there is
* possibility of switch to positive but they are declared const.
* wolfssl_bn_set_neg() only returns -1 if the bn is NULL, but we
* already check that so we can ignore the return code. Note for
* wolfSSL_BN_is_negative if n=1 then set to positive. */
WOLFSSL_BIGNUM* abs_a = wolfSSL_BN_dup(a);
WOLFSSL_BIGNUM* abs_b = wolfSSL_BN_dup(b);
if (abs_a == NULL || abs_b == NULL) {
WOLFSSL_MSG("wolfSSL_BN_dup failed");
wolfSSL_BN_free(abs_a);
wolfSSL_BN_free(abs_b);
return WOLFSSL_FATAL_ERROR;
}
if (wolfSSL_BN_is_negative(abs_a)) {
wolfssl_bn_set_neg(abs_a, 1);
}
if (wolfSSL_BN_is_negative(abs_b)) {
wolfssl_bn_set_neg(abs_b, 1);
}
ret = wolfSSL_BN_cmp(abs_a, abs_b);
wolfSSL_BN_free(abs_a);
wolfSSL_BN_free(abs_b);
}
return ret;
}
/* Indicates whether a big number is the value 0.
*
* Return compliant with OpenSSL.
*
* @param [in] bn Big number to use.
* @return 1 when number is zero.
* @return 0 when number is not zero.
* @return 0 when bn or internal representation of bn is NULL.
*/
int wolfSSL_BN_is_zero(const WOLFSSL_BIGNUM* bn)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_is_zero");
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
ret = 0;
}
else {
/* wolfCrypt checks whether value is 0. */
ret = (mp_iszero((mp_int*)bn->internal) == MP_YES);
}
return ret;
}
/* Indicates whether a big number is the value 1.
*
* Return compliant with OpenSSL.
*
* @param [in] bn Big number to use.
* @return 1 when number is one.
* @return 0 when number is not one.
* @return 0 when bn or internal representation of bn is NULL.
*/
int wolfSSL_BN_is_one(const WOLFSSL_BIGNUM* bn)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_is_one");
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
ret = 0;
}
else {
/* wolfCrypt checks whether value is 1. */
ret = (mp_cmp_d((mp_int*)bn->internal, 1) == MP_EQ);
}
return ret;
}
/* Indicates whether a big number is the value passed in.
*
* Return compliant with OpenSSL.
*
* @param [in] bn Big number to use.
* @return 1 when big number is the value.
* @return 0 when big number is not the value.
* @return 0 when bn or internal representation of bn is NULL.
*/
int wolfSSL_BN_is_word(const WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_is_word");
/* Validate parameter. */
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
else
#if DIGIT_BIT < (SIZEOF_LONG * CHAR_BIT)
/* When value is greater than what can be stored in one digit - special
* case. */
if (w > (WOLFSSL_BN_ULONG)MP_MASK) {
/* TODO: small stack */
mp_int w_mp;
/* Create a MP to hold the number. */
if (mp_init(&w_mp) != MP_OKAY) {
ret = 0;
}
/* Set the value - held in more than one digit. */
else if (mp_set_int(&w_mp, w) != MP_OKAY) {
ret = 0;
}
else {
/* Compare MP representations. */
ret = (mp_cmp((mp_int *)bn->internal, &w_mp) == MP_EQ);
mp_free(&w_mp);
}
}
else
#endif
{
/* wolfCrypt checks whether it is the value. */
ret = (mp_isword((mp_int*)bn->internal, (mp_digit)w) == MP_YES);
}
return ret;
}
/*******************************************************************************
* Word operation APIs.
******************************************************************************/
enum BN_WORD_OP {
BN_WORD_ADD = 0,
BN_WORD_SUB = 1,
BN_WORD_MUL = 2,
BN_WORD_DIV = 3,
BN_WORD_MOD = 4
};
/* Helper function for word operations.
*
* @param [in, out] bn Big number to operate on.
* @param [in] w Word to operate with.
* @param [in] op Operation to perform. See BN_WORD_OP for valid values.
* @param [out] mod_res Result of the modulo operation.
* @return 1 on success.
* @return 0 on failure.
*/
static int bn_word_helper(const WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w,
enum BN_WORD_OP op, WOLFSSL_BN_ULONG* mod_res)
{
int ret = 1;
WOLFSSL_ENTER("bn_word_helper");
/* Validate parameters. */
if (ret == 1 && BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
if (ret == 1) {
int rc = MP_OKAY;
#if DIGIT_BIT < (SIZEOF_LONG * CHAR_BIT)
/* When input 'w' is greater than what can be stored in one digit */
if (w > (WOLFSSL_BN_ULONG)MP_MASK) {
DECL_MP_INT_SIZE_DYN(w_mp, sizeof(WOLFSSL_BN_ULONG) * CHAR_BIT,
sizeof(WOLFSSL_BN_ULONG) * CHAR_BIT);
NEW_MP_INT_SIZE(w_mp, sizeof(WOLFSSL_BN_ULONG) * CHAR_BIT, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
#ifdef MP_INT_SIZE_CHECK_NULL
if (w_mp == NULL) {
WOLFSSL_MSG("NEW_MP_INT_SIZE error");
ret = 0;
}
#endif
if (ret == 1 && mp_set_int(w_mp, w) != MP_OKAY) {
WOLFSSL_MSG("mp_set_int error");
ret = 0;
}
if (ret == 1) {
switch (op) {
case BN_WORD_ADD:
rc = mp_add((mp_int*)bn->internal, w_mp,
(mp_int*)bn->internal);
break;
case BN_WORD_SUB:
rc = mp_sub((mp_int*)bn->internal, w_mp,
(mp_int*)bn->internal);
break;
case BN_WORD_MUL:
rc = mp_mul((mp_int*)bn->internal, w_mp,
(mp_int*)bn->internal);
break;
case BN_WORD_DIV:
rc = mp_div((mp_int*)bn->internal, w_mp,
(mp_int*)bn->internal, NULL);
break;
case BN_WORD_MOD:
rc = mp_mod((mp_int*) bn->internal, w_mp,
w_mp);
if (rc == MP_OKAY && mod_res != NULL)
*mod_res = wolfssl_bn_get_word_1(w_mp);
break;
default:
rc = WOLFSSL_NOT_IMPLEMENTED;
break;
}
}
FREE_MP_INT_SIZE(w_mp, NULL, DYNAMIC_TYPE_RSA);
}
else
#endif
{
switch (op) {
case BN_WORD_ADD:
rc = mp_add_d((mp_int*)bn->internal, (mp_digit)w,
(mp_int*)bn->internal);
break;
case BN_WORD_SUB:
rc = mp_sub_d((mp_int*)bn->internal, (mp_digit)w,
(mp_int*)bn->internal);
break;
case BN_WORD_MUL:
rc = mp_mul_d((mp_int*)bn->internal, (mp_digit)w,
(mp_int*)bn->internal);
break;
case BN_WORD_DIV:
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
/* copied from sp_int.h */
#if (defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_VERIFY_ONLY)) || \
defined(WOLFSSL_KEY_GEN) || defined(HAVE_COMP_KEY) || \
defined(WC_MP_TO_RADIX)
rc = mp_div_d((mp_int*)bn->internal, (mp_digit)w,
(mp_int*)bn->internal, NULL);
#else
rc = WOLFSSL_NOT_IMPLEMENTED;
#endif
#else
rc = WOLFSSL_NOT_IMPLEMENTED;
#endif
break;
case BN_WORD_MOD:
{
mp_digit _mod_res;
rc = mp_mod_d((mp_int*) bn->internal, (mp_digit) w,
&_mod_res);
if (rc == MP_OKAY && mod_res != NULL)
*mod_res = (WOLFSSL_BN_ULONG)_mod_res;
}
break;
default:
rc = WOLFSSL_NOT_IMPLEMENTED;
break;
}
}
if (ret == 1 && rc != MP_OKAY) {
WOLFSSL_MSG("mp word operation error or not implemented");
ret = 0;
}
}
WOLFSSL_LEAVE("bn_word_helper", ret);
return ret;
}
/* Add a word to a big number.
*
* Return code compliant with OpenSSL.
*
* @param [in, out] bn Big number to operate on.
* @param [in] w Word to operate with.
* @return 1 on success.
* @return 0 in failure.
*/
int wolfSSL_BN_add_word(WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_add_word");
ret = bn_word_helper(bn, w, BN_WORD_ADD, NULL);
WOLFSSL_LEAVE("wolfSSL_BN_add_word", ret);
return ret;
}
/* Subtract a word from a big number.
*
* Return code compliant with OpenSSL.
*
* @param [in, out] bn Big number to operate on.
* @param [in] w Word to operate with.
* @return 1 on success.
* @return 0 in failure.
*/
int wolfSSL_BN_sub_word(WOLFSSL_BIGNUM* bn, WOLFSSL_BN_ULONG w)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_sub_word");
ret = bn_word_helper(bn, w, BN_WORD_SUB, NULL);
WOLFSSL_LEAVE("wolfSSL_BN_sub_word", ret);
return ret;
}
int wolfSSL_BN_mul_word(WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_mul_word");
ret = bn_word_helper(bn, w, BN_WORD_MUL, NULL);
WOLFSSL_LEAVE("wolfSSL_BN_mul_word", ret);
return ret;
}
int wolfSSL_BN_div_word(WOLFSSL_BIGNUM *bn, WOLFSSL_BN_ULONG w)
{
int ret;
WOLFSSL_ENTER("wolfSSL_BN_div_word");
ret = bn_word_helper(bn, w, BN_WORD_DIV, NULL);
WOLFSSL_LEAVE("wolfSSL_BN_div_word", ret);
return ret;
}
#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_RSA) || !defined(NO_DH) || \
!defined(NO_DSA))
/* Calculate bn modulo word w. bn % w
*
* Return code compliant with OpenSSL.
*
* @return Word result on success
* @return -1 on error
*/
WOLFSSL_BN_ULONG wolfSSL_BN_mod_word(const WOLFSSL_BIGNUM *bn,
WOLFSSL_BN_ULONG w)
{
int ret;
WOLFSSL_BN_ULONG res = 0;
WOLFSSL_ENTER("wolfSSL_BN_mod_word");
ret = bn_word_helper(bn, w, BN_WORD_MOD, &res);
WOLFSSL_LEAVE("wolfSSL_BN_mod_word", ret);
return ret == 1 ? res : (WOLFSSL_BN_ULONG)-1;
}
#endif /* WOLFSSL_KEY_GEN && (!NO_RSA || !NO_DH || !NO_DSA) */
/*******************************************************************************
* Shift APIs
******************************************************************************/
#ifndef WOLFSSL_SP_MATH
/* Shift the value in bn left by n bits into r. r = bn << n
*
* Return code compliant with OpenSSL.
*
* @return 1 on success.
* @return 0 when r or bn or internal representation is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_lshift(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *bn, int n)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_BN_lshift");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
else if (n < 0) {
WOLFSSL_MSG("n value error");
ret = 0;
}
/* Use wolfCrypt perform operation. */
if ((ret == 1) && (mp_mul_2d((mp_int*)bn->internal, n,
(mp_int*)r->internal) != MP_OKAY)) {
WOLFSSL_MSG("mp_mul_2d error");
ret = 0;
}
return ret;
}
/* Shift the value in bn right by n bits into r. r = bn >> n
*
* Return code compliant with OpenSSL.
*
* @return 1 on success.
* @return 0 when r or bn or internal representation is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_rshift(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *bn, int n)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_BN_rshift");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
else if (n < 0) {
WOLFSSL_MSG("n value error");
ret = 0;
}
/* Use wolfCrypt perform operation. */
if ((ret == 1) && (mp_div_2d((mp_int*)bn->internal, n, (mp_int*)r->internal,
NULL) != MP_OKAY)) {
WOLFSSL_MSG("mp_mul_2d error");
ret = 0;
}
return ret;
}
#endif
/*******************************************************************************
* Simple Math APIs
******************************************************************************/
/* Add a to b into r. r = a + b
*
* Return code compliant with OpenSSL.
*
* @param [out] r Big number to put result into.
* @param [in] a Big number to be added to.
* @param [in] b Big number to add with.
*
* @return 1 on success.
* @return 0 when r, a or b or internal representation is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_add(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a, WOLFSSL_BIGNUM *b)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_BN_add");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
/* Add the internal representations into internal representation. */
if ((ret == 1) && (mp_add((mp_int*)a->internal, (mp_int*)b->internal,
(mp_int*)r->internal) != MP_OKAY)) {
WOLFSSL_MSG("mp_add_d error");
ret = 0;
}
return ret;
}
/* Subtract a from b into r. r = a - b
*
* @param [out] r Big number to put result into.
* @param [in] a Big number to be subtracted from.
* @param [in] b Big number to subtract with.
*
* @return 1 on success.
* @return 0 when r, a or b is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_sub(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a,
const WOLFSSL_BIGNUM* b)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_BN_sub");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
ret = 0;
}
/* Have wolfCrypt perform operation with internal representations. */
if ((ret == 1) && (mp_sub((mp_int*)a->internal,(mp_int*)b->internal,
(mp_int*)r->internal) != MP_OKAY)) {
ret = 0;
}
WOLFSSL_LEAVE("wolfSSL_BN_sub mp_sub", ret);
return ret;
}
/* Multiply a with b into r. r = a * b
*
* @param [out] r Big number to put result into.
* @param [in] a Big number to be multiplied.
* @param [in] b Big number to multiply with.
* @param [in] ctx BN context object. Unused.
*
* @return 1 on success.
* @return 0 when r, a or b is NULL.
* @return 0 when internal representation of r, a or b is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_mul(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a, WOLFSSL_BIGNUM *b,
WOLFSSL_BN_CTX *ctx)
{
int ret = 1;
(void)ctx;
WOLFSSL_ENTER("wolfSSL_BN_mul");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
ret = 0;
}
/* Have wolfCrypt perform operation with internal representations. */
if ((ret == 1) && (mp_mul((mp_int*)a->internal, (mp_int*)b->internal,
(mp_int*)r->internal) != MP_OKAY)) {
ret = 0;
}
WOLFSSL_LEAVE("wolfSSL_BN_mul", ret);
return ret;
}
#ifndef WOLFSSL_SP_MATH
/* Divide a by b into dv and put remainder into rem. dv = a / b, rem = a % b
*
* @param [out] dv Big number to put division result into.
* @param [out] rem Big number to put remainder into.
* @param [in] a Big number to be divided.
* @param [in] b Big number to divide with.
* @param [in] ctx BN context object. Unused.
*
* @return 1 on success.
* @return 0 when dv, rem, a or b is NULL.
* @return 0 when internal representation of dv, rem, a or b is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_div(WOLFSSL_BIGNUM* dv, WOLFSSL_BIGNUM* rem,
const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* d, WOLFSSL_BN_CTX* ctx)
{
int ret = 1;
WOLFSSL_BIGNUM* res = dv;
/* BN context not needed. */
(void)ctx;
WOLFSSL_ENTER("wolfSSL_BN_div");
if (BN_IS_NULL(res)) {
res = wolfSSL_BN_new();
}
/* Validate parameters. */
if (BN_IS_NULL(res) || BN_IS_NULL(rem) || BN_IS_NULL(a) || BN_IS_NULL(d)) {
ret = 0;
}
/* Have wolfCrypt perform operation with internal representations. */
if ((ret == 1) && (mp_div((mp_int*)a->internal, (mp_int*)d->internal,
(mp_int*)res->internal, (mp_int*)rem->internal) != MP_OKAY)) {
ret = 0;
}
if (res != dv)
wolfSSL_BN_free(res);
WOLFSSL_LEAVE("wolfSSL_BN_div", ret);
return ret;
}
#endif
/* Calculate a mod b into r. r = a % b
*
* @param [out] r Big number to put result into.
* @param [in] a Big number to reduced
* @param [in] b Big number to reduce with.
* @param [in] ctx BN context object. Unused.
*
* @return 1 on success.
* @return 0 when r, a or b is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_mod(WOLFSSL_BIGNUM* r, const WOLFSSL_BIGNUM* a,
const WOLFSSL_BIGNUM* b, const WOLFSSL_BN_CTX* c)
{
int ret = 1;
(void)c;
WOLFSSL_ENTER("wolfSSL_BN_mod");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
ret = 0;
}
/* Have wolfCrypt perform operation with internal representations. */
if ((ret == 1) && (mp_mod((mp_int*)a->internal,(mp_int*)b->internal,
(mp_int*)r->internal) != MP_OKAY)) {
ret = 0;
}
WOLFSSL_LEAVE("wolfSSL_BN_mod mp_mod", ret);
return ret;
}
/*******************************************************************************
* Math and Mod APIs
******************************************************************************/
#ifndef WOLFSSL_SP_MATH
/* Add a to b modulo m into r. r = a + b (mod m)
*
* @param [in, out] r Big number to hold result.
* @param [in] a Big number to add to.
* @param [in] b Big number to add with.
* @param [in] m Big number that is the modulus.
* @param [in] ctx BN context. Not used.
* @return 1 on success.
* @return 0 when r, a or b or internal representation is NULL.
* @return 0 on calculation failure.
*/
int wolfSSL_BN_mod_add(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
const WOLFSSL_BIGNUM *b, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx)
{
int ret = 1;
/* BN context not needed. */
(void)ctx;
WOLFSSL_ENTER("wolfSSL_BN_add");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b) || BN_IS_NULL(m)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
/* Perform operation with wolfCrypt. */
if ((ret == 1) && (mp_addmod((mp_int*)a->internal, (mp_int*)b->internal,
(mp_int*)m->internal, (mp_int*)r->internal) != MP_OKAY)) {
WOLFSSL_MSG("mp_add_d error");
ret = 0;
}
return ret;
}
#endif
/* Calculate a multiplied by b, mod m into r. r = (a * b) % m
*
* @param [out] r Big number to put result into.
* @param [in] a Base as a big number.
* @param [in] b Multiplier as a big number.
* @param [in] m Modulus as a big number.
* @param [in] ctx BN context object. Unused.
*
* @return 1 on success.
* @return 0 when r, a, b or m is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_mod_mul(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
const WOLFSSL_BIGNUM *b, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx)
{
int ret = 1;
/* BN context not needed. */
(void)ctx;
WOLFSSL_ENTER("wolfSSL_BN_mod_mul");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b) || BN_IS_NULL(m)) {
WOLFSSL_MSG("Bad Argument");
ret = 0;
}
/* Have wolfCrypt perform operation with internal representations. */
if ((ret == 1) && (mp_mulmod((mp_int*)a->internal, (mp_int*)b->internal,
(mp_int*)m->internal, (mp_int*)r->internal)) != MP_OKAY) {
ret = 0;
}
WOLFSSL_LEAVE("wolfSSL_BN_mod_mul", ret);
return ret;
}
/* Calculate a to the power of e, mod m into r. r = (a ^ e) % m
*
* @param [out] r Big number to put result into.
* @param [in] a Base as a big number.
* @param [in] e Exponent as a big number.
* @param [in] m Modulus as a big number.
* @param [in] ctx BN context object. Unused.
*
* @return 1 on success.
* @return 0 when r, a, p or m is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_mod_exp(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *a,
const WOLFSSL_BIGNUM *e, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx)
{
int ret = 1;
/* BN context not needed. */
(void)ctx;
WOLFSSL_ENTER("wolfSSL_BN_mod_exp");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(e) || BN_IS_NULL(m)) {
WOLFSSL_MSG("Bad Argument");
ret = 0;
}
/* Have wolfCrypt perform operation with internal representations. */
if ((ret == 1) && (mp_exptmod((mp_int*)a->internal, (mp_int*)e->internal,
(mp_int*)m->internal, (mp_int*)r->internal)) != MP_OKAY) {
ret = 0;
}
WOLFSSL_LEAVE("wolfSSL_BN_mod_exp", ret);
return ret;
}
/* Calculate the modular inverse of a mod m into r. r = a^-1 mod m
*
* A new big number is allocated when r is NULL.
*
* @param [in, out] r Big number to hold result. May be NULL.
* @param [in] a Big number to invert.
* @param [in] m Big number that is the modulus.
* @param [in] ctx BN context. Not used.
* @return Big number holding result on success.
* @return NULL on failure.
*/
WOLFSSL_BIGNUM *wolfSSL_BN_mod_inverse(WOLFSSL_BIGNUM *r, WOLFSSL_BIGNUM *a,
const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx)
{
int err = 0;
WOLFSSL_BIGNUM* t = NULL;
/* BN context not needed. */
(void)ctx;
WOLFSSL_ENTER("wolfSSL_BN_mod_inverse");
/* Validate parameters. */
if (BN_IS_NULL(a) || BN_IS_NULL(m) || ((r != NULL) &&
(r->internal == NULL))) {
WOLFSSL_MSG("a or n NULL error");
err = 1;
}
/* Check whether we have a result big number. */
if ((!err) && (r == NULL)) {
/* Allocate a new big number to hold result and be returned. */
t = wolfSSL_BN_new();
if (t == NULL){
WOLFSSL_MSG("WolfSSL_BN_new() failed");
err = 1;
}
r = t;
}
/* Compute inverse of a modulo n and return in r */
if ((!err) && (mp_invmod((mp_int *)a->internal, (mp_int *)m->internal,
(mp_int*)r->internal) != MP_OKAY)) {
WOLFSSL_MSG("mp_invmod() error");
err = 1;
}
if (err) {
wolfSSL_BN_free(t);
r = NULL;
}
return r;
}
/*******************************************************************************
* Other Math APIs
******************************************************************************/
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
/* Needed to get mp_gcd. */
/* Greatest Common Divisor (GCM) of a and b into r. r = GCD(a, b)
*
* @param [out] r Big number to put result into.
* @param [in] a First big number.
* @param [in] b Second big number.
* @param [in] ctx BN context object. Unused.
*
* @return 1 on success.
* @return 0 when r, a or b is NULL.
* @return 0 when internal representation of r, a or b is NULL.
* @return 0 on failure.
*/
int wolfSSL_BN_gcd(WOLFSSL_BIGNUM* r, WOLFSSL_BIGNUM* a, WOLFSSL_BIGNUM* b,
WOLFSSL_BN_CTX* ctx)
{
int ret = 1;
/* BN context not needed. */
(void)ctx;
WOLFSSL_ENTER("wolfSSL_BN_gcd");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(a) || BN_IS_NULL(b)) {
ret = 0;
}
/* Have wolfCrypt perform operation with internal representations. */
if ((ret == 1) && (mp_gcd((mp_int*)a->internal, (mp_int*)b->internal,
(mp_int*)r->internal) != MP_OKAY)) {
ret = 0;
}
WOLFSSL_LEAVE("wolfSSL_BN_gcd", ret);
return ret;
}
#endif /* !NO_RSA && WOLFSSL_KEY_GEN */
/*******************************************************************************
* Random APIs
******************************************************************************/
/* Generates a random number up to bits long.
*
* @param [in, out] bn Big number to generate into.
* @param [in] bits Number of bits in word.
* @param [in] top Whether top bits must be set.
* Valid values: WOLFSSL_BN_RAND_TOP_ANY,
* WOLFSSL_BN_RAND_TOP_ONE, WOLFSSL_BN_RAND_TOP_TWO.
* @param [in] bottom Whether bottom bit must be set.
* Valid values: WOLFSSL_BN_RAND_BOTTOM_ANY,
WOLFSSL_BN_RAND_BOTTOM_ODD.
* @return 1 on success.
* @return 0 when bn is NULL.
* @return 0 when bits is invalid.
* @return 0 when bits and top/bottom are invalid.
* @return 0 when generation fails.
*/
int wolfSSL_BN_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom)
{
int ret = 1;
word32 len = (word32)((bits + 7) / 8);
WC_RNG* rng;
WOLFSSL_ENTER("wolfSSL_BN_rand");
/* Validate parameters. */
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("Bad argument - bn");
ret = 0;
}
else if (bits < 0) {
WOLFSSL_MSG("Bad argument - bits < 0");
ret = 0;
}
else if ((bits == 0) && ((bottom != WOLFSSL_BN_RAND_BOTTOM_ANY) ||
(top != WOLFSSL_BN_RAND_TOP_ANY))) {
WOLFSSL_MSG("Bad top/bottom - bits == 0");
ret = 0;
}
else if ((bits == 1) && (top > WOLFSSL_BN_RAND_TOP_ONE)) {
WOLFSSL_MSG("Bad top - bits == 1");
ret = 0;
}
/* Handle simple case of zero bits. */
if ((ret == 1) && (bits == 0)) {
mp_zero((mp_int*)bn->internal);
}
else if (ret == 1) {
byte* buff = NULL;
/* Get random to global random to generate bits. */
if ((rng = wolfssl_make_global_rng()) == NULL) {
WOLFSSL_MSG("Failed to use global RNG.");
ret = 0;
}
/* Allocate buffer to hold generated bits. */
if ((ret == 1) && ((buff = (byte*)XMALLOC(len, NULL,
DYNAMIC_TYPE_TMP_BUFFER)) == NULL)) {
WOLFSSL_MSG("Failed to allocate buffer.");
ret = 0;
}
/* Generate bytes to cover bits. */
if ((ret == 1) && wc_RNG_GenerateBlock(rng, buff, len) != 0) {
WOLFSSL_MSG("wc_RNG_GenerateBlock failed");
ret = 0;
}
/* Read bytes in to big number. */
if ((ret == 1) && mp_read_unsigned_bin((mp_int*)bn->internal, buff, len)
!= MP_OKAY) {
WOLFSSL_MSG("mp_read_unsigned_bin failed");
ret = 0;
}
/* Dispose of buffer - no longer needed. */
XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (ret == 1) {
/* Truncate to requested bit length. */
mp_rshb((mp_int*)bn->internal, 8 - (bits % 8));
}
/* Set top bit when required. */
if ((ret == 1) && (top >= WOLFSSL_BN_RAND_TOP_ONE) &&
(mp_set_bit((mp_int*)bn->internal, bits - 1) != MP_OKAY)) {
WOLFSSL_MSG("Failed to set top bit");
ret = 0;
}
/* Set second top bit when required. */
if ((ret == 1) && (top > WOLFSSL_BN_RAND_TOP_ONE) &&
(mp_set_bit((mp_int*)bn->internal, bits - 2) != MP_OKAY)) {
WOLFSSL_MSG("Failed to set second top bit");
ret = 0;
}
/* Set bottom bit when required. */
if ((ret == 1) && (bottom == WOLFSSL_BN_RAND_BOTTOM_ODD) &&
(mp_set_bit((mp_int*)bn->internal, 0) != MP_OKAY)) {
WOLFSSL_MSG("Failed to set 0th bit");
ret = 0;
}
}
WOLFSSL_LEAVE("wolfSSL_BN_rand", ret);
return ret;
}
/* Generates a pseudo-random number up to bits long.
*
* Implemented using wolfSSL_BN_rand().
*
* @param [in, out] bn Big number to generate into.
* @param [in] bits Number of bits in word.
* @param [in] top Whether top bits must be set.
* Valid values: WOLFSSL_BN_RAND_TOP_ANY,
* WOLFSSL_BN_RAND_TOP_ONE, WOLFSSL_BN_RAND_TOP_TWO.
* @param [in] bottom Whether bottom bit must be set.
* Valid values: WOLFSSL_BN_RAND_BOTTOM_ANY,
WOLFSSL_BN_RAND_BOTTOM_ODD.
* @return 1 on success.
* @return 0 when bn is NULL.
* @return 0 when bits is invalid.
* @return 0 when bits and top/bottom are invalid.
* @return 0 when generation fails.
*/
int wolfSSL_BN_pseudo_rand(WOLFSSL_BIGNUM* bn, int bits, int top, int bottom)
{
return wolfSSL_BN_rand(bn, bits, top, bottom);
}
/* Maximum number of trials to attempt at generating a number in range. */
#define RANGE_MAX_TRIALS 100
/* Generate big number to be a value between 0 and range-1.
*
* N = length of range input var
*
* Generate N-bit length numbers until generated number is less than range
* @param [in] r Big number to generate into.
* @param [in] range The upper limit of generated number.
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_BN_rand_range(WOLFSSL_BIGNUM *r, const WOLFSSL_BIGNUM *range)
{
int ret = 1;
WOLFSSL_ENTER("wolfSSL_BN_rand_range");
/* Validate parameters. */
if (BN_IS_NULL(r) || BN_IS_NULL(range)) {
WOLFSSL_MSG("Bad parameter");
ret = 0;
}
if (ret == 1) {
/* Calculate number of bits in modulus. */
int n = wolfSSL_BN_num_bits(range);
if (n <= 1) {
/* Modulus is 0 or 1. */
wolfSSL_BN_zero(r);
}
else {
int i;
/* Try generating a number in range for a limited number of trials.
*/
for (i = 0; (ret == 1) && (i < RANGE_MAX_TRIALS); i++) {
/* Generate a random number in range. */
if (wolfSSL_BN_pseudo_rand(r, n, WOLFSSL_BN_RAND_TOP_ANY,
WOLFSSL_BN_RAND_BOTTOM_ANY) == 0) {
WOLFSSL_MSG("wolfSSL_BN_rand error");
ret = 0;
}
/* Check if in range. */
else if (wolfSSL_BN_cmp(r, range) < 0) {
break;
}
}
/* Fail if max trial attempts made. */
if (i >= RANGE_MAX_TRIALS) {
WOLFSSL_MSG("wolfSSL_BN_rand_range too many iterations");
ret = 0;
}
}
}
return ret;
}
/*******************************************************************************
* Prime APIs
******************************************************************************/
#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_RSA) || !defined(NO_DH) || \
!defined(NO_DSA))
/* Generate a prime number.
*
* @param [in, out] prime Big number to generate into.
* @param [in] bits Number of bits in generated number.
* @param [in] safe Whether number must be a safe prime.
* @param [in] add Value to add when generating. Not used.
* @param [in] rem Remainder of number modulo add. Not used.
* @param [in] cb Generation callback. Not used.
* @return 1 on success.
* @return 0 when prime is NULL.
* @return 0 when safe required or add or rem is not NULL.
* @return 0 on generation failure.
*/
int wolfSSL_BN_generate_prime_ex(WOLFSSL_BIGNUM* prime, int bits,
int safe, const WOLFSSL_BIGNUM* add, const WOLFSSL_BIGNUM* rem,
WOLFSSL_BN_GENCB* cb)
{
int ret = 1;
WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0);
WC_RNG* rng = NULL;
int localRng = 0;
/* Callback not used. */
(void)cb;
WOLFSSL_ENTER("wolfSSL_BN_generate_prime_ex");
/* Check unsupported parameters. */
if ((safe == 1) || (add != NULL) || (rem != NULL)) {
ret = 0;
}
/* Validate parameters. */
else if (BN_IS_NULL(prime)) {
ret = 0;
}
/* Create a new RNG or use global. */
if ((ret == 1) && ((rng = wolfssl_make_rng(tmpRng, &localRng)) == NULL)) {
ret = 0;
}
/* Use wolfCrypt to generate a prime. */
if ((ret == 1) && (mp_rand_prime((mp_int*)prime->internal, (bits + 7) / 8,
rng, NULL) != MP_OKAY)) {
ret = 0;
}
if (localRng) {
/* Dispose of local RNG that was created. */
wc_FreeRng(rng);
WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG);
}
WOLFSSL_LEAVE("wolfSSL_BN_generate_prime_ex", ret);
return ret;
}
/* Check whether a big number is prime.
*
* Return code compliant with OpenSSL.
*
* @param [in] bn Big number to check.
* @param [in] checks Number of Miller-Rabin tests to perform.
* @param [in] ctx BN context. Not used.
* @param [in] cb Generation callback. Not used.
* @return 1 when number is prime.
* @return 0 when number is not prime.
* @return -1 when bn is NULL or failure when checking.
*/
int wolfSSL_BN_is_prime_ex(const WOLFSSL_BIGNUM *bn, int checks,
WOLFSSL_BN_CTX *ctx, WOLFSSL_BN_GENCB *cb)
{
int ret = 1;
WC_RNG* rng = NULL;
WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0);
int localRng = 0;
int res = MP_NO;
/* BN context not needed. */
(void)ctx;
(void)cb;
WOLFSSL_ENTER("wolfSSL_BN_is_prime_ex");
if (BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = WOLFSSL_FATAL_ERROR;
}
/* Create a new RNG or use global. */
if ((ret == 1) && ((rng = wolfssl_make_rng(tmpRng, &localRng)) == NULL)) {
ret = WOLFSSL_FATAL_ERROR;
}
if ((ret == 1) && (mp_prime_is_prime_ex((mp_int*)bn->internal, checks, &res,
rng) != MP_OKAY)) {
WOLFSSL_MSG("mp_prime_is_prime_ex error");
ret = WOLFSSL_FATAL_ERROR;
}
if (localRng) {
wc_FreeRng(rng);
WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG);
}
if ((ret != -1) && (res != MP_YES)) {
WOLFSSL_MSG("mp_prime_is_prime_ex not prime");
ret = 0;
}
return ret;
}
#endif /* WOLFSSL_KEY_GEN && (!NO_RSA || !NO_DH || !NO_DSA) */
/*******************************************************************************
* Print APIs
******************************************************************************/
#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) && \
defined(XFPRINTF)
/* Print big number to file pointer.
*
* Return code compliant with OpenSSL.
*
* @param [in] fp File pointer.
* @param [in] bn Big number to print.
* @return 1 on success.
* @return 0 when fp is a bad file pointer.
* @return 0 when bn is NULL.
* @return 0 when creating hex string fails.
* @return 0 when printing fails.
*/
int wolfSSL_BN_print_fp(XFILE fp, const WOLFSSL_BIGNUM *bn)
{
int ret = 1;
char* buf = NULL;
WOLFSSL_ENTER("wolfSSL_BN_print_fp");
/* Validate parameters. */
if ((fp == XBADFILE) || BN_IS_NULL(bn)) {
WOLFSSL_MSG("bn NULL error");
ret = 0;
}
/* Create a hex string of big number. */
if ((ret == 1) && ((buf = wolfSSL_BN_bn2hex(bn)) == NULL)) {
WOLFSSL_MSG("wolfSSL_BN_bn2hex failure");
ret = 0;
}
/* Print hex string to file pointer. */
if ((ret == 1) && (XFPRINTF(fp, "%s", buf) < 0)) {
ret = 0;
}
/* Dispose of any allocated data. */
XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL);
return ret;
}
#endif /* !NO_FILESYSTEM && XFPRINTF */
#ifndef NO_WOLFSSL_BN_CTX
/*******************************************************************************
* BN_CTX APIs
******************************************************************************/
/* Create a new BN context object.
*
* @return BN context object on success.
* @return NULL on failure.
*/
WOLFSSL_BN_CTX* wolfSSL_BN_CTX_new(void)
{
WOLFSSL_BN_CTX* ctx = NULL;
WOLFSSL_ENTER("wolfSSL_BN_CTX_new");
ctx = (WOLFSSL_BN_CTX*)XMALLOC(sizeof(WOLFSSL_BN_CTX), NULL,
DYNAMIC_TYPE_OPENSSL);
if (ctx != NULL) {
XMEMSET(ctx, 0, sizeof(WOLFSSL_BN_CTX));
}
return ctx;
}
#ifndef NO_WOLFSSL_STUB
/* deprecated
*
* Initialize a BN context object.
* This function was removed in OpenSSL 1.1.0 and later.
* Keeping a stub function here for older applications that have BN_CTX_init()
* calls.
*
* @param [in] ctx Dummy BN context.
*/
void wolfSSL_BN_CTX_init(WOLFSSL_BN_CTX* ctx)
{
(void)ctx;
WOLFSSL_ENTER("wolfSSL_BN_CTX_init");
WOLFSSL_STUB("wolfSSL_BN_CTX_init");
WOLFSSL_MSG("wolfSSL_BN_CTX_init is deprecated");
}
#endif
/* Free a BN context object.
*
* @param [in] ctx BN context object.
*/
void wolfSSL_BN_CTX_free(WOLFSSL_BN_CTX* ctx)
{
WOLFSSL_ENTER("wolfSSL_BN_CTX_free");
if (ctx != NULL) {
while (ctx->list != NULL) {
struct WOLFSSL_BN_CTX_LIST* tmp = ctx->list;
ctx->list = ctx->list->next;
wolfSSL_BN_free(tmp->bn);
XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL);
}
XFREE(ctx, NULL, DYNAMIC_TYPE_OPENSSL);
}
}
/* Get a big number from the BN context.
*
* @param [in] ctx BN context object.
* @return Big number on success.
* @return NULL on failure.
*/
WOLFSSL_BIGNUM *wolfSSL_BN_CTX_get(WOLFSSL_BN_CTX *ctx)
{
WOLFSSL_BIGNUM* bn = NULL;
WOLFSSL_ENTER("wolfSSL_BN_CTX_get");
if (ctx != NULL) {
struct WOLFSSL_BN_CTX_LIST* node = (struct WOLFSSL_BN_CTX_LIST*)XMALLOC(
sizeof(struct WOLFSSL_BN_CTX_LIST), NULL, DYNAMIC_TYPE_OPENSSL);
if (node != NULL) {
XMEMSET(node, 0, sizeof(struct WOLFSSL_BN_CTX_LIST));
bn = node->bn = wolfSSL_BN_new();
if (node->bn != NULL) {
node->next = ctx->list;
ctx->list = node;
}
else {
XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL);
node = NULL;
}
}
}
return bn;
}
#ifndef NO_WOLFSSL_STUB
/* Start stack of temporary big numbers.
*
* Newly allocated big numbers are returned instead of having a stack.
*
* @param [in] ctx BN context. Not used.
*/
void wolfSSL_BN_CTX_start(WOLFSSL_BN_CTX *ctx)
{
(void)ctx;
WOLFSSL_ENTER("wolfSSL_BN_CTX_start");
WOLFSSL_STUB("BN_CTX_start");
WOLFSSL_MSG("wolfSSL_BN_CTX_start TBD");
}
#endif
#endif /* NO_WOLFSSL_BN_CTX */
/*******************************************************************************
* BN_MONT_CTX APIs
******************************************************************************/
WOLFSSL_BN_MONT_CTX* wolfSSL_BN_MONT_CTX_new(void)
{
/* wolfcrypt doesn't need BN MONT context. */
static int mont;
WOLFSSL_ENTER("wolfSSL_BN_MONT_CTX_new");
return (WOLFSSL_BN_MONT_CTX*)&mont;
}
void wolfSSL_BN_MONT_CTX_free(WOLFSSL_BN_MONT_CTX *mont)
{
(void)mont;
WOLFSSL_ENTER("wolfSSL_BN_MONT_CTX_free");
/* Don't do anything since using dummy, static BN context. */
}
int wolfSSL_BN_MONT_CTX_set(WOLFSSL_BN_MONT_CTX *mont,
const WOLFSSL_BIGNUM *mod, WOLFSSL_BN_CTX *ctx)
{
(void) mont;
(void) mod;
(void) ctx;
WOLFSSL_ENTER("wolfSSL_BN_MONT_CTX_set");
return WOLFSSL_SUCCESS;
}
/* Calculate r = a ^ p % m.
*
* @param [out] r Big number to store the result.
* @param [in] a Base as an unsigned long.
* @param [in] p Exponent as a big number.
* @param [in] m Modulus as a big number.
* @param [in] ctx BN context object. Unused.
* @param [in] mont Montgomery context object. Unused.
*
* @return 1 on success.
* @return 0 on failure.
*/
int wolfSSL_BN_mod_exp_mont_word(WOLFSSL_BIGNUM *r, WOLFSSL_BN_ULONG a,
const WOLFSSL_BIGNUM *p, const WOLFSSL_BIGNUM *m, WOLFSSL_BN_CTX *ctx,
WOLFSSL_BN_MONT_CTX *mont)
{
WOLFSSL_BIGNUM* tmp = NULL;
int ret = WOLFSSL_SUCCESS;
(void)mont;
WOLFSSL_ENTER("wolfSSL_BN_mod_exp_mont_word");
if (ret == WOLFSSL_SUCCESS && (tmp = wolfSSL_BN_new()) == NULL) {
WOLFSSL_MSG("wolfSSL_BN_new failed");
ret = WOLFSSL_FAILURE;
}
if (ret == WOLFSSL_SUCCESS && (wolfSSL_BN_set_word(tmp, (unsigned long)a))
== WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
WOLFSSL_MSG("wolfSSL_BN_set_word failed");
ret = WOLFSSL_FAILURE;
}
if (ret == WOLFSSL_SUCCESS)
ret = wolfSSL_BN_mod_exp(r, tmp, p, m, ctx);
wolfSSL_BN_free(tmp);
return ret;
}
#endif /* OPENSSL_EXTRA */
#endif /* !WOLFSSL_SSL_BN_INCLUDED */