From 76014260f6ec49e2b2dcbd5175cf92c33810a9c2 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 2 Mar 2022 17:12:02 -0700 Subject: [PATCH 1/9] add EC_KEY_up_ref() and unit test --- src/ssl.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ tests/api.c | 15 +++++++++++++ wolfssl/openssl/ec.h | 7 ++++++ 3 files changed, 73 insertions(+) diff --git a/src/ssl.c b/src/ssl.c index a79142b27..ce0ca2361 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -38862,6 +38862,15 @@ WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_ex(void* heap, int devId) InitwolfSSL_ECKey(external); + external->refCount = 1; +#ifndef SINGLE_THREADED + if (wc_InitMutex(&external->refMutex) != 0) { + WOLFSSL_MSG("wc_InitMutex WOLFSSL_EC_KEY failure"); + XFREE(external, heap, DYNAMIC_TYPE_ECC); + return NULL; + } +#endif + external->internal = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC); if (external->internal == NULL) { @@ -38909,10 +38918,32 @@ WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new(void) void wolfSSL_EC_KEY_free(WOLFSSL_EC_KEY *key) { + int doFree = 0; + WOLFSSL_ENTER("wolfSSL_EC_KEY_free"); if (key != NULL) { void* heap = key->heap; + + #ifndef SINGLE_THREADED + if (wc_LockMutex(&key->refMutex) != 0) { + WOLFSSL_MSG("Could not lock EC_KEY mutex"); + } + #endif + + /* only free if all references to it are done */ + key->refCount--; + if (key->refCount == 0) { + doFree = 1; + } + #ifndef SINGLE_THREADED + wc_UnLockMutex(&key->refMutex); + #endif + + if (doFree == 0) { + return; + } + if (key->internal != NULL) { wc_ecc_free((ecc_key*)key->internal); XFREE(key->internal, heap, DYNAMIC_TYPE_ECC); @@ -38928,6 +38959,26 @@ void wolfSSL_EC_KEY_free(WOLFSSL_EC_KEY *key) } } +/* Increments ref count of WOLFSSL_EC_KEY. + * Return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on error */ +int wolfSSL_EC_KEY_up_ref(WOLFSSL_EC_KEY* key) +{ + if (key) { + #ifndef SINGLE_THREADED + if (wc_LockMutex(&key->refMutex) != 0) { + WOLFSSL_MSG("Failed to lock EC_KEY mutex"); + } + #endif + key->refCount++; + #ifndef SINGLE_THREADED + wc_UnLockMutex(&key->refMutex); + #endif + return WOLFSSL_SUCCESS; + } + + return WOLFSSL_FAILURE; +} + /* set the group in WOLFSSL_EC_KEY and return WOLFSSL_SUCCESS on success */ int wolfSSL_EC_KEY_set_group(WOLFSSL_EC_KEY *key, WOLFSSL_EC_GROUP *group) { diff --git a/tests/api.c b/tests/api.c index 06535e3aa..fe844767f 100644 --- a/tests/api.c +++ b/tests/api.c @@ -42909,6 +42909,21 @@ static void test_wolfSSL_EC_KEY_dup(void) wolfSSL_EC_KEY_free(ecKey); wolfSSL_EC_KEY_free(dupKey); + /* Test EC_KEY_up_ref */ + AssertNotNull(ecKey = wolfSSL_EC_KEY_new()); + AssertIntEQ(wolfSSL_EC_KEY_generate_key(ecKey), 1); + AssertIntEQ(wolfSSL_EC_KEY_up_ref(NULL), WOLFSSL_FAILURE); + AssertIntEQ(wolfSSL_EC_KEY_up_ref(ecKey), WOLFSSL_SUCCESS); + /* reference count doesn't follow duplicate */ + AssertNotNull(dupKey = wolfSSL_EC_KEY_dup(ecKey)); + AssertIntEQ(wolfSSL_EC_KEY_up_ref(dupKey), WOLFSSL_SUCCESS); /* +1 */ + AssertIntEQ(wolfSSL_EC_KEY_up_ref(dupKey), WOLFSSL_SUCCESS); /* +2 */ + wolfSSL_EC_KEY_free(dupKey); /* 3 */ + wolfSSL_EC_KEY_free(dupKey); /* 2 */ + wolfSSL_EC_KEY_free(dupKey); /* 1, free */ + wolfSSL_EC_KEY_free(ecKey); /* 2 */ + wolfSSL_EC_KEY_free(ecKey); /* 1, free */ + printf(resultFmt, passed); #endif } diff --git a/wolfssl/openssl/ec.h b/wolfssl/openssl/ec.h index 47ab4defb..fa0ac7a6b 100644 --- a/wolfssl/openssl/ec.h +++ b/wolfssl/openssl/ec.h @@ -119,6 +119,10 @@ struct WOLFSSL_EC_KEY { char form; /* Either POINT_CONVERSION_UNCOMPRESSED or * POINT_CONVERSION_COMPRESSED */ word16 pkcs8HeaderSz; +#ifndef SINGLE_THREADED + wolfSSL_Mutex refMutex; /* ref count mutex */ +#endif + int refCount; /* reference count */ /* option bits */ byte inSet:1; /* internal set from external ? */ @@ -138,6 +142,8 @@ size_t wolfSSL_EC_get_builtin_curves(WOLFSSL_EC_BUILTIN_CURVE *r,size_t nitems); WOLFSSL_API WOLFSSL_EC_KEY *wolfSSL_EC_KEY_dup(const WOLFSSL_EC_KEY *src); +WOLFSSL_API +int wolfSSL_EC_KEY_up_ref(WOLFSSL_EC_KEY* key); WOLFSSL_API int wolfSSL_ECPoint_i2d(const WOLFSSL_EC_GROUP *curve, @@ -307,6 +313,7 @@ typedef WOLFSSL_EC_BUILTIN_CURVE EC_builtin_curve; #define EC_KEY_new wolfSSL_EC_KEY_new #define EC_KEY_free wolfSSL_EC_KEY_free #define EC_KEY_dup wolfSSL_EC_KEY_dup +#define EC_KEY_up_ref wolfSSL_EC_KEY_up_ref #define EC_KEY_get0_public_key wolfSSL_EC_KEY_get0_public_key #define EC_KEY_get0_group wolfSSL_EC_KEY_get0_group #define EC_KEY_set_private_key wolfSSL_EC_KEY_set_private_key From 8e0f5f9289b6066385d3fbc21d5a6c1e42ee8b39 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 4 Mar 2022 17:00:51 -0700 Subject: [PATCH 2/9] EVP_PKEY_get1/set1_EC_KEY: modify for EC_KEY_up_ref support --- wolfcrypt/src/evp.c | 61 +++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index c607b1517..55b7c3bcf 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -6941,29 +6941,37 @@ WOLFSSL_EC_KEY *wolfSSL_EVP_PKEY_get0_EC_KEY(WOLFSSL_EVP_PKEY *pkey) WOLFSSL_EC_KEY* wolfSSL_EVP_PKEY_get1_EC_KEY(WOLFSSL_EVP_PKEY* key) { - WOLFSSL_EC_KEY* local; + WOLFSSL_EC_KEY* local = NULL; WOLFSSL_ENTER("wolfSSL_EVP_PKEY_get1_EC_KEY"); if (key == NULL) { return NULL; } - - local = wolfSSL_EC_KEY_new(); - if (local == NULL) { - WOLFSSL_MSG("Error creating a new WOLFSSL_EC_KEY structure"); - return NULL; - } - if (key->type == EVP_PKEY_EC) { - if (wolfSSL_EC_KEY_LoadDer(local, (const unsigned char*)key->pkey.ptr, - key->pkey_sz) != WOLFSSL_SUCCESS) { - /* now try public key */ - if (wolfSSL_EC_KEY_LoadDer_ex(local, - (const unsigned char*)key->pkey.ptr, - key->pkey_sz, WOLFSSL_EC_KEY_LOAD_PUBLIC) != WOLFSSL_SUCCESS) { + if (key->ecc != NULL) { + if (wolfSSL_EC_KEY_up_ref(key->ecc) != WOLFSSL_SUCCESS) { + return NULL; + } + local = key->ecc; + } + else { + local = wolfSSL_EC_KEY_new(); + if (local == NULL) { + WOLFSSL_MSG("Error creating a new WOLFSSL_EC_KEY structure"); + return NULL; + } - wolfSSL_EC_KEY_free(local); - local = NULL; + if (wolfSSL_EC_KEY_LoadDer(local, + (const unsigned char*)key->pkey.ptr, + key->pkey_sz) != WOLFSSL_SUCCESS) { + /* now try public key */ + if (wolfSSL_EC_KEY_LoadDer_ex(local, + (const unsigned char*)key->pkey.ptr, key->pkey_sz, + WOLFSSL_EC_KEY_LOAD_PUBLIC) != WOLFSSL_SUCCESS) { + + wolfSSL_EC_KEY_free(local); + local = NULL; + } } } } @@ -6972,11 +6980,7 @@ WOLFSSL_EC_KEY* wolfSSL_EVP_PKEY_get1_EC_KEY(WOLFSSL_EVP_PKEY* key) wolfSSL_EC_KEY_free(local); local = NULL; } -#ifdef OPENSSL_ALL - if (!local && key->ecc) { - local = wolfSSL_EC_KEY_dup(key->ecc); - } -#endif + return local; } #endif /* HAVE_ECC */ @@ -7225,8 +7229,11 @@ static int ECC_populate_EVP_PKEY(EVP_PKEY* pkey, WOLFSSL_EC_KEY *key) int wolfSSL_EVP_PKEY_set1_EC_KEY(WOLFSSL_EVP_PKEY *pkey, WOLFSSL_EC_KEY *key) { #ifdef HAVE_ECC - if((pkey == NULL) || (key ==NULL))return WOLFSSL_FAILURE; WOLFSSL_ENTER("wolfSSL_EVP_PKEY_set1_EC_KEY"); + + if (pkey == NULL || key == NULL) { + return WOLFSSL_FAILURE; + } #ifndef NO_RSA if (pkey->rsa != NULL && pkey->ownRsa == 1) { wolfSSL_RSA_free(pkey->rsa); @@ -7245,18 +7252,24 @@ int wolfSSL_EVP_PKEY_set1_EC_KEY(WOLFSSL_EVP_PKEY *pkey, WOLFSSL_EC_KEY *key) } pkey->ownDh = 0; #endif + + if (wolfSSL_EC_KEY_up_ref(key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_EC_KEY_up_ref failed"); + return WOLFSSL_FAILURE; + } + if (pkey->ecc != NULL && pkey->ownEcc == 1) { wolfSSL_EC_KEY_free(pkey->ecc); } pkey->ecc = key; - pkey->ownEcc = 0; /* pkey does not own EC key */ + pkey->ownEcc = 1; /* doesn't own EC_KEY but needs to call free on it */ pkey->type = EVP_PKEY_EC; return ECC_populate_EVP_PKEY(pkey, key); #else (void)pkey; (void)key; return WOLFSSL_FAILURE; -#endif +#endif /* HAVE_ECC */ } void* wolfSSL_EVP_X_STATE(const WOLFSSL_EVP_CIPHER_CTX* ctx) From 85f85cc76a99da7070ec64b17dd00f11dffd1b50 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 2 Mar 2022 16:20:12 -0700 Subject: [PATCH 3/9] add DH_up_ref() and unit test --- src/ssl.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ tests/api.c | 9 ++++++++ wolfssl/openssl/dh.h | 17 ++++++++++----- 3 files changed, 72 insertions(+), 6 deletions(-) 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 From f3f0d49fcee2adf91dcf67eee5ffd893805d27df Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 4 Mar 2022 11:35:31 -0700 Subject: [PATCH 4/9] EVP_PKEY_CTX_new: set curve NID from pkey if available --- wolfcrypt/src/evp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 55b7c3bcf..9c59a67e8 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1416,7 +1416,12 @@ WOLFSSL_EVP_PKEY_CTX *wolfSSL_EVP_PKEY_CTX_new(WOLFSSL_EVP_PKEY *pkey, WOLFSSL_E ctx->padding = RSA_PKCS1_PADDING; #endif #ifdef HAVE_ECC - ctx->curveNID = ECC_CURVE_DEF; + if (pkey->ecc && pkey->ecc->group) { + /* set curve NID from pkey if available */ + ctx->curveNID = pkey->ecc->group->curve_nid; + } else { + ctx->curveNID = ECC_CURVE_DEF; + } #endif if (wolfSSL_EVP_PKEY_up_ref(pkey) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Couldn't increase key reference count"); From 939ce713df2ac39346f8378deae1a915bf86b6e4 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 4 Mar 2022 11:43:20 -0700 Subject: [PATCH 5/9] EVP_PKEY_derive: set internal DH key if needed --- wolfcrypt/src/evp.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 9c59a67e8..118426f84 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1535,7 +1535,18 @@ int wolfSSL_EVP_PKEY_derive(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *key, size_ #ifndef NO_DH case EVP_PKEY_DH: /* Use DH */ - if (!ctx->pkey->dh || !ctx->peerKey->dh || !ctx->peerKey->dh->pub_key) { + if (!ctx->pkey->dh || !ctx->peerKey->dh) { + return WOLFSSL_FAILURE; + } + /* set internal peer key if not done */ + if (!ctx->peerKey->dh->inSet) { + if (SetDhInternal(ctx->peerKey->dh) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("SetDhInternal failed"); + return WOLFSSL_FAILURE; + } + } + if (!ctx->peerKey->dh->pub_key) { + WOLFSSL_MSG("SetDhInternal failed, pub_key is NULL"); return WOLFSSL_FAILURE; } if ((len = wolfSSL_DH_size(ctx->pkey->dh)) <= 0) { From f49983b3b3f5c5b17b71c659fbabc405e6e9405d Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 4 Mar 2022 15:04:32 -0700 Subject: [PATCH 6/9] EVP_PKEY_keygen: add DH keygen support, fixes to EVP_PKEY_set1/get1_DH --- src/ssl.c | 3 +- tests/api.c | 46 +++++++++++++++++++++-- wolfcrypt/src/evp.c | 90 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 120 insertions(+), 19 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 6b58f29ac..9a58ae53e 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -43117,7 +43117,8 @@ int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, } #endif /* HAVE_ECC */ -#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH)) +#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || \ + defined(WOLFSSL_OPENSSH) || defined(OPENSSL_EXTRA)) /* return WOLFSSL_SUCCESS if success, WOLFSSL_FATAL_ERROR if error */ #if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) int wolfSSL_DH_LoadDer(WOLFSSL_DH* dh, const unsigned char* derBuf, int derSz) diff --git a/tests/api.c b/tests/api.c index 818b17163..739efb1dc 100644 --- a/tests/api.c +++ b/tests/api.c @@ -43527,8 +43527,17 @@ static void test_wolfSSL_EVP_PKEY_paramgen(void) static void test_wolfSSL_EVP_PKEY_keygen(void) { - WOLFSSL_EVP_PKEY* pkey; - EVP_PKEY_CTX *ctx; + WOLFSSL_EVP_PKEY* pkey = NULL; + EVP_PKEY_CTX* ctx = NULL; +#ifndef NO_DH + WOLFSSL_EVP_PKEY* params = NULL; + DH* dh = NULL; + const BIGNUM* pubkey = NULL; + const BIGNUM* privkey = NULL; + ASN1_INTEGER* asn1int = NULL; + unsigned int length = 0; + byte* derBuffer = NULL; +#endif printf(testingFmt, "wolfSSL_EVP_PKEY_keygen"); @@ -43543,9 +43552,40 @@ static void test_wolfSSL_EVP_PKEY_keygen(void) /* Good case */ AssertIntEQ(wolfSSL_EVP_PKEY_keygen(ctx, &pkey), 0); - EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); + pkey = NULL; + +#if !defined(NO_DH) && (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION>2))) + /* Test DH keygen */ + { + AssertNotNull(params = wolfSSL_EVP_PKEY_new()); + AssertNotNull(dh = DH_get_2048_256()); + AssertIntEQ(EVP_PKEY_set1_DH(params, dh), WOLFSSL_SUCCESS); + AssertNotNull(ctx = EVP_PKEY_CTX_new(params, NULL)); + AssertIntEQ(EVP_PKEY_keygen_init(ctx), WOLFSSL_SUCCESS); + AssertIntEQ(EVP_PKEY_keygen(ctx, &pkey), WOLFSSL_SUCCESS); + + DH_free(dh); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(params); + + /* try exporting generated key to DER, to verify */ + AssertNotNull(dh = EVP_PKEY_get1_DH(pkey)); + DH_get0_key(dh, &pubkey, &privkey); + AssertNotNull(pubkey); + AssertNotNull(privkey); + AssertNotNull(asn1int = BN_to_ASN1_INTEGER(pubkey, NULL)); + AssertIntGT((length = i2d_ASN1_INTEGER(asn1int, &derBuffer)), 0); + + ASN1_INTEGER_free(asn1int); + DH_free(dh); + XFREE(derBuffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + EVP_PKEY_free(pkey); + } +#endif printf(resultFmt, passed); } diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 118426f84..fdec88027 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -2062,15 +2062,16 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx, if (pkey == NULL) { if (ctx->pkey == NULL || (ctx->pkey->type != EVP_PKEY_EC && - ctx->pkey->type != EVP_PKEY_RSA)) { + ctx->pkey->type != EVP_PKEY_RSA && + ctx->pkey->type != EVP_PKEY_DH)) { WOLFSSL_MSG("Key not set or key type not supported"); return BAD_FUNC_ARG; } - ownPkey = 1; pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) + if (pkey == NULL) { return MEMORY_E; - + } + ownPkey = 1; pkey->type = ctx->pkey->type; } @@ -2102,6 +2103,26 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx, } } break; +#endif +#if !defined(NO_DH) && (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION>2))) + case EVP_PKEY_DH: + pkey->dh = wolfSSL_DH_new(); + if (pkey->dh) { + pkey->ownDh = 1; + /* load DH params from CTX */ + ret = wolfSSL_DH_LoadDer(pkey->dh, + (const unsigned char*)ctx->pkey->pkey.ptr, + ctx->pkey->pkey_sz); + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_DH_generate_key(pkey->dh); + } + if (ret == WOLFSSL_SUCCESS) { + /* copy private/public key from external to internal */ + ret = SetDhInternal(pkey->dh); + } + } + break; #endif default: break; @@ -7022,11 +7043,36 @@ int wolfSSL_EVP_PKEY_set1_DH(WOLFSSL_EVP_PKEY *pkey, WOLFSSL_DH *key) if (pkey == NULL || key == NULL) return WOLFSSL_FAILURE; + /* free other types if needed */ +#ifndef NO_RSA + if (pkey->rsa != NULL && pkey->ownRsa == 1) { + wolfSSL_RSA_free(pkey->rsa); + } + pkey->ownRsa = 0; +#endif +#ifndef NO_DSA + if (pkey->dsa != NULL && pkey->ownDsa == 1) { + wolfSSL_DSA_free(pkey->dsa); + } + pkey->ownDsa = 0; +#endif +#ifdef HAVE_ECC + if (pkey->ecc != NULL && pkey->ownEcc == 1) { + wolfSSL_EC_KEY_free(pkey->ecc); + } + pkey->ownEcc = 0; +#endif + + if (wolfSSL_DH_up_ref(key) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_DH_up_ref failed"); + return WOLFSSL_FAILURE; + } + if (pkey->dh != NULL && pkey->ownDh == 1) wolfSSL_DH_free(pkey->dh); pkey->dh = key; - pkey->ownDh = 0; /* pkey does not own DH */ + pkey->ownDh = 1; /* pkey does not own DH but needs to call free on it */ pkey->type = EVP_PKEY_DH; if (key->inSet == 0) { if (SetDhInternal(key) != WOLFSSL_SUCCESS) { @@ -7102,17 +7148,31 @@ WOLFSSL_DH* wolfSSL_EVP_PKEY_get1_DH(WOLFSSL_EVP_PKEY* key) } if (key->type == EVP_PKEY_DH) { - local = wolfSSL_DH_new(); - if (local == NULL) { - WOLFSSL_MSG("Error creating a new WOLFSSL_DH structure"); - return NULL; + /* if key->dh already exists copy instead of re-importing from DER */ + if (key->dh != NULL) { + if (wolfSSL_DH_up_ref(key->dh) != WOLFSSL_SUCCESS) { + return NULL; + } + local = key->dh; } - - if (wolfSSL_DH_LoadDer(local, (const unsigned char*)key->pkey.ptr, - key->pkey_sz) != SSL_SUCCESS) { - wolfSSL_DH_free(local); - WOLFSSL_MSG("Error wolfSSL_DH_LoadDer"); - local = NULL; + else { +#if !defined(NO_DH) && (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION>2))) + local = wolfSSL_DH_new(); + if (local == NULL) { + WOLFSSL_MSG("Error creating a new WOLFSSL_DH structure"); + return NULL; + } + if (wolfSSL_DH_LoadDer(local, (const unsigned char*)key->pkey.ptr, + key->pkey_sz) != SSL_SUCCESS) { + wolfSSL_DH_free(local); + WOLFSSL_MSG("Error wolfSSL_DH_LoadDer"); + local = NULL; + } +#else + WOLFSSL_MSG("EVP_PKEY does not hold DH struct"); + return NULL; +#endif } } else { From e1da313b91f18b59db3c4d74f976f28c3f40a02a Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 4 Mar 2022 16:46:39 -0700 Subject: [PATCH 7/9] EVP_PKEY_copy_parameters: add support for EVP_PKEY_DH --- tests/api.c | 58 ++++++++++++++++++++++++++++++++++++++++++++- wolfcrypt/src/evp.c | 45 +++++++++++++++++++++++++++++++---- 2 files changed, 97 insertions(+), 6 deletions(-) diff --git a/tests/api.c b/tests/api.c index 739efb1dc..747452b5c 100644 --- a/tests/api.c +++ b/tests/api.c @@ -43529,7 +43529,8 @@ static void test_wolfSSL_EVP_PKEY_keygen(void) { WOLFSSL_EVP_PKEY* pkey = NULL; EVP_PKEY_CTX* ctx = NULL; -#ifndef NO_DH +#if !defined(NO_DH) && (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION>2))) WOLFSSL_EVP_PKEY* params = NULL; DH* dh = NULL; const BIGNUM* pubkey = NULL; @@ -43623,6 +43624,60 @@ static void test_wolfSSL_EVP_PKEY_missing_parameters(void) printf(resultFmt, passed); #endif } +static void test_wolfSSL_EVP_PKEY_copy_parameters(void) +{ +#if defined(OPENSSL_EXTRA) && !defined(NO_DH) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_SELFTEST) && (defined(OPENSSL_ALL) || defined(WOLFSSL_QT) || \ + defined(WOLFSSL_OPENSSH)) && defined(WOLFSSL_DH_EXTRA) && \ + !defined(NO_FILESYSTEM) + + WOLFSSL_EVP_PKEY* params = NULL; + WOLFSSL_EVP_PKEY* copy = NULL; + DH* dh = NULL; + BIGNUM* p1; + BIGNUM* g1; + BIGNUM* q1; + BIGNUM* p2; + BIGNUM* g2; + BIGNUM* q2; + + printf(testingFmt, "wolfSSL_EVP_PKEY_copy_parameters"); + + /* create DH with DH_get_2048_256 params */ + AssertNotNull(params = wolfSSL_EVP_PKEY_new()); + AssertNotNull(dh = DH_get_2048_256()); + AssertIntEQ(EVP_PKEY_set1_DH(params, dh), WOLFSSL_SUCCESS); + DH_get0_pqg(dh, (const BIGNUM**)&p1, + (const BIGNUM**)&q1, + (const BIGNUM**)&g1); + DH_free(dh); + + /* create DH with random generated DH params */ + AssertNotNull(copy = wolfSSL_EVP_PKEY_new()); + AssertNotNull(dh = DH_generate_parameters(2048, 2, NULL, NULL)); + AssertIntEQ(EVP_PKEY_set1_DH(copy, dh), WOLFSSL_SUCCESS); + DH_free(dh); + + AssertIntEQ(EVP_PKEY_copy_parameters(copy, params), WOLFSSL_SUCCESS); + AssertNotNull(dh = EVP_PKEY_get1_DH(copy)); + AssertNotNull(dh->p); + AssertNotNull(dh->g); + AssertNotNull(dh->q); + DH_get0_pqg(dh, (const BIGNUM**)&p2, + (const BIGNUM**)&q2, + (const BIGNUM**)&g2); + + AssertIntEQ(BN_cmp(p1, p2), 0); + AssertIntEQ(BN_cmp(q1, q2), 0); + AssertIntEQ(BN_cmp(g1, g2), 0); + + DH_free(dh); + EVP_PKEY_free(copy); + EVP_PKEY_free(params); + + printf(resultFmt, passed); +#endif +} static void test_wolfSSL_EVP_PKEY_CTX_set_rsa_keygen_bits(void) { WOLFSSL_EVP_PKEY* pkey; @@ -52852,6 +52907,7 @@ void ApiTest(void) test_wolfSSL_EVP_PKEY_keygen(); test_wolfSSL_EVP_PKEY_keygen_init(); test_wolfSSL_EVP_PKEY_missing_parameters(); + test_wolfSSL_EVP_PKEY_copy_parameters(); test_wolfSSL_EVP_PKEY_CTX_set_rsa_keygen_bits(); test_wolfSSL_EVP_CIPHER_CTX_iv_length(); test_wolfSSL_EVP_CIPHER_CTX_key_length(); diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index fdec88027..18f11a93e 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -2248,19 +2248,54 @@ int wolfSSL_EVP_PKEY_copy_parameters(WOLFSSL_EVP_PKEY *to, } break; #endif -#ifndef NO_RSA - case EVP_PKEY_RSA: -#endif #ifndef NO_DH case EVP_PKEY_DH: + if (from->dh) { + WOLFSSL_BIGNUM* cpy; + if (!to->dh && !(to->dh = wolfSSL_DH_new())) { + WOLFSSL_MSG("wolfSSL_DH_new error"); + return WOLFSSL_FAILURE; + } + + /* free existing BIGNUMs if needed before copying over new */ + wolfSSL_BN_free(to->dh->p); + wolfSSL_BN_free(to->dh->g); + wolfSSL_BN_free(to->dh->q); + to->dh->p = NULL; + to->dh->g = NULL; + to->dh->q = NULL; + + if (!(cpy = wolfSSL_BN_dup(from->dh->p))) { + WOLFSSL_MSG("wolfSSL_BN_dup error, DH p"); + return WOLFSSL_FAILURE; + } + to->dh->p = cpy; + if (!(cpy = wolfSSL_BN_dup(from->dh->g))) { + WOLFSSL_MSG("wolfSSL_BN_dup error, DH g"); + return WOLFSSL_FAILURE; + } + to->dh->g = cpy; + if (!(cpy = wolfSSL_BN_dup(from->dh->q))) { + WOLFSSL_MSG("wolfSSL_BN_dup error, DH q"); + return WOLFSSL_FAILURE; + } + to->dh->q = cpy; + } + else { + WOLFSSL_MSG("Missing DH struct"); + return WOLFSSL_FAILURE; + } + break; +#endif +#ifndef NO_RSA + case EVP_PKEY_RSA: #endif default: WOLFSSL_MSG("Copy parameters not available for this key type"); return WOLFSSL_FAILURE; } -#if defined(HAVE_ECC) || !defined(NO_DSA) + return WOLFSSL_SUCCESS; -#endif } #ifndef NO_WOLFSSL_STUB From 9fff321e3e31923856f558794ba8f1093d1a8c7b Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 11 Mar 2022 10:11:02 -0700 Subject: [PATCH 8/9] address PR review feedback on EVP_PKEY changes --- tests/api.c | 8 +++----- wolfcrypt/src/evp.c | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/api.c b/tests/api.c index 747452b5c..8d8532f1a 100644 --- a/tests/api.c +++ b/tests/api.c @@ -42911,7 +42911,7 @@ static void test_wolfSSL_EC_KEY_dup(void) /* Test EC_KEY_up_ref */ AssertNotNull(ecKey = wolfSSL_EC_KEY_new()); - AssertIntEQ(wolfSSL_EC_KEY_generate_key(ecKey), 1); + AssertIntEQ(wolfSSL_EC_KEY_generate_key(ecKey), WOLFSSL_SUCCESS); AssertIntEQ(wolfSSL_EC_KEY_up_ref(NULL), WOLFSSL_FAILURE); AssertIntEQ(wolfSSL_EC_KEY_up_ref(ecKey), WOLFSSL_SUCCESS); /* reference count doesn't follow duplicate */ @@ -43529,8 +43529,7 @@ static void test_wolfSSL_EVP_PKEY_keygen(void) { WOLFSSL_EVP_PKEY* pkey = NULL; EVP_PKEY_CTX* ctx = NULL; -#if !defined(NO_DH) && (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION>2))) +#if !defined(NO_DH) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) WOLFSSL_EVP_PKEY* params = NULL; DH* dh = NULL; const BIGNUM* pubkey = NULL; @@ -43557,8 +43556,7 @@ static void test_wolfSSL_EVP_PKEY_keygen(void) EVP_PKEY_free(pkey); pkey = NULL; -#if !defined(NO_DH) && (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION>2))) +#if !defined(NO_DH) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) /* Test DH keygen */ { AssertNotNull(params = wolfSSL_EVP_PKEY_new()); diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 18f11a93e..15e7d5231 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1419,7 +1419,8 @@ WOLFSSL_EVP_PKEY_CTX *wolfSSL_EVP_PKEY_CTX_new(WOLFSSL_EVP_PKEY *pkey, WOLFSSL_E if (pkey->ecc && pkey->ecc->group) { /* set curve NID from pkey if available */ ctx->curveNID = pkey->ecc->group->curve_nid; - } else { + } + else { ctx->curveNID = ECC_CURVE_DEF; } #endif @@ -2104,8 +2105,7 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx, } break; #endif -#if !defined(NO_DH) && (!defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION>2))) +#if !defined(NO_DH) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) case EVP_PKEY_DH: pkey->dh = wolfSSL_DH_new(); if (pkey->dh) { @@ -2226,6 +2226,15 @@ int wolfSSL_EVP_PKEY_copy_parameters(WOLFSSL_EVP_PKEY *to, WOLFSSL_MSG("wolfSSL_DSA_new error"); return WOLFSSL_FAILURE; } + + /* free existing BIGNUMs if needed before copying over new */ + wolfSSL_BN_free(to->dsa->p); + wolfSSL_BN_free(to->dsa->g); + wolfSSL_BN_free(to->dsa->q); + to->dsa->p = NULL; + to->dsa->g = NULL; + to->dsa->q = NULL; + if (!(cpy = wolfSSL_BN_dup(from->dsa->p))) { WOLFSSL_MSG("wolfSSL_BN_dup error"); return WOLFSSL_FAILURE; From c491a6c829c19e4aba3ab8520670435db4ddc2b5 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 18 Mar 2022 16:37:45 -0600 Subject: [PATCH 9/9] EVP_PKEY_copy_parameters: correctly mark inner struct owned --- wolfcrypt/src/evp.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 15e7d5231..18afe0b43 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -2203,11 +2203,13 @@ int wolfSSL_EVP_PKEY_copy_parameters(WOLFSSL_EVP_PKEY *to, #ifdef HAVE_ECC case EVP_PKEY_EC: if (from->ecc) { - if (!to->ecc && !(to->ecc = wolfSSL_EC_KEY_new())) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); - return WOLFSSL_FAILURE; + if (!to->ecc) { + if ((to->ecc = wolfSSL_EC_KEY_new()) == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); + return WOLFSSL_FAILURE; + } + to->ownEcc = 1; } - to->ownEcc = 1; to->ecc->group->curve_idx = from->ecc->group->curve_idx; to->ecc->group->curve_nid = from->ecc->group->curve_nid; to->ecc->group->curve_oid = from->ecc->group->curve_oid; @@ -2222,9 +2224,12 @@ int wolfSSL_EVP_PKEY_copy_parameters(WOLFSSL_EVP_PKEY *to, case EVP_PKEY_DSA: if (from->dsa) { WOLFSSL_BIGNUM* cpy; - if (!to->dsa && !(to->dsa = wolfSSL_DSA_new())) { - WOLFSSL_MSG("wolfSSL_DSA_new error"); - return WOLFSSL_FAILURE; + if (!to->dsa) { + if ((to->dsa = wolfSSL_DSA_new()) == NULL) { + WOLFSSL_MSG("wolfSSL_DSA_new error"); + return WOLFSSL_FAILURE; + } + to->ownDsa = 1; } /* free existing BIGNUMs if needed before copying over new */ @@ -2261,9 +2266,12 @@ int wolfSSL_EVP_PKEY_copy_parameters(WOLFSSL_EVP_PKEY *to, case EVP_PKEY_DH: if (from->dh) { WOLFSSL_BIGNUM* cpy; - if (!to->dh && !(to->dh = wolfSSL_DH_new())) { - WOLFSSL_MSG("wolfSSL_DH_new error"); - return WOLFSSL_FAILURE; + if (!to->dh) { + if ((to->dh = wolfSSL_DH_new()) == NULL) { + WOLFSSL_MSG("wolfSSL_DH_new error"); + return WOLFSSL_FAILURE; + } + to->ownDh = 1; } /* free existing BIGNUMs if needed before copying over new */