diff --git a/src/ssl.c b/src/ssl.c index ce0ca2361..6b58f29ac 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -33996,6 +33996,17 @@ WOLFSSL_DH* wolfSSL_DH_new(void) } InitwolfSSL_DH(external); + + external->refCount = 1; +#ifndef SINGLE_THREADED + if (wc_InitMutex(&external->refMutex) != 0) { + WOLFSSL_MSG("wc_InitMutex WOLFSSL_DH failure"); + XFREE(key, NULL, DYNAMIC_TYPE_DH); + XFREE(external, NULL, DYNAMIC_TYPE_DH); + return NULL; + } +#endif + if (wc_InitDhKey(key) != 0) { WOLFSSL_MSG("wolfSSL_DH_new InitDhKey failure"); XFREE(key, NULL, DYNAMIC_TYPE_DH); @@ -34011,9 +34022,30 @@ WOLFSSL_DH* wolfSSL_DH_new(void) void wolfSSL_DH_free(WOLFSSL_DH* dh) { + int doFree = 0; + WOLFSSL_ENTER("wolfSSL_DH_free"); if (dh) { + + #ifndef SINGLE_THREADED + if (wc_LockMutex(&dh->refMutex) != 0) { + WOLFSSL_MSG("Could not lock DH mutex"); + } + #endif + /* only free if all references to it are done */ + dh->refCount--; + if (dh->refCount == 0) { + doFree = 1; + } + #ifndef SINGLE_THREADED + wc_UnLockMutex(&dh->refMutex); + #endif + + if (doFree == 0) { + return; + } + if (dh->internal) { wc_FreeDhKey((DhKey*)dh->internal); XFREE(dh->internal, NULL, DYNAMIC_TYPE_DH); @@ -34030,6 +34062,26 @@ void wolfSSL_DH_free(WOLFSSL_DH* dh) } } +int wolfSSL_DH_up_ref(WOLFSSL_DH* dh) +{ + WOLFSSL_ENTER("wolfSSL_DH_up_ref"); + + if (dh) { + #ifndef SINGLE_THREADED + if (wc_LockMutex(&dh->refMutex) != 0) { + WOLFSSL_MSG("Failed to lock DH mutex"); + } + #endif + dh->refCount++; + #ifndef SINGLE_THREADED + wc_UnLockMutex(&dh->refMutex); + #endif + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + int SetDhInternal(WOLFSSL_DH* dh) { int ret = WOLFSSL_FATAL_ERROR; diff --git a/tests/api.c b/tests/api.c index fe844767f..818b17163 100644 --- a/tests/api.c +++ b/tests/api.c @@ -51442,6 +51442,15 @@ static void test_wolfSSL_DH(void) AssertPtrEq(q, NULL); AssertPtrEq(g, NULL); DH_free(dh); + + /* Test DH_up_ref() */ + dh = wolfSSL_DH_new(); + AssertNotNull(dh); + AssertIntEQ(wolfSSL_DH_up_ref(NULL), WOLFSSL_FAILURE); + AssertIntEQ(wolfSSL_DH_up_ref(dh), WOLFSSL_SUCCESS); + DH_free(dh); /* decrease ref count */ + DH_free(dh); /* free WOLFSSL_DH */ + printf(resultFmt, passed); #endif /* OPENSSL_EXTRA && !NO_DH */ } diff --git a/wolfssl/openssl/dh.h b/wolfssl/openssl/dh.h index 11d650192..fe4b3fc2d 100644 --- a/wolfssl/openssl/dh.h +++ b/wolfssl/openssl/dh.h @@ -41,15 +41,19 @@ struct WOLFSSL_DH { WOLFSSL_BIGNUM* p; WOLFSSL_BIGNUM* g; WOLFSSL_BIGNUM* q; - WOLFSSL_BIGNUM* pub_key; /* openssh deference g^x */ - WOLFSSL_BIGNUM* priv_key; /* openssh deference x */ + WOLFSSL_BIGNUM* pub_key; /* openssh deference g^x */ + WOLFSSL_BIGNUM* priv_key; /* openssh deference x */ void* internal; /* our DH */ char inSet; /* internal set from external ? */ char exSet; /* external set from internal ? */ /*added for lighttpd openssl compatibility, go back and add a getter in * lighttpd src code. */ - int length; + int length; +#ifndef SINGLE_THREADED + wolfSSL_Mutex refMutex; /* ref count mutex */ +#endif + int refCount; /* reference count */ }; WOLFSSL_API WOLFSSL_DH *wolfSSL_d2i_DHparams(WOLFSSL_DH **dh, @@ -58,6 +62,7 @@ WOLFSSL_API int wolfSSL_i2d_DHparams(const WOLFSSL_DH *dh, unsigned char **out); WOLFSSL_API WOLFSSL_DH* wolfSSL_DH_new(void); WOLFSSL_API void wolfSSL_DH_free(WOLFSSL_DH* dh); WOLFSSL_API WOLFSSL_DH* wolfSSL_DH_dup(WOLFSSL_DH* dh); +WOLFSSL_API int wolfSSL_DH_up_ref(WOLFSSL_DH* dh); WOLFSSL_API int wolfSSL_DH_check(const WOLFSSL_DH *dh, int *codes); WOLFSSL_API int wolfSSL_DH_size(WOLFSSL_DH* dh); @@ -72,13 +77,13 @@ WOLFSSL_API int wolfSSL_DH_set0_pqg(WOLFSSL_DH *dh, WOLFSSL_BIGNUM *p, WOLFSSL_API WOLFSSL_DH* wolfSSL_DH_get_2048_256(void); - #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) typedef WOLFSSL_DH DH; -#define DH_new wolfSSL_DH_new -#define DH_free wolfSSL_DH_free +#define DH_new wolfSSL_DH_new +#define DH_free wolfSSL_DH_free +#define DH_up_ref wolfSSL_DH_up_ref #define d2i_DHparams wolfSSL_d2i_DHparams #define i2d_DHparams wolfSSL_i2d_DHparams