diff --git a/src/bio.c b/src/bio.c index fbdcdfd08..b0dd63774 100644 --- a/src/bio.c +++ b/src/bio.c @@ -725,6 +725,32 @@ long wolfSSL_BIO_ctrl(WOLFSSL_BIO *bio, int cmd, long larg, void *parg) } return ret; } + +/* Increment the WOLFSSL_BIO ref count by one, prevents BIO from being + * freed until ref count is back down to 1. + * + * bio the structure to increment ref count + * + * returns 1 on success, 0 on failure */ + +int wolfSSL_BIO_up_ref(WOLFSSL_BIO* bio) +{ + if (bio) { + #ifndef SINGLE_THREADED + if (wc_LockMutex(&bio->refMutex) != 0) { + WOLFSSL_MSG("Failed to lock BIO mutex"); + } + #endif + bio->refCount++; + #ifndef SINGLE_THREADED + wc_UnLockMutex(&bio->refMutex); + #endif + + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} #endif diff --git a/src/ssl.c b/src/ssl.c index 8d54d8812..f9b553bbd 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -44900,6 +44900,47 @@ end: return NULL; #endif } + +#ifndef NO_FILESYSTEM +/* Reads DH parameters from a file pointer into WOLFSSL_DH structure. + * + * fp file pointer to read DH parameter file from + * x output WOLFSSL_DH to be created and populated from fp + * cb password callback, to be used to decrypt encrypted DH parameters PEM + * u context pointer to user-defined data to be received back in password cb + * + * Returns new WOLFSSL_DH structure pointer on success, NULL on failure. */ +WOLFSSL_DH *wolfSSL_PEM_read_DHparams(XFILE fp, WOLFSSL_DH **x, + pem_password_cb *cb, void *u) +{ + WOLFSSL_BIO* fbio = NULL; + WOLFSSL_DH* dh = NULL; + + if (fp == NULL) { + WOLFSSL_MSG("DH parameter file cannot be NULL"); + return NULL; + } + + fbio = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); + if (fbio == NULL) { + WOLFSSL_MSG("Unable to create file BIO to process DH PEM"); + return NULL; + } + + if (wolfSSL_BIO_set_fp(fbio, fp, BIO_NOCLOSE) != WOLFSSL_SUCCESS) { + wolfSSL_BIO_free(fbio); + WOLFSSL_MSG("wolfSSL_BIO_set_fp error"); + return NULL; + } + + /* wolfSSL_PEM_read_bio_DHparams() sanitizes x, cb, u args */ + dh = wolfSSL_PEM_read_bio_DHparams(fbio, x, cb, u); + + wolfSSL_BIO_free(fbio); + return dh; +} +#endif /* !NO_FILESYSTEM */ + #endif /* !NO_BIO */ #if defined(WOLFSSL_DH_EXTRA) && !defined(NO_FILESYSTEM) @@ -57164,7 +57205,19 @@ int wolfSSL_CONF_cmd(WOLFSSL_CONF_CTX* cctx, const char* cmd, const char* value) if (method->createCb) { method->createCb(bio); } - } + + #if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) + bio->refCount = 1; + #ifndef SINGLE_THREADED + if (wc_InitMutex(&bio->refMutex) != 0) { + wolfSSL_BIO_free(bio); + WOLFSSL_MSG("wc_InitMutex failed for WOLFSSL_BIO"); + return NULL; + } + #endif + #endif + +} return bio; } @@ -57209,13 +57262,14 @@ int wolfSSL_CONF_cmd(WOLFSSL_CONF_CTX* cctx, const char* cmd, const char* value) int wolfSSL_BIO_free(WOLFSSL_BIO* bio) { int ret; + #if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) + int doFree = 0; + #endif /* unchain?, doesn't matter in goahead since from free all */ WOLFSSL_ENTER("wolfSSL_BIO_free"); if (bio) { -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS - wolfSSL_CRYPTO_cleanup_ex_data(&bio->ex_data); -#endif + if (bio->infoCb) { /* info callback is called before free */ ret = (int)bio->infoCb(bio, WOLFSSL_BIO_CB_FREE, NULL, 0, 0, 1); @@ -57224,6 +57278,37 @@ int wolfSSL_CONF_cmd(WOLFSSL_CONF_CTX* cctx, const char* cmd, const char* value) } } + #if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) + #ifndef SINGLE_THREADED + if (wc_LockMutex(&bio->refMutex) != 0) { + WOLFSSL_MSG("Couldn't lock BIO mutex"); + return WOLFSSL_FAILURE; + } + #endif + + /* only free if all references to it are done */ + bio->refCount--; + if (bio->refCount == 0) { + doFree = 1; + } + + #ifndef SINGLE_THREADED + wc_UnLockMutex(&bio->refMutex); + #endif + + if (!doFree) { + /* return success if BIO ref count is not 1 yet */ + return WOLFSSL_SUCCESS; + } + #ifndef SINGLE_THREADED + wc_FreeMutex(&bio->refMutex); + #endif + #endif + + #ifdef HAVE_EX_DATA_CLEANUP_HOOKS + wolfSSL_CRYPTO_cleanup_ex_data(&bio->ex_data); + #endif + /* call custom set free callback */ if (bio->method && bio->method->freeCb) { bio->method->freeCb(bio); diff --git a/tests/api.c b/tests/api.c index 1ec407ff4..523b43878 100644 --- a/tests/api.c +++ b/tests/api.c @@ -37045,6 +37045,24 @@ static void test_wolfSSL_BIO_f_md(void) #endif } +static void test_wolfSSL_BIO_up_ref(void) +{ +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) + BIO* bio; + printf(testingFmt, "wolfSSL_BIO_up_ref()"); + + AssertNotNull(bio = BIO_new(BIO_f_md())); + AssertIntEQ(BIO_up_ref(NULL), 0); + AssertIntEQ(BIO_up_ref(bio), 1); + BIO_free(bio); + AssertIntEQ(BIO_up_ref(bio), 1); + BIO_free(bio); + BIO_free(bio); + + printf(resultFmt, "passed"); +#endif +} + #endif /* !NO_BIO */ #if defined(OPENSSL_EXTRA) && defined(HAVE_IO_TESTS_DEPENDENCIES) @@ -38836,7 +38854,50 @@ static int test_wolfSSL_EVP_Cipher_extra(void) return 0; } +static void test_wolfSSL_PEM_read_DHparams(void) +{ +#if defined(OPENSSL_ALL) && !defined(NO_BIO) && \ + !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) && !defined(NO_FILESYSTEM) + DH* dh; + XFILE fp; + unsigned char derOut[300]; + unsigned char* derOutBuf = derOut; + int derOutSz = 0; + unsigned char derExpected[300]; + int derExpectedSz = 0; + + printf(testingFmt, "wolfSSL_PEM_read_DHparams()"); + + XMEMSET(derOut, 0, sizeof(derOut)); + XMEMSET(derExpected, 0, sizeof(derExpected)); + + /* open DH param file, read into DH struct */ + AssertNotNull(fp = XFOPEN(dhParamFile, "rb")); + + /* bad args */ + AssertNull(dh = PEM_read_DHparams(NULL, &dh, NULL, NULL)); + AssertNull(dh = PEM_read_DHparams(NULL, NULL, NULL, NULL)); + + /* good args */ + AssertNotNull(dh = PEM_read_DHparams(fp, &dh, NULL, NULL)); + XFCLOSE(fp); + + /* read in certs/dh2048.der for comparison against exported params */ + fp = XFOPEN("./certs/dh2048.der", "rb"); + AssertTrue(fp != XBADFILE); + derExpectedSz = (int)XFREAD(derExpected, 1, sizeof(derExpected), fp); + XFCLOSE(fp); + + /* export DH back to DER and compare */ + derOutSz = wolfSSL_i2d_DHparams(dh, &derOutBuf); + AssertIntEQ(derOutSz, derExpectedSz); + AssertIntEQ(XMEMCMP(derOut, derExpected, derOutSz), 0); + DH_free(dh); + + printf(resultFmt, passed); +#endif +} static void test_wolfSSL_AES_ecb_encrypt(void) { @@ -41416,6 +41477,26 @@ static void test_wolfSSL_EVP_get_digestbynid(void) printf(resultFmt, passed); #endif } +static void test_wolfSSL_EVP_MD_nid(void) +{ +#if defined(OPENSSL_ALL) + + printf(testingFmt, "wolfSSL_EVP_MD_nid"); + +#ifndef NO_MD5 + AssertIntEQ(EVP_MD_nid(EVP_md5()), NID_md5); +#endif +#ifndef NO_SHA + AssertIntEQ(EVP_MD_nid(EVP_sha1()), NID_sha1); +#endif +#ifndef NO_SHA256 + AssertIntEQ(EVP_MD_nid(EVP_sha256()), NID_sha256); +#endif + AssertIntEQ(EVP_MD_nid(NULL), NID_undef); + + printf(resultFmt, passed); +#endif +} static void test_wolfSSL_EVP_PKEY_get0_EC_KEY(void) { #if defined(HAVE_ECC) && defined(OPENSSL_ALL) @@ -49285,6 +49366,7 @@ void ApiTest(void) test_wolfSSL_BIO_accept(); test_wolfSSL_BIO_printf(); test_wolfSSL_BIO_f_md(); + test_wolfSSL_BIO_up_ref(); #endif test_wolfSSL_cert_cb(); test_wolfSSL_SESSION(); @@ -49304,6 +49386,7 @@ void ApiTest(void) test_wolfSSL_SHA(); test_wolfSSL_DH_1536_prime(); test_wolfSSL_PEM_write_DHparams(); + test_wolfSSL_PEM_read_DHparams(); test_wolfSSL_AES_ecb_encrypt(); test_wolfSSL_MD5(); test_wolfSSL_MD5_Transform(); @@ -49397,6 +49480,7 @@ void ApiTest(void) test_wolfSSL_EVP_aes_192_gcm(); test_wolfSSL_EVP_ripemd160(); test_wolfSSL_EVP_get_digestbynid(); + test_wolfSSL_EVP_MD_nid(); test_wolfSSL_EVP_PKEY_get0_EC_KEY(); test_wolfSSL_EVP_X_STATE(); test_wolfSSL_EVP_X_STATE_LEN(); diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 06fbaa02c..8a0bee3dd 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -3716,16 +3716,28 @@ const WOLFSSL_EVP_MD *wolfSSL_EVP_get_digestbyname(const char *name) return NULL; } +/* Returns the NID of the WOLFSSL_EVP_MD passed in. + * + * type - pointer to WOLFSSL_EVP_MD for which to return NID value + * + * Returns NID on success, or NID_undef if none exists. + */ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) { const struct s_ent *ent ; WOLFSSL_ENTER("EVP_MD_type"); + + if (type == NULL) { + WOLFSSL_MSG("MD type arg is NULL"); + return NID_undef; + } + for( ent = md_tbl; ent->name != NULL; ent++){ if(XSTRNCMP((const char *)type, ent->name, XSTRLEN(ent->name)+1) == 0) { return ent->nid; } } - return 0; + return NID_undef; } #ifndef NO_MD4 diff --git a/wolfssl/openssl/bio.h b/wolfssl/openssl/bio.h index 69368e942..2390c8e97 100644 --- a/wolfssl/openssl/bio.h +++ b/wolfssl/openssl/bio.h @@ -63,6 +63,7 @@ #define BIO_ctrl_reset_read_request wolfSSL_BIO_ctrl_reset_read_request #define BIO_set_write_buf_size wolfSSL_BIO_set_write_buf_size #define BIO_make_bio_pair wolfSSL_BIO_make_bio_pair +#define BIO_up_ref wolfSSL_BIO_up_ref #define BIO_new_fd wolfSSL_BIO_new_fd #define BIO_set_fp wolfSSL_BIO_set_fp diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index f6f688bc0..2b5d99cde 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -907,6 +907,7 @@ typedef WOLFSSL_ASN1_PCTX ASN1_PCTX; #define EVP_get_cipherbynid wolfSSL_EVP_get_cipherbynid #define EVP_get_digestbynid wolfSSL_EVP_get_digestbynid +#define EVP_MD_nid wolfSSL_EVP_MD_type #define EVP_get_cipherbyname wolfSSL_EVP_get_cipherbyname #define EVP_get_digestbyname wolfSSL_EVP_get_digestbyname diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 31f0e62b1..62db34926 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -1069,6 +1069,7 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define DHparams_dup wolfSSL_DH_dup #define PEM_read_bio_DHparams wolfSSL_PEM_read_bio_DHparams +#define PEM_read_DHparams wolfSSL_PEM_read_DHparams #define PEM_read_bio_DSAparams wolfSSL_PEM_read_bio_DSAparams #if defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY) diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 9a8127242..44572de4c 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -530,6 +530,12 @@ struct WOLFSSL_BIO { #ifdef HAVE_EX_DATA WOLFSSL_CRYPTO_EX_DATA ex_data; #endif +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) + #ifndef SINGLE_THREADED + wolfSSL_Mutex refMutex; /* ref count mutex */ + #endif + int refCount; /* reference count */ +#endif }; typedef struct WOLFSSL_COMP_METHOD { @@ -1534,6 +1540,7 @@ WOLFSSL_API long wolfSSL_BIO_int_ctrl(WOLFSSL_BIO *bp, int cmd, long larg, int i WOLFSSL_API int wolfSSL_BIO_set_write_buf_size(WOLFSSL_BIO *b, long size); WOLFSSL_API int wolfSSL_BIO_make_bio_pair(WOLFSSL_BIO *b1, WOLFSSL_BIO *b2); +WOLFSSL_API int wolfSSL_BIO_up_ref(WOLFSSL_BIO *b); WOLFSSL_API int wolfSSL_BIO_ctrl_reset_read_request(WOLFSSL_BIO *b); WOLFSSL_API int wolfSSL_BIO_nread0(WOLFSSL_BIO *bio, char **buf); WOLFSSL_API int wolfSSL_BIO_nread(WOLFSSL_BIO *bio, char **buf, int num); @@ -4085,6 +4092,10 @@ WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_new_fp(XFILE fp, int c); WOLFSSL_API long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX*, WOLFSSL_DH*); WOLFSSL_API WOLFSSL_DH *wolfSSL_PEM_read_bio_DHparams(WOLFSSL_BIO *bp, WOLFSSL_DH **x, pem_password_cb *cb, void *u); +#ifndef NO_FILESYSTEM +WOLFSSL_API WOLFSSL_DH *wolfSSL_PEM_read_DHparams(XFILE fp, WOLFSSL_DH **x, + pem_password_cb *cb, void *u); +#endif WOLFSSL_API WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSAparams(WOLFSSL_BIO *bp, WOLFSSL_DSA **x, pem_password_cb *cb, void *u); WOLFSSL_API int wolfSSL_PEM_write_bio_X509_REQ(WOLFSSL_BIO *bp,WOLFSSL_X509 *x);