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 {